Skip to content
This repository has been archived by the owner on Nov 15, 2023. It is now read-only.

Commit

Permalink
Switch to new light client protocol (#5472)
Browse files Browse the repository at this point in the history
* Switch to the new protocol

* Oops, forgot to remove light_dispatch.rs

* Fix tests

* Address review
  • Loading branch information
tomaka authored Apr 1, 2020
1 parent 905677d commit f68d22f
Show file tree
Hide file tree
Showing 7 changed files with 481 additions and 1,682 deletions.
4 changes: 3 additions & 1 deletion client/network/src/behaviour.rs
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,6 @@ impl<B: BlockT, H: ExHashT> Behaviour<B, H> {
}

/// Issue a light client request.
#[allow(unused)]
pub fn light_client_request(&mut self, r: light_client_handler::Request<B>) -> Result<(), light_client_handler::Error> {
self.light_client_handler.request(r)
}
Expand Down Expand Up @@ -175,6 +174,9 @@ Behaviour<B, H> {
let ev = Event::NotificationsReceived { remote, messages };
self.events.push(BehaviourOut::Event(ev));
},
CustomMessageOutcome::PeerNewBest(peer_id, number) => {
self.light_client_handler.update_best_block(&peer_id, number);
}
CustomMessageOutcome::None => {}
}
}
Expand Down
2 changes: 1 addition & 1 deletion client/network/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
//! See the documentation of [`Params`].
pub use crate::chain::{Client, FinalityProofProvider};
pub use crate::on_demand_layer::OnDemand;
pub use crate::on_demand_layer::{AlwaysBadChecker, OnDemand};
pub use crate::service::{TransactionPool, EmptyTransactionPool};
pub use libp2p::{identity, core::PublicKey, wasm_ext::ExtTransport, build_multiaddr};

Expand Down
116 changes: 97 additions & 19 deletions client/network/src/on_demand_layer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,17 @@

//! On-demand requests service.
use crate::protocol::light_dispatch::RequestData;
use std::{collections::HashMap, pin::Pin, sync::Arc, task::Context, task::Poll};
use futures::{prelude::*, channel::mpsc, channel::oneshot};
use crate::protocol::light_client_handler;

use futures::{channel::mpsc, channel::oneshot, prelude::*};
use parking_lot::Mutex;
use sp_blockchain::Error as ClientError;
use sc_client_api::{
Fetcher, FetchChecker, RemoteHeaderRequest, RemoteCallRequest, RemoteReadRequest,
RemoteChangesRequest, RemoteReadChildRequest, RemoteBodyRequest,
FetchChecker, Fetcher, RemoteBodyRequest, RemoteCallRequest, RemoteChangesRequest,
RemoteHeaderRequest, RemoteReadChildRequest, RemoteReadRequest, StorageProof, ChangesProof,
};
use sp_blockchain::Error as ClientError;
use sp_runtime::traits::{Block as BlockT, Header as HeaderT, NumberFor};
use std::{collections::HashMap, pin::Pin, sync::Arc, task::Context, task::Poll};

/// Implements the `Fetcher` trait of the client. Makes it possible for the light client to perform
/// network requests for some state.
Expand All @@ -41,13 +42,72 @@ pub struct OnDemand<B: BlockT> {
/// Note that a better alternative would be to use a MPMC queue here, and add a `poll` method
/// from the `OnDemand`. However there exists no popular implementation of MPMC channels in
/// asynchronous Rust at the moment
requests_queue: Mutex<Option<mpsc::UnboundedReceiver<RequestData<B>>>>,
requests_queue: Mutex<Option<mpsc::UnboundedReceiver<light_client_handler::Request<B>>>>,

/// Sending side of `requests_queue`.
requests_send: mpsc::UnboundedSender<RequestData<B>>,
requests_send: mpsc::UnboundedSender<light_client_handler::Request<B>>,
}

/// Dummy implementation of `FetchChecker` that always assumes that responses are bad.
///
/// Considering that it is the responsibility of the client to build the fetcher, it can use this
/// implementation if it knows that it will never perform any request.
#[derive(Default, Clone)]
pub struct AlwaysBadChecker;

impl<Block: BlockT> FetchChecker<Block> for AlwaysBadChecker {
fn check_header_proof(
&self,
_request: &RemoteHeaderRequest<Block::Header>,
_remote_header: Option<Block::Header>,
_remote_proof: StorageProof,
) -> Result<Block::Header, ClientError> {
Err(ClientError::Msg("AlwaysBadChecker".into()))
}

fn check_read_proof(
&self,
_request: &RemoteReadRequest<Block::Header>,
_remote_proof: StorageProof,
) -> Result<HashMap<Vec<u8>,Option<Vec<u8>>>, ClientError> {
Err(ClientError::Msg("AlwaysBadChecker".into()))
}

fn check_read_child_proof(
&self,
_request: &RemoteReadChildRequest<Block::Header>,
_remote_proof: StorageProof,
) -> Result<HashMap<Vec<u8>, Option<Vec<u8>>>, ClientError> {
Err(ClientError::Msg("AlwaysBadChecker".into()))
}

fn check_execution_proof(
&self,
_request: &RemoteCallRequest<Block::Header>,
_remote_proof: StorageProof,
) -> Result<Vec<u8>, ClientError> {
Err(ClientError::Msg("AlwaysBadChecker".into()))
}

fn check_changes_proof(
&self,
_request: &RemoteChangesRequest<Block::Header>,
_remote_proof: ChangesProof<Block::Header>
) -> Result<Vec<(NumberFor<Block>, u32)>, ClientError> {
Err(ClientError::Msg("AlwaysBadChecker".into()))
}

fn check_body_proof(
&self,
_request: &RemoteBodyRequest<Block::Header>,
_body: Vec<Block::Extrinsic>
) -> Result<Vec<Block::Extrinsic>, ClientError> {
Err(ClientError::Msg("AlwaysBadChecker".into()))
}
}

impl<B: BlockT> OnDemand<B> where
impl<B: BlockT> OnDemand<B>
where
B::Header: HeaderT,
{
/// Creates new on-demand service.
Expand All @@ -74,12 +134,15 @@ impl<B: BlockT> OnDemand<B> where
///
/// If this function returns `None`, that means that the receiver has already been extracted in
/// the past, and therefore that something already handles the requests.
pub(crate) fn extract_receiver(&self) -> Option<mpsc::UnboundedReceiver<RequestData<B>>> {
pub(crate) fn extract_receiver(
&self,
) -> Option<mpsc::UnboundedReceiver<light_client_handler::Request<B>>> {
self.requests_queue.lock().take()
}
}

impl<B> Fetcher<B> for OnDemand<B> where
impl<B> Fetcher<B> for OnDemand<B>
where
B: BlockT,
B::Header: HeaderT,
{
Expand All @@ -91,40 +154,55 @@ impl<B> Fetcher<B> for OnDemand<B> where

fn remote_header(&self, request: RemoteHeaderRequest<B::Header>) -> Self::RemoteHeaderResult {
let (sender, receiver) = oneshot::channel();
let _ = self.requests_send.unbounded_send(RequestData::RemoteHeader(request, sender));
let _ = self
.requests_send
.unbounded_send(light_client_handler::Request::Header { request, sender });
RemoteResponse { receiver }
}

fn remote_read(&self, request: RemoteReadRequest<B::Header>) -> Self::RemoteReadResult {
let (sender, receiver) = oneshot::channel();
let _ = self.requests_send.unbounded_send(RequestData::RemoteRead(request, sender));
let _ = self
.requests_send
.unbounded_send(light_client_handler::Request::Read { request, sender });
RemoteResponse { receiver }
}

fn remote_read_child(
&self,
request: RemoteReadChildRequest<B::Header>
request: RemoteReadChildRequest<B::Header>,
) -> Self::RemoteReadResult {
let (sender, receiver) = oneshot::channel();
let _ = self.requests_send.unbounded_send(RequestData::RemoteReadChild(request, sender));
let _ = self
.requests_send
.unbounded_send(light_client_handler::Request::ReadChild { request, sender });
RemoteResponse { receiver }
}

fn remote_call(&self, request: RemoteCallRequest<B::Header>) -> Self::RemoteCallResult {
let (sender, receiver) = oneshot::channel();
let _ = self.requests_send.unbounded_send(RequestData::RemoteCall(request, sender));
let _ = self
.requests_send
.unbounded_send(light_client_handler::Request::Call { request, sender });
RemoteResponse { receiver }
}

fn remote_changes(&self, request: RemoteChangesRequest<B::Header>) -> Self::RemoteChangesResult {
fn remote_changes(
&self,
request: RemoteChangesRequest<B::Header>,
) -> Self::RemoteChangesResult {
let (sender, receiver) = oneshot::channel();
let _ = self.requests_send.unbounded_send(RequestData::RemoteChanges(request, sender));
let _ = self
.requests_send
.unbounded_send(light_client_handler::Request::Changes { request, sender });
RemoteResponse { receiver }
}

fn remote_body(&self, request: RemoteBodyRequest<B::Header>) -> Self::RemoteBodyResult {
let (sender, receiver) = oneshot::channel();
let _ = self.requests_send.unbounded_send(RequestData::RemoteBody(request, sender));
let _ = self
.requests_send
.unbounded_send(light_client_handler::Request::Body { request, sender });
RemoteResponse { receiver }
}
}
Expand Down
Loading

0 comments on commit f68d22f

Please sign in to comment.