mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-13 14:01:06 +00:00
Switch to new light client protocol (#5472)
* Switch to the new protocol * Oops, forgot to remove light_dispatch.rs * Fix tests * Address review
This commit is contained in:
@@ -133,7 +133,6 @@ impl<B: BlockT, H: ExHashT> Behaviour<B, H> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Issue a light client request.
|
/// 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> {
|
pub fn light_client_request(&mut self, r: light_client_handler::Request<B>) -> Result<(), light_client_handler::Error> {
|
||||||
self.light_client_handler.request(r)
|
self.light_client_handler.request(r)
|
||||||
}
|
}
|
||||||
@@ -175,6 +174,9 @@ Behaviour<B, H> {
|
|||||||
let ev = Event::NotificationsReceived { remote, messages };
|
let ev = Event::NotificationsReceived { remote, messages };
|
||||||
self.events.push(BehaviourOut::Event(ev));
|
self.events.push(BehaviourOut::Event(ev));
|
||||||
},
|
},
|
||||||
|
CustomMessageOutcome::PeerNewBest(peer_id, number) => {
|
||||||
|
self.light_client_handler.update_best_block(&peer_id, number);
|
||||||
|
}
|
||||||
CustomMessageOutcome::None => {}
|
CustomMessageOutcome::None => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,7 +20,7 @@
|
|||||||
//! See the documentation of [`Params`].
|
//! See the documentation of [`Params`].
|
||||||
|
|
||||||
pub use crate::chain::{Client, FinalityProofProvider};
|
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 crate::service::{TransactionPool, EmptyTransactionPool};
|
||||||
pub use libp2p::{identity, core::PublicKey, wasm_ext::ExtTransport, build_multiaddr};
|
pub use libp2p::{identity, core::PublicKey, wasm_ext::ExtTransport, build_multiaddr};
|
||||||
|
|
||||||
|
|||||||
@@ -16,16 +16,17 @@
|
|||||||
|
|
||||||
//! On-demand requests service.
|
//! On-demand requests service.
|
||||||
|
|
||||||
use crate::protocol::light_dispatch::RequestData;
|
use crate::protocol::light_client_handler;
|
||||||
use std::{collections::HashMap, pin::Pin, sync::Arc, task::Context, task::Poll};
|
|
||||||
use futures::{prelude::*, channel::mpsc, channel::oneshot};
|
use futures::{channel::mpsc, channel::oneshot, prelude::*};
|
||||||
use parking_lot::Mutex;
|
use parking_lot::Mutex;
|
||||||
use sp_blockchain::Error as ClientError;
|
|
||||||
use sc_client_api::{
|
use sc_client_api::{
|
||||||
Fetcher, FetchChecker, RemoteHeaderRequest, RemoteCallRequest, RemoteReadRequest,
|
FetchChecker, Fetcher, RemoteBodyRequest, RemoteCallRequest, RemoteChangesRequest,
|
||||||
RemoteChangesRequest, RemoteReadChildRequest, RemoteBodyRequest,
|
RemoteHeaderRequest, RemoteReadChildRequest, RemoteReadRequest, StorageProof, ChangesProof,
|
||||||
};
|
};
|
||||||
|
use sp_blockchain::Error as ClientError;
|
||||||
use sp_runtime::traits::{Block as BlockT, Header as HeaderT, NumberFor};
|
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
|
/// Implements the `Fetcher` trait of the client. Makes it possible for the light client to perform
|
||||||
/// network requests for some state.
|
/// network requests for some state.
|
||||||
@@ -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
|
/// 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
|
/// from the `OnDemand`. However there exists no popular implementation of MPMC channels in
|
||||||
/// asynchronous Rust at the moment
|
/// 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`.
|
/// Sending side of `requests_queue`.
|
||||||
requests_send: mpsc::UnboundedSender<RequestData<B>>,
|
requests_send: mpsc::UnboundedSender<light_client_handler::Request<B>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<B: BlockT> OnDemand<B> where
|
/// 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
|
||||||
B::Header: HeaderT,
|
B::Header: HeaderT,
|
||||||
{
|
{
|
||||||
/// Creates new on-demand service.
|
/// Creates new on-demand service.
|
||||||
@@ -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
|
/// 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.
|
/// 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()
|
self.requests_queue.lock().take()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<B> Fetcher<B> for OnDemand<B> where
|
impl<B> Fetcher<B> for OnDemand<B>
|
||||||
|
where
|
||||||
B: BlockT,
|
B: BlockT,
|
||||||
B::Header: HeaderT,
|
B::Header: HeaderT,
|
||||||
{
|
{
|
||||||
@@ -91,40 +154,55 @@ impl<B> Fetcher<B> for OnDemand<B> where
|
|||||||
|
|
||||||
fn remote_header(&self, request: RemoteHeaderRequest<B::Header>) -> Self::RemoteHeaderResult {
|
fn remote_header(&self, request: RemoteHeaderRequest<B::Header>) -> Self::RemoteHeaderResult {
|
||||||
let (sender, receiver) = oneshot::channel();
|
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 }
|
RemoteResponse { receiver }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn remote_read(&self, request: RemoteReadRequest<B::Header>) -> Self::RemoteReadResult {
|
fn remote_read(&self, request: RemoteReadRequest<B::Header>) -> Self::RemoteReadResult {
|
||||||
let (sender, receiver) = oneshot::channel();
|
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 }
|
RemoteResponse { receiver }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn remote_read_child(
|
fn remote_read_child(
|
||||||
&self,
|
&self,
|
||||||
request: RemoteReadChildRequest<B::Header>
|
request: RemoteReadChildRequest<B::Header>,
|
||||||
) -> Self::RemoteReadResult {
|
) -> Self::RemoteReadResult {
|
||||||
let (sender, receiver) = oneshot::channel();
|
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 }
|
RemoteResponse { receiver }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn remote_call(&self, request: RemoteCallRequest<B::Header>) -> Self::RemoteCallResult {
|
fn remote_call(&self, request: RemoteCallRequest<B::Header>) -> Self::RemoteCallResult {
|
||||||
let (sender, receiver) = oneshot::channel();
|
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 }
|
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 (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 }
|
RemoteResponse { receiver }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn remote_body(&self, request: RemoteBodyRequest<B::Header>) -> Self::RemoteBodyResult {
|
fn remote_body(&self, request: RemoteBodyRequest<B::Header>) -> Self::RemoteBodyResult {
|
||||||
let (sender, receiver) = oneshot::channel();
|
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 }
|
RemoteResponse { receiver }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,21 +38,20 @@ use sp_runtime::traits::{
|
|||||||
Block as BlockT, Header as HeaderT, NumberFor, One, Zero, CheckedSub
|
Block as BlockT, Header as HeaderT, NumberFor, One, Zero, CheckedSub
|
||||||
};
|
};
|
||||||
use sp_arithmetic::traits::SaturatedConversion;
|
use sp_arithmetic::traits::SaturatedConversion;
|
||||||
use message::{BlockAnnounce, BlockAttributes, Direction, FromBlock, Message, RequestId};
|
use message::{BlockAnnounce, Message};
|
||||||
use message::generic::{Message as GenericMessage, ConsensusMessage};
|
use message::generic::{Message as GenericMessage, ConsensusMessage};
|
||||||
use light_dispatch::{LightDispatch, LightDispatchNetwork, RequestData};
|
|
||||||
use prometheus_endpoint::{Registry, Gauge, GaugeVec, PrometheusError, Opts, register, U64};
|
use prometheus_endpoint::{Registry, Gauge, GaugeVec, PrometheusError, Opts, register, U64};
|
||||||
use sync::{ChainSync, SyncState};
|
use sync::{ChainSync, SyncState};
|
||||||
use crate::service::{TransactionPool, ExHashT};
|
use crate::service::{TransactionPool, ExHashT};
|
||||||
use crate::config::{BoxFinalityProofRequestBuilder, Roles};
|
use crate::config::{BoxFinalityProofRequestBuilder, Roles};
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
use std::collections::{BTreeMap, HashMap, HashSet};
|
use std::collections::{BTreeMap, HashMap, HashSet, VecDeque};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::fmt::Write;
|
use std::fmt::Write;
|
||||||
use std::{cmp, num::NonZeroUsize, pin::Pin, task::Poll, time};
|
use std::{cmp, num::NonZeroUsize, pin::Pin, task::Poll, time};
|
||||||
use log::{log, Level, trace, debug, warn, error};
|
use log::{log, Level, trace, debug, warn, error};
|
||||||
use crate::chain::{Client, FinalityProofProvider};
|
use crate::chain::{Client, FinalityProofProvider};
|
||||||
use sc_client_api::{FetchChecker, ChangesProof, StorageProof};
|
use sc_client_api::{ChangesProof, StorageProof};
|
||||||
use crate::error;
|
use crate::error;
|
||||||
use util::LruHashSet;
|
use util::LruHashSet;
|
||||||
use wasm_timer::Instant;
|
use wasm_timer::Instant;
|
||||||
@@ -74,7 +73,6 @@ pub mod block_requests;
|
|||||||
pub mod message;
|
pub mod message;
|
||||||
pub mod event;
|
pub mod event;
|
||||||
pub mod light_client_handler;
|
pub mod light_client_handler;
|
||||||
pub mod light_dispatch;
|
|
||||||
pub mod sync;
|
pub mod sync;
|
||||||
|
|
||||||
pub use block_requests::BlockRequests;
|
pub use block_requests::BlockRequests;
|
||||||
@@ -201,9 +199,9 @@ pub struct Protocol<B: BlockT, H: ExHashT> {
|
|||||||
tick_timeout: Pin<Box<dyn Stream<Item = ()> + Send>>,
|
tick_timeout: Pin<Box<dyn Stream<Item = ()> + Send>>,
|
||||||
/// Interval at which we call `propagate_extrinsics`.
|
/// Interval at which we call `propagate_extrinsics`.
|
||||||
propagate_timeout: Pin<Box<dyn Stream<Item = ()> + Send>>,
|
propagate_timeout: Pin<Box<dyn Stream<Item = ()> + Send>>,
|
||||||
|
/// Pending list of messages to return from `poll` as a priority.
|
||||||
|
pending_messages: VecDeque<CustomMessageOutcome<B>>,
|
||||||
config: ProtocolConfig,
|
config: ProtocolConfig,
|
||||||
/// Handler for light client requests.
|
|
||||||
light_dispatch: LightDispatch<B>,
|
|
||||||
genesis_hash: B::Hash,
|
genesis_hash: B::Hash,
|
||||||
sync: ChainSync<B>,
|
sync: ChainSync<B>,
|
||||||
context_data: ContextData<B, H>,
|
context_data: ContextData<B, H>,
|
||||||
@@ -276,132 +274,6 @@ pub struct PeerInfo<B: BlockT> {
|
|||||||
pub best_number: <B::Header as HeaderT>::Number,
|
pub best_number: <B::Header as HeaderT>::Number,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct LightDispatchIn<'a> {
|
|
||||||
behaviour: &'a mut GenericProto,
|
|
||||||
peerset: sc_peerset::PeersetHandle,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, B: BlockT> LightDispatchNetwork<B> for LightDispatchIn<'a> {
|
|
||||||
fn report_peer(&mut self, who: &PeerId, reputation: sc_peerset::ReputationChange) {
|
|
||||||
self.peerset.report_peer(who.clone(), reputation)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn disconnect_peer(&mut self, who: &PeerId) {
|
|
||||||
self.behaviour.disconnect_peer(who)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn send_header_request(&mut self, who: &PeerId, id: RequestId, block: <<B as BlockT>::Header as HeaderT>::Number) {
|
|
||||||
let message: Message<B> = message::generic::Message::RemoteHeaderRequest(message::RemoteHeaderRequest {
|
|
||||||
id,
|
|
||||||
block,
|
|
||||||
});
|
|
||||||
|
|
||||||
self.behaviour.send_packet(who, message.encode())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn send_read_request(
|
|
||||||
&mut self,
|
|
||||||
who: &PeerId,
|
|
||||||
id: RequestId,
|
|
||||||
block: <B as BlockT>::Hash,
|
|
||||||
keys: Vec<Vec<u8>>,
|
|
||||||
) {
|
|
||||||
let message: Message<B> = message::generic::Message::RemoteReadRequest(message::RemoteReadRequest {
|
|
||||||
id,
|
|
||||||
block,
|
|
||||||
keys,
|
|
||||||
});
|
|
||||||
|
|
||||||
self.behaviour.send_packet(who, message.encode())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn send_read_child_request(
|
|
||||||
&mut self,
|
|
||||||
who: &PeerId,
|
|
||||||
id: RequestId,
|
|
||||||
block: <B as BlockT>::Hash,
|
|
||||||
storage_key: Vec<u8>,
|
|
||||||
child_info: Vec<u8>,
|
|
||||||
child_type: u32,
|
|
||||||
keys: Vec<Vec<u8>>,
|
|
||||||
) {
|
|
||||||
let message: Message<B> = message::generic::Message::RemoteReadChildRequest(message::RemoteReadChildRequest {
|
|
||||||
id,
|
|
||||||
block,
|
|
||||||
storage_key,
|
|
||||||
child_info,
|
|
||||||
child_type,
|
|
||||||
keys,
|
|
||||||
});
|
|
||||||
|
|
||||||
self.behaviour.send_packet(who, message.encode())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn send_call_request(
|
|
||||||
&mut self,
|
|
||||||
who: &PeerId,
|
|
||||||
id: RequestId,
|
|
||||||
block: <B as BlockT>::Hash,
|
|
||||||
method: String,
|
|
||||||
data: Vec<u8>
|
|
||||||
) {
|
|
||||||
let message: Message<B> = message::generic::Message::RemoteCallRequest(message::RemoteCallRequest {
|
|
||||||
id,
|
|
||||||
block,
|
|
||||||
method,
|
|
||||||
data,
|
|
||||||
});
|
|
||||||
|
|
||||||
self.behaviour.send_packet(who, message.encode())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn send_changes_request(
|
|
||||||
&mut self,
|
|
||||||
who: &PeerId,
|
|
||||||
id: RequestId,
|
|
||||||
first: <B as BlockT>::Hash,
|
|
||||||
last: <B as BlockT>::Hash,
|
|
||||||
min: <B as BlockT>::Hash,
|
|
||||||
max: <B as BlockT>::Hash,
|
|
||||||
storage_key: Option<Vec<u8>>,
|
|
||||||
key: Vec<u8>,
|
|
||||||
) {
|
|
||||||
let message: Message<B> = message::generic::Message::RemoteChangesRequest(message::RemoteChangesRequest {
|
|
||||||
id,
|
|
||||||
first,
|
|
||||||
last,
|
|
||||||
min,
|
|
||||||
max,
|
|
||||||
storage_key,
|
|
||||||
key,
|
|
||||||
});
|
|
||||||
|
|
||||||
self.behaviour.send_packet(who, message.encode())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn send_body_request(
|
|
||||||
&mut self,
|
|
||||||
who: &PeerId,
|
|
||||||
id: RequestId,
|
|
||||||
fields: BlockAttributes,
|
|
||||||
from: FromBlock<<B as BlockT>::Hash, <<B as BlockT>::Header as HeaderT>::Number>,
|
|
||||||
to: Option<<B as BlockT>::Hash>,
|
|
||||||
direction: Direction,
|
|
||||||
max: Option<u32>
|
|
||||||
) {
|
|
||||||
let message: Message<B> = message::generic::Message::BlockRequest(message::BlockRequest::<B> {
|
|
||||||
id,
|
|
||||||
fields,
|
|
||||||
from,
|
|
||||||
to,
|
|
||||||
direction,
|
|
||||||
max,
|
|
||||||
});
|
|
||||||
|
|
||||||
self.behaviour.send_packet(who, message.encode())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Data necessary to create a context.
|
/// Data necessary to create a context.
|
||||||
struct ContextData<B: BlockT, H: ExHashT> {
|
struct ContextData<B: BlockT, H: ExHashT> {
|
||||||
// All connected peers
|
// All connected peers
|
||||||
@@ -444,7 +316,6 @@ impl<B: BlockT, H: ExHashT> Protocol<B, H> {
|
|||||||
pub fn new(
|
pub fn new(
|
||||||
config: ProtocolConfig,
|
config: ProtocolConfig,
|
||||||
chain: Arc<dyn Client<B>>,
|
chain: Arc<dyn Client<B>>,
|
||||||
checker: Arc<dyn FetchChecker<B>>,
|
|
||||||
transaction_pool: Arc<dyn TransactionPool<H, B>>,
|
transaction_pool: Arc<dyn TransactionPool<H, B>>,
|
||||||
finality_proof_provider: Option<Arc<dyn FinalityProofProvider<B>>>,
|
finality_proof_provider: Option<Arc<dyn FinalityProofProvider<B>>>,
|
||||||
finality_proof_request_builder: Option<BoxFinalityProofRequestBuilder<B>>,
|
finality_proof_request_builder: Option<BoxFinalityProofRequestBuilder<B>>,
|
||||||
@@ -500,13 +371,13 @@ impl<B: BlockT, H: ExHashT> Protocol<B, H> {
|
|||||||
let protocol = Protocol {
|
let protocol = Protocol {
|
||||||
tick_timeout: Box::pin(interval(TICK_TIMEOUT)),
|
tick_timeout: Box::pin(interval(TICK_TIMEOUT)),
|
||||||
propagate_timeout: Box::pin(interval(PROPAGATE_TIMEOUT)),
|
propagate_timeout: Box::pin(interval(PROPAGATE_TIMEOUT)),
|
||||||
|
pending_messages: VecDeque::new(),
|
||||||
config,
|
config,
|
||||||
context_data: ContextData {
|
context_data: ContextData {
|
||||||
peers: HashMap::new(),
|
peers: HashMap::new(),
|
||||||
stats: HashMap::new(),
|
stats: HashMap::new(),
|
||||||
chain,
|
chain,
|
||||||
},
|
},
|
||||||
light_dispatch: LightDispatch::new(checker),
|
|
||||||
genesis_hash: info.genesis_hash,
|
genesis_hash: info.genesis_hash,
|
||||||
sync,
|
sync,
|
||||||
handshaking_peers: HashMap::new(),
|
handshaking_peers: HashMap::new(),
|
||||||
@@ -609,20 +480,6 @@ impl<B: BlockT, H: ExHashT> Protocol<B, H> {
|
|||||||
self.sync.num_sync_requests()
|
self.sync.num_sync_requests()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Starts a new data demand request.
|
|
||||||
///
|
|
||||||
/// The parameter contains a `Sender` where the result, once received, must be sent.
|
|
||||||
pub(crate) fn add_light_client_request(&mut self, rq: RequestData<B>) {
|
|
||||||
self.light_dispatch.add_request(LightDispatchIn {
|
|
||||||
behaviour: &mut self.behaviour,
|
|
||||||
peerset: self.peerset_handle.clone(),
|
|
||||||
}, rq);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn is_light_response(&self, who: &PeerId, response_id: message::RequestId) -> bool {
|
|
||||||
self.light_dispatch.is_light_response(&who, response_id)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn handle_response(
|
fn handle_response(
|
||||||
&mut self,
|
&mut self,
|
||||||
who: PeerId,
|
who: PeerId,
|
||||||
@@ -682,15 +539,10 @@ impl<B: BlockT, H: ExHashT> Protocol<B, H> {
|
|||||||
GenericMessage::Status(s) => return self.on_status_message(who, s),
|
GenericMessage::Status(s) => return self.on_status_message(who, s),
|
||||||
GenericMessage::BlockRequest(r) => self.on_block_request(who, r),
|
GenericMessage::BlockRequest(r) => self.on_block_request(who, r),
|
||||||
GenericMessage::BlockResponse(r) => {
|
GenericMessage::BlockResponse(r) => {
|
||||||
// Note, this is safe because only `ordinary bodies` and `remote bodies` are received in this matter.
|
if let Some(request) = self.handle_response(who.clone(), &r) {
|
||||||
if self.is_light_response(&who, r.id) {
|
let outcome = self.on_block_response(who.clone(), request, r);
|
||||||
self.on_remote_body_response(who, r);
|
self.update_peer_info(&who);
|
||||||
} else {
|
return outcome
|
||||||
if let Some(request) = self.handle_response(who.clone(), &r) {
|
|
||||||
let outcome = self.on_block_response(who.clone(), request, r);
|
|
||||||
self.update_peer_info(&who);
|
|
||||||
return outcome
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
GenericMessage::BlockAnnounce(announce) => {
|
GenericMessage::BlockAnnounce(announce) => {
|
||||||
@@ -701,20 +553,20 @@ impl<B: BlockT, H: ExHashT> Protocol<B, H> {
|
|||||||
GenericMessage::Transactions(m) =>
|
GenericMessage::Transactions(m) =>
|
||||||
self.on_extrinsics(who, m),
|
self.on_extrinsics(who, m),
|
||||||
GenericMessage::RemoteCallRequest(request) => self.on_remote_call_request(who, request),
|
GenericMessage::RemoteCallRequest(request) => self.on_remote_call_request(who, request),
|
||||||
GenericMessage::RemoteCallResponse(response) =>
|
GenericMessage::RemoteCallResponse(_) =>
|
||||||
self.on_remote_call_response(who, response),
|
warn!(target: "sub-libp2p", "Received unexpected RemoteCallResponse"),
|
||||||
GenericMessage::RemoteReadRequest(request) =>
|
GenericMessage::RemoteReadRequest(request) =>
|
||||||
self.on_remote_read_request(who, request),
|
self.on_remote_read_request(who, request),
|
||||||
GenericMessage::RemoteReadResponse(response) =>
|
GenericMessage::RemoteReadResponse(_) =>
|
||||||
self.on_remote_read_response(who, response),
|
warn!(target: "sub-libp2p", "Received unexpected RemoteReadResponse"),
|
||||||
GenericMessage::RemoteHeaderRequest(request) =>
|
GenericMessage::RemoteHeaderRequest(request) =>
|
||||||
self.on_remote_header_request(who, request),
|
self.on_remote_header_request(who, request),
|
||||||
GenericMessage::RemoteHeaderResponse(response) =>
|
GenericMessage::RemoteHeaderResponse(_) =>
|
||||||
self.on_remote_header_response(who, response),
|
warn!(target: "sub-libp2p", "Received unexpected RemoteHeaderResponse"),
|
||||||
GenericMessage::RemoteChangesRequest(request) =>
|
GenericMessage::RemoteChangesRequest(request) =>
|
||||||
self.on_remote_changes_request(who, request),
|
self.on_remote_changes_request(who, request),
|
||||||
GenericMessage::RemoteChangesResponse(response) =>
|
GenericMessage::RemoteChangesResponse(_) =>
|
||||||
self.on_remote_changes_response(who, response),
|
warn!(target: "sub-libp2p", "Received unexpected RemoteChangesResponse"),
|
||||||
GenericMessage::FinalityProofRequest(request) =>
|
GenericMessage::FinalityProofRequest(request) =>
|
||||||
self.on_finality_proof_request(who, request),
|
self.on_finality_proof_request(who, request),
|
||||||
GenericMessage::FinalityProofResponse(response) =>
|
GenericMessage::FinalityProofResponse(response) =>
|
||||||
@@ -805,10 +657,6 @@ impl<B: BlockT, H: ExHashT> Protocol<B, H> {
|
|||||||
};
|
};
|
||||||
if let Some(_peer_data) = removed {
|
if let Some(_peer_data) = removed {
|
||||||
self.sync.peer_disconnected(peer.clone());
|
self.sync.peer_disconnected(peer.clone());
|
||||||
self.light_dispatch.on_disconnect(LightDispatchIn {
|
|
||||||
behaviour: &mut self.behaviour,
|
|
||||||
peerset: self.peerset_handle.clone(),
|
|
||||||
}, &peer);
|
|
||||||
|
|
||||||
// Notify all the notification protocols as closed.
|
// Notify all the notification protocols as closed.
|
||||||
CustomMessageOutcome::NotificationStreamClosed {
|
CustomMessageOutcome::NotificationStreamClosed {
|
||||||
@@ -989,10 +837,6 @@ impl<B: BlockT, H: ExHashT> Protocol<B, H> {
|
|||||||
/// > **Note**: This method normally doesn't have to be called except for testing purposes.
|
/// > **Note**: This method normally doesn't have to be called except for testing purposes.
|
||||||
pub fn tick(&mut self) {
|
pub fn tick(&mut self) {
|
||||||
self.maintain_peers();
|
self.maintain_peers();
|
||||||
self.light_dispatch.maintain_peers(LightDispatchIn {
|
|
||||||
behaviour: &mut self.behaviour,
|
|
||||||
peerset: self.peerset_handle.clone(),
|
|
||||||
});
|
|
||||||
self.report_metrics()
|
self.report_metrics()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1140,10 +984,7 @@ impl<B: BlockT, H: ExHashT> Protocol<B, H> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let info = self.context_data.peers.get(&who).expect("We just inserted above; QED").info.clone();
|
let info = self.context_data.peers.get(&who).expect("We just inserted above; QED").info.clone();
|
||||||
self.light_dispatch.on_connect(LightDispatchIn {
|
self.pending_messages.push_back(CustomMessageOutcome::PeerNewBest(who.clone(), status.best_number));
|
||||||
behaviour: &mut self.behaviour,
|
|
||||||
peerset: self.peerset_handle.clone(),
|
|
||||||
}, who.clone(), status.roles, status.best_number);
|
|
||||||
if info.roles.is_full() {
|
if info.roles.is_full() {
|
||||||
match self.sync.new_peer(who.clone(), info.best_hash, info.best_number) {
|
match self.sync.new_peer(who.clone(), info.best_hash, info.best_number) {
|
||||||
Ok(None) => (),
|
Ok(None) => (),
|
||||||
@@ -1408,13 +1249,11 @@ impl<B: BlockT, H: ExHashT> Protocol<B, H> {
|
|||||||
announce: BlockAnnounce<B::Header>,
|
announce: BlockAnnounce<B::Header>,
|
||||||
) -> CustomMessageOutcome<B> {
|
) -> CustomMessageOutcome<B> {
|
||||||
let hash = announce.header.hash();
|
let hash = announce.header.hash();
|
||||||
|
let number = *announce.header.number();
|
||||||
|
|
||||||
if let Some(ref mut peer) = self.context_data.peers.get_mut(&who) {
|
if let Some(ref mut peer) = self.context_data.peers.get_mut(&who) {
|
||||||
peer.known_blocks.insert(hash.clone());
|
peer.known_blocks.insert(hash.clone());
|
||||||
}
|
}
|
||||||
self.light_dispatch.update_best_number(LightDispatchIn {
|
|
||||||
behaviour: &mut self.behaviour,
|
|
||||||
peerset: self.peerset_handle.clone(),
|
|
||||||
}, who.clone(), *announce.header.number());
|
|
||||||
|
|
||||||
let is_their_best = match announce.state.unwrap_or(message::BlockState::Best) {
|
let is_their_best = match announce.state.unwrap_or(message::BlockState::Best) {
|
||||||
message::BlockState::Best => true,
|
message::BlockState::Best => true,
|
||||||
@@ -1429,7 +1268,11 @@ impl<B: BlockT, H: ExHashT> Protocol<B, H> {
|
|||||||
// 1) we're on light client;
|
// 1) we're on light client;
|
||||||
// AND
|
// AND
|
||||||
// 2) parent block is already imported and not pruned.
|
// 2) parent block is already imported and not pruned.
|
||||||
return CustomMessageOutcome::None
|
if is_their_best {
|
||||||
|
return CustomMessageOutcome::PeerNewBest(who, number);
|
||||||
|
} else {
|
||||||
|
return CustomMessageOutcome::None;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
sync::OnBlockAnnounce::ImportHeader => () // We proceed with the import.
|
sync::OnBlockAnnounce::ImportHeader => () // We proceed with the import.
|
||||||
}
|
}
|
||||||
@@ -1454,15 +1297,28 @@ impl<B: BlockT, H: ExHashT> Protocol<B, H> {
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
match blocks_to_import {
|
match blocks_to_import {
|
||||||
Ok(sync::OnBlockData::Import(origin, blocks)) => CustomMessageOutcome::BlockImport(origin, blocks),
|
Ok(sync::OnBlockData::Import(origin, blocks)) => {
|
||||||
|
if is_their_best {
|
||||||
|
self.pending_messages.push_back(CustomMessageOutcome::PeerNewBest(who, number));
|
||||||
|
}
|
||||||
|
CustomMessageOutcome::BlockImport(origin, blocks)
|
||||||
|
},
|
||||||
Ok(sync::OnBlockData::Request(peer, req)) => {
|
Ok(sync::OnBlockData::Request(peer, req)) => {
|
||||||
self.send_request(&peer, GenericMessage::BlockRequest(req));
|
self.send_request(&peer, GenericMessage::BlockRequest(req));
|
||||||
CustomMessageOutcome::None
|
if is_their_best {
|
||||||
|
CustomMessageOutcome::PeerNewBest(who, number)
|
||||||
|
} else {
|
||||||
|
CustomMessageOutcome::None
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Err(sync::BadPeer(id, repu)) => {
|
Err(sync::BadPeer(id, repu)) => {
|
||||||
self.behaviour.disconnect_peer(&id);
|
self.behaviour.disconnect_peer(&id);
|
||||||
self.peerset_handle.report_peer(id, repu);
|
self.peerset_handle.report_peer(id, repu);
|
||||||
CustomMessageOutcome::None
|
if is_their_best {
|
||||||
|
CustomMessageOutcome::PeerNewBest(who, number)
|
||||||
|
} else {
|
||||||
|
CustomMessageOutcome::None
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1597,18 +1453,6 @@ impl<B: BlockT, H: ExHashT> Protocol<B, H> {
|
|||||||
self.sync.on_finality_proof_import(request_block, finalization_result)
|
self.sync.on_finality_proof_import(request_block, finalization_result)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn on_remote_call_response(
|
|
||||||
&mut self,
|
|
||||||
who: PeerId,
|
|
||||||
response: message::RemoteCallResponse
|
|
||||||
) {
|
|
||||||
trace!(target: "sync", "Remote call response {} from {}", response.id, who);
|
|
||||||
self.light_dispatch.on_remote_call_response(LightDispatchIn {
|
|
||||||
behaviour: &mut self.behaviour,
|
|
||||||
peerset: self.peerset_handle.clone(),
|
|
||||||
}, who, response);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn on_remote_read_request(
|
fn on_remote_read_request(
|
||||||
&mut self,
|
&mut self,
|
||||||
who: PeerId,
|
who: PeerId,
|
||||||
@@ -1723,18 +1567,6 @@ impl<B: BlockT, H: ExHashT> Protocol<B, H> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn on_remote_read_response(
|
|
||||||
&mut self,
|
|
||||||
who: PeerId,
|
|
||||||
response: message::RemoteReadResponse
|
|
||||||
) {
|
|
||||||
trace!(target: "sync", "Remote read response {} from {}", response.id, who);
|
|
||||||
self.light_dispatch.on_remote_read_response(LightDispatchIn {
|
|
||||||
behaviour: &mut self.behaviour,
|
|
||||||
peerset: self.peerset_handle.clone(),
|
|
||||||
}, who, response);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn on_remote_header_request(
|
fn on_remote_header_request(
|
||||||
&mut self,
|
&mut self,
|
||||||
who: PeerId,
|
who: PeerId,
|
||||||
@@ -1765,18 +1597,6 @@ impl<B: BlockT, H: ExHashT> Protocol<B, H> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn on_remote_header_response(
|
|
||||||
&mut self,
|
|
||||||
who: PeerId,
|
|
||||||
response: message::RemoteHeaderResponse<B::Header>,
|
|
||||||
) {
|
|
||||||
trace!(target: "sync", "Remote header proof response {} from {}", response.id, who);
|
|
||||||
self.light_dispatch.on_remote_header_response(LightDispatchIn {
|
|
||||||
behaviour: &mut self.behaviour,
|
|
||||||
peerset: self.peerset_handle.clone(),
|
|
||||||
}, who, response);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn on_remote_changes_request(
|
fn on_remote_changes_request(
|
||||||
&mut self,
|
&mut self,
|
||||||
who: PeerId,
|
who: PeerId,
|
||||||
@@ -1838,22 +1658,6 @@ impl<B: BlockT, H: ExHashT> Protocol<B, H> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn on_remote_changes_response(
|
|
||||||
&mut self,
|
|
||||||
who: PeerId,
|
|
||||||
response: message::RemoteChangesResponse<NumberFor<B>, B::Hash>,
|
|
||||||
) {
|
|
||||||
trace!(target: "sync", "Remote changes proof response {} from {} (max={})",
|
|
||||||
response.id,
|
|
||||||
who,
|
|
||||||
response.max
|
|
||||||
);
|
|
||||||
self.light_dispatch.on_remote_changes_response(LightDispatchIn {
|
|
||||||
behaviour: &mut self.behaviour,
|
|
||||||
peerset: self.peerset_handle.clone(),
|
|
||||||
}, who, response);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn on_finality_proof_request(
|
fn on_finality_proof_request(
|
||||||
&mut self,
|
&mut self,
|
||||||
who: PeerId,
|
who: PeerId,
|
||||||
@@ -1905,17 +1709,6 @@ impl<B: BlockT, H: ExHashT> Protocol<B, H> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn on_remote_body_response(
|
|
||||||
&mut self,
|
|
||||||
peer: PeerId,
|
|
||||||
response: message::BlockResponse<B>
|
|
||||||
) {
|
|
||||||
self.light_dispatch.on_remote_body_response(LightDispatchIn {
|
|
||||||
behaviour: &mut self.behaviour,
|
|
||||||
peerset: self.peerset_handle.clone(),
|
|
||||||
}, peer, response);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn format_stats(&self) -> String {
|
fn format_stats(&self) -> String {
|
||||||
let mut out = String::new();
|
let mut out = String::new();
|
||||||
for (id, stats) in &self.context_data.stats {
|
for (id, stats) in &self.context_data.stats {
|
||||||
@@ -1987,6 +1780,8 @@ pub enum CustomMessageOutcome<B: BlockT> {
|
|||||||
NotificationStreamClosed { remote: PeerId, protocols: Vec<ConsensusEngineId> },
|
NotificationStreamClosed { remote: PeerId, protocols: Vec<ConsensusEngineId> },
|
||||||
/// Messages have been received on one or more notifications protocols.
|
/// Messages have been received on one or more notifications protocols.
|
||||||
NotificationsReceived { remote: PeerId, messages: Vec<(ConsensusEngineId, Bytes)> },
|
NotificationsReceived { remote: PeerId, messages: Vec<(ConsensusEngineId, Bytes)> },
|
||||||
|
/// Peer has a reported a new head of chain.
|
||||||
|
PeerNewBest(PeerId, NumberFor<B>),
|
||||||
None,
|
None,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2067,6 +1862,10 @@ impl<B: BlockT, H: ExHashT> NetworkBehaviour for Protocol<B, H> {
|
|||||||
Self::OutEvent
|
Self::OutEvent
|
||||||
>
|
>
|
||||||
> {
|
> {
|
||||||
|
if let Some(message) = self.pending_messages.pop_front() {
|
||||||
|
return Poll::Ready(NetworkBehaviourAction::GenerateEvent(message));
|
||||||
|
}
|
||||||
|
|
||||||
while let Poll::Ready(Some(())) = self.tick_timeout.poll_next_unpin(cx) {
|
while let Poll::Ready(Some(())) = self.tick_timeout.poll_next_unpin(cx) {
|
||||||
self.tick();
|
self.tick();
|
||||||
}
|
}
|
||||||
@@ -2221,7 +2020,6 @@ impl<B: BlockT, H: ExHashT> Drop for Protocol<B, H> {
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use crate::PeerId;
|
use crate::PeerId;
|
||||||
use crate::protocol::light_dispatch::AlwaysBadChecker;
|
|
||||||
use crate::config::{EmptyTransactionPool, Roles};
|
use crate::config::{EmptyTransactionPool, Roles};
|
||||||
use super::{CustomMessageOutcome, Protocol, ProtocolConfig};
|
use super::{CustomMessageOutcome, Protocol, ProtocolConfig};
|
||||||
|
|
||||||
@@ -2240,7 +2038,6 @@ mod tests {
|
|||||||
max_parallel_downloads: 10,
|
max_parallel_downloads: 10,
|
||||||
},
|
},
|
||||||
client.clone(),
|
client.clone(),
|
||||||
Arc::new(AlwaysBadChecker),
|
|
||||||
Arc::new(EmptyTransactionPool),
|
Arc::new(EmptyTransactionPool),
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ use codec::{self, Encode, Decode};
|
|||||||
use crate::{
|
use crate::{
|
||||||
chain::Client,
|
chain::Client,
|
||||||
config::ProtocolId,
|
config::ProtocolId,
|
||||||
protocol::{api, light_dispatch::TIMEOUT_REPUTATION_CHANGE}
|
protocol::{api, message::BlockAttributes}
|
||||||
};
|
};
|
||||||
use futures::{channel::oneshot, future::BoxFuture, prelude::*, stream::FuturesUnordered};
|
use futures::{channel::oneshot, future::BoxFuture, prelude::*, stream::FuturesUnordered};
|
||||||
use libp2p::{
|
use libp2p::{
|
||||||
@@ -74,6 +74,9 @@ use std::{
|
|||||||
use void::Void;
|
use void::Void;
|
||||||
use wasm_timer::Instant;
|
use wasm_timer::Instant;
|
||||||
|
|
||||||
|
/// Reputation change for a peer when a request timed out.
|
||||||
|
pub(crate) const TIMEOUT_REPUTATION_CHANGE: i32 = -(1 << 8);
|
||||||
|
|
||||||
/// Configuration options for `LightClientHandler` behaviour.
|
/// Configuration options for `LightClientHandler` behaviour.
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct Config {
|
pub struct Config {
|
||||||
@@ -82,7 +85,8 @@ pub struct Config {
|
|||||||
max_pending_requests: usize,
|
max_pending_requests: usize,
|
||||||
inactivity_timeout: Duration,
|
inactivity_timeout: Duration,
|
||||||
request_timeout: Duration,
|
request_timeout: Duration,
|
||||||
protocol: Bytes,
|
light_protocol: Bytes,
|
||||||
|
block_protocol: Bytes,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Config {
|
impl Config {
|
||||||
@@ -100,7 +104,8 @@ impl Config {
|
|||||||
max_pending_requests: 128,
|
max_pending_requests: 128,
|
||||||
inactivity_timeout: Duration::from_secs(15),
|
inactivity_timeout: Duration::from_secs(15),
|
||||||
request_timeout: Duration::from_secs(15),
|
request_timeout: Duration::from_secs(15),
|
||||||
protocol: Bytes::new(),
|
light_protocol: Bytes::new(),
|
||||||
|
block_protocol: Bytes::new(),
|
||||||
};
|
};
|
||||||
c.set_protocol(id);
|
c.set_protocol(id);
|
||||||
c
|
c
|
||||||
@@ -138,11 +143,18 @@ impl Config {
|
|||||||
|
|
||||||
/// Set protocol to use for upgrade negotiation.
|
/// Set protocol to use for upgrade negotiation.
|
||||||
pub fn set_protocol(&mut self, id: &ProtocolId) -> &mut Self {
|
pub fn set_protocol(&mut self, id: &ProtocolId) -> &mut Self {
|
||||||
let mut v = Vec::new();
|
let mut vl = Vec::new();
|
||||||
v.extend_from_slice(b"/");
|
vl.extend_from_slice(b"/");
|
||||||
v.extend_from_slice(id.as_bytes());
|
vl.extend_from_slice(id.as_bytes());
|
||||||
v.extend_from_slice(b"/light/2");
|
vl.extend_from_slice(b"/light/2");
|
||||||
self.protocol = v.into();
|
self.light_protocol = vl.into();
|
||||||
|
|
||||||
|
let mut vb = Vec::new();
|
||||||
|
vb.extend_from_slice(b"/");
|
||||||
|
vb.extend_from_slice(id.as_bytes());
|
||||||
|
vb.extend_from_slice(b"/sync/2");
|
||||||
|
self.block_protocol = vb.into();
|
||||||
|
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -176,6 +188,10 @@ pub enum Error {
|
|||||||
// used because we currently only support a subset of those.
|
// used because we currently only support a subset of those.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum Request<B: Block> {
|
pub enum Request<B: Block> {
|
||||||
|
Body {
|
||||||
|
request: fetcher::RemoteBodyRequest<B::Header>,
|
||||||
|
sender: oneshot::Sender<Result<Vec<B::Extrinsic>, ClientError>>
|
||||||
|
},
|
||||||
Header {
|
Header {
|
||||||
request: fetcher::RemoteHeaderRequest<B::Header>,
|
request: fetcher::RemoteHeaderRequest<B::Header>,
|
||||||
sender: oneshot::Sender<Result<B::Header, ClientError>>
|
sender: oneshot::Sender<Result<B::Header, ClientError>>
|
||||||
@@ -208,7 +224,8 @@ enum Reply<B: Block> {
|
|||||||
VecU8(Vec<u8>),
|
VecU8(Vec<u8>),
|
||||||
VecNumberU32(Vec<(<B::Header as Header>::Number, u32)>),
|
VecNumberU32(Vec<(<B::Header as Header>::Number, u32)>),
|
||||||
MapVecU8OptVecU8(HashMap<Vec<u8>, Option<Vec<u8>>>),
|
MapVecU8OptVecU8(HashMap<Vec<u8>, Option<Vec<u8>>>),
|
||||||
Header(B::Header)
|
Header(B::Header),
|
||||||
|
Extrinsics(Vec<B::Extrinsic>),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Augments a light client request with metadata.
|
/// Augments a light client request with metadata.
|
||||||
@@ -291,6 +308,7 @@ where
|
|||||||
/// means to determine it ourselves.
|
/// means to determine it ourselves.
|
||||||
pub fn update_best_block(&mut self, peer: &PeerId, num: NumberFor<B>) {
|
pub fn update_best_block(&mut self, peer: &PeerId, num: NumberFor<B>) {
|
||||||
if let Some(info) = self.peers.get_mut(peer) {
|
if let Some(info) = self.peers.get_mut(peer) {
|
||||||
|
log::trace!("new best block for {:?}: {:?}", peer, num);
|
||||||
info.best_block = Some(num)
|
info.best_block = Some(num)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -360,10 +378,23 @@ where
|
|||||||
( &mut self
|
( &mut self
|
||||||
, peer: &PeerId
|
, peer: &PeerId
|
||||||
, request: &Request<B>
|
, request: &Request<B>
|
||||||
, response: api::v1::light::Response
|
, response: Response
|
||||||
) -> Result<Reply<B>, Error>
|
) -> Result<Reply<B>, Error>
|
||||||
{
|
{
|
||||||
log::trace!("response from {}", peer);
|
log::trace!("response from {}", peer);
|
||||||
|
match response {
|
||||||
|
Response::Light(r) => self.on_response_light(peer, request, r),
|
||||||
|
Response::Block(r) => self.on_response_block(peer, request, r),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn on_response_light
|
||||||
|
( &mut self
|
||||||
|
, peer: &PeerId
|
||||||
|
, request: &Request<B>
|
||||||
|
, response: api::v1::light::Response
|
||||||
|
) -> Result<Reply<B>, Error>
|
||||||
|
{
|
||||||
use api::v1::light::response::Response;
|
use api::v1::light::response::Response;
|
||||||
match response.response {
|
match response.response {
|
||||||
Some(Response::RemoteCallResponse(response)) =>
|
Some(Response::RemoteCallResponse(response)) =>
|
||||||
@@ -429,6 +460,32 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn on_response_block
|
||||||
|
( &mut self
|
||||||
|
, peer: &PeerId
|
||||||
|
, request: &Request<B>
|
||||||
|
, response: api::v1::BlockResponse
|
||||||
|
) -> Result<Reply<B>, Error>
|
||||||
|
{
|
||||||
|
let request = if let Request::Body { request , .. } = &request {
|
||||||
|
request
|
||||||
|
} else {
|
||||||
|
return Err(Error::UnexpectedResponse);
|
||||||
|
};
|
||||||
|
|
||||||
|
let body: Vec<_> = match response.blocks.into_iter().next() {
|
||||||
|
Some(b) => b.body,
|
||||||
|
None => return Err(Error::UnexpectedResponse),
|
||||||
|
};
|
||||||
|
|
||||||
|
let body = body.into_iter()
|
||||||
|
.map(|mut extrinsic| B::Extrinsic::decode(&mut &extrinsic[..]))
|
||||||
|
.collect::<Result<_, _>>()?;
|
||||||
|
|
||||||
|
let body = self.checker.check_body_proof(&request, body)?;
|
||||||
|
Ok(Reply::Extrinsics(body))
|
||||||
|
}
|
||||||
|
|
||||||
fn on_remote_call_request
|
fn on_remote_call_request
|
||||||
( &mut self
|
( &mut self
|
||||||
, peer: &PeerId
|
, peer: &PeerId
|
||||||
@@ -664,7 +721,7 @@ where
|
|||||||
fn new_handler(&mut self) -> Self::ProtocolsHandler {
|
fn new_handler(&mut self) -> Self::ProtocolsHandler {
|
||||||
let p = InboundProtocol {
|
let p = InboundProtocol {
|
||||||
max_request_size: self.config.max_request_size,
|
max_request_size: self.config.max_request_size,
|
||||||
protocol: self.config.protocol.clone(),
|
protocol: self.config.light_protocol.clone(),
|
||||||
};
|
};
|
||||||
OneShotHandler::new(SubstreamProtocol::new(p), self.config.inactivity_timeout)
|
OneShotHandler::new(SubstreamProtocol::new(p), self.config.inactivity_timeout)
|
||||||
}
|
}
|
||||||
@@ -839,30 +896,40 @@ where
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
if let Some(peer) = available_peer {
|
if let Some(peer) = available_peer {
|
||||||
let rq = serialize_request(&request.request);
|
let buf = match serialize_request(&request.request) {
|
||||||
let mut buf = Vec::with_capacity(rq.encoded_len());
|
Ok(b) => b,
|
||||||
if let Err(e) = rq.encode(&mut buf) {
|
Err(e) => {
|
||||||
log::debug!("failed to serialize request: {}", e);
|
log::debug!("failed to serialize request: {}", e);
|
||||||
send_reply(Err(ClientError::RemoteFetchFailed), request.request)
|
send_reply(Err(ClientError::RemoteFetchFailed), request.request);
|
||||||
} else {
|
continue;
|
||||||
let id = self.next_request_id();
|
}
|
||||||
log::trace!("sending request {} to peer {}", id, peer);
|
};
|
||||||
let protocol = OutboundProtocol {
|
|
||||||
request: buf,
|
let id = self.next_request_id();
|
||||||
request_id: id,
|
log::trace!("sending request {} to peer {}", id, peer);
|
||||||
max_response_size: self.config.max_response_size,
|
let protocol = OutboundProtocol {
|
||||||
protocol: self.config.protocol.clone(),
|
request: buf,
|
||||||
};
|
request_id: id,
|
||||||
self.peers.get_mut(&peer).map(|info| info.status = PeerStatus::BusyWith(id));
|
expected: match request.request {
|
||||||
let rw = RequestWrapper {
|
Request::Body { .. } => ExpectedResponseTy::Block,
|
||||||
timestamp: request.timestamp,
|
_ => ExpectedResponseTy::Light,
|
||||||
retries: request.retries,
|
},
|
||||||
request: request.request,
|
max_response_size: self.config.max_response_size,
|
||||||
peer: peer.clone(),
|
protocol: match request.request {
|
||||||
};
|
Request::Body { .. } => self.config.block_protocol.clone(),
|
||||||
self.outstanding.insert(id, rw);
|
_ => self.config.light_protocol.clone(),
|
||||||
return Poll::Ready(NetworkBehaviourAction::SendEvent { peer_id: peer, event: protocol })
|
},
|
||||||
}
|
};
|
||||||
|
self.peers.get_mut(&peer).map(|info| info.status = PeerStatus::BusyWith(id));
|
||||||
|
let rw = RequestWrapper {
|
||||||
|
timestamp: request.timestamp,
|
||||||
|
retries: request.retries,
|
||||||
|
request: request.request,
|
||||||
|
peer: peer.clone(),
|
||||||
|
};
|
||||||
|
self.outstanding.insert(id, rw);
|
||||||
|
return Poll::Ready(NetworkBehaviourAction::SendEvent { peer_id: peer, event: protocol })
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
self.pending_requests.push_front(request);
|
self.pending_requests.push_front(request);
|
||||||
log::debug!("no peer available to send request to");
|
log::debug!("no peer available to send request to");
|
||||||
@@ -903,6 +970,7 @@ where
|
|||||||
|
|
||||||
fn required_block<B: Block>(request: &Request<B>) -> NumberFor<B> {
|
fn required_block<B: Block>(request: &Request<B>) -> NumberFor<B> {
|
||||||
match request {
|
match request {
|
||||||
|
Request::Body { request, .. } => *request.header.number(),
|
||||||
Request::Header { request, .. } => request.block,
|
Request::Header { request, .. } => request.block,
|
||||||
Request::Read { request, .. } => *request.header.number(),
|
Request::Read { request, .. } => *request.header.number(),
|
||||||
Request::ReadChild { request, .. } => *request.header.number(),
|
Request::ReadChild { request, .. } => *request.header.number(),
|
||||||
@@ -913,6 +981,7 @@ fn required_block<B: Block>(request: &Request<B>) -> NumberFor<B> {
|
|||||||
|
|
||||||
fn retries<B: Block>(request: &Request<B>) -> usize {
|
fn retries<B: Block>(request: &Request<B>) -> usize {
|
||||||
let rc = match request {
|
let rc = match request {
|
||||||
|
Request::Body { request, .. } => request.retry_count,
|
||||||
Request::Header { request, .. } => request.retry_count,
|
Request::Header { request, .. } => request.retry_count,
|
||||||
Request::Read { request, .. } => request.retry_count,
|
Request::Read { request, .. } => request.retry_count,
|
||||||
Request::ReadChild { request, .. } => request.retry_count,
|
Request::ReadChild { request, .. } => request.retry_count,
|
||||||
@@ -922,8 +991,20 @@ fn retries<B: Block>(request: &Request<B>) -> usize {
|
|||||||
rc.unwrap_or(0)
|
rc.unwrap_or(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn serialize_request<B: Block>(request: &Request<B>) -> api::v1::light::Request {
|
fn serialize_request<B: Block>(request: &Request<B>) -> Result<Vec<u8>, prost::EncodeError> {
|
||||||
let request = match request {
|
let request = match request {
|
||||||
|
Request::Body { request, .. } => {
|
||||||
|
let rq = api::v1::BlockRequest {
|
||||||
|
fields: u32::from(BlockAttributes::BODY.bits()),
|
||||||
|
from_block: Some(api::v1::block_request::FromBlock::Hash(request.header.hash().encode())),
|
||||||
|
to_block: Vec::new(),
|
||||||
|
direction: api::v1::Direction::Ascending as i32,
|
||||||
|
max_blocks: 1,
|
||||||
|
};
|
||||||
|
let mut buf = Vec::with_capacity(rq.encoded_len());
|
||||||
|
rq.encode(&mut buf)?;
|
||||||
|
return Ok(buf);
|
||||||
|
}
|
||||||
Request::Header { request, .. } => {
|
Request::Header { request, .. } => {
|
||||||
let r = api::v1::light::RemoteHeaderRequest { block: request.block.encode() };
|
let r = api::v1::light::RemoteHeaderRequest { block: request.block.encode() };
|
||||||
api::v1::light::request::Request::RemoteHeaderRequest(r)
|
api::v1::light::request::Request::RemoteHeaderRequest(r)
|
||||||
@@ -966,7 +1047,10 @@ fn serialize_request<B: Block>(request: &Request<B>) -> api::v1::light::Request
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
api::v1::light::Request { request: Some(request) }
|
let rq = api::v1::light::Request { request: Some(request) };
|
||||||
|
let mut buf = Vec::with_capacity(rq.encoded_len());
|
||||||
|
rq.encode(&mut buf)?;
|
||||||
|
Ok(buf)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn send_reply<B: Block>(result: Result<Reply<B>, ClientError>, request: Request<B>) {
|
fn send_reply<B: Block>(result: Result<Reply<B>, ClientError>, request: Request<B>) {
|
||||||
@@ -974,6 +1058,11 @@ fn send_reply<B: Block>(result: Result<Reply<B>, ClientError>, request: Request<
|
|||||||
let _ = sender.send(item); // It is okay if the other end already hung up.
|
let _ = sender.send(item); // It is okay if the other end already hung up.
|
||||||
}
|
}
|
||||||
match request {
|
match request {
|
||||||
|
Request::Body { request, sender } => match result {
|
||||||
|
Err(e) => send(Err(e), sender),
|
||||||
|
Ok(Reply::Extrinsics(x)) => send(Ok(x), sender),
|
||||||
|
reply => log::error!("invalid reply for body request: {:?}, {:?}", reply, request),
|
||||||
|
}
|
||||||
Request::Header { request, sender } => match result {
|
Request::Header { request, sender } => match result {
|
||||||
Err(e) => send(Err(e), sender),
|
Err(e) => send(Err(e), sender),
|
||||||
Ok(Reply::Header(x)) => send(Ok(x), sender),
|
Ok(Reply::Header(x)) => send(Ok(x), sender),
|
||||||
@@ -1008,7 +1097,16 @@ pub enum Event<T> {
|
|||||||
/// Incoming request from remote and substream to use for the response.
|
/// Incoming request from remote and substream to use for the response.
|
||||||
Request(api::v1::light::Request, T),
|
Request(api::v1::light::Request, T),
|
||||||
/// Incoming response from remote.
|
/// Incoming response from remote.
|
||||||
Response(u64, api::v1::light::Response),
|
Response(u64, Response),
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Incoming response from remote.
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub enum Response {
|
||||||
|
/// Incoming light response from remote.
|
||||||
|
Light(api::v1::light::Response),
|
||||||
|
/// Incoming block response from remote.
|
||||||
|
Block(api::v1::BlockResponse),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Substream upgrade protocol.
|
/// Substream upgrade protocol.
|
||||||
@@ -1023,23 +1121,23 @@ pub struct InboundProtocol {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl UpgradeInfo for InboundProtocol {
|
impl UpgradeInfo for InboundProtocol {
|
||||||
type Info = Bytes;
|
type Info = Bytes;
|
||||||
type InfoIter = iter::Once<Self::Info>;
|
type InfoIter = iter::Once<Self::Info>;
|
||||||
|
|
||||||
fn protocol_info(&self) -> Self::InfoIter {
|
fn protocol_info(&self) -> Self::InfoIter {
|
||||||
iter::once(self.protocol.clone())
|
iter::once(self.protocol.clone())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> InboundUpgrade<T> for InboundProtocol
|
impl<T> InboundUpgrade<T> for InboundProtocol
|
||||||
where
|
where
|
||||||
T: AsyncRead + AsyncWrite + Unpin + Send + 'static
|
T: AsyncRead + AsyncWrite + Unpin + Send + 'static
|
||||||
{
|
{
|
||||||
type Output = Event<T>;
|
type Output = Event<T>;
|
||||||
type Error = ReadOneError;
|
type Error = ReadOneError;
|
||||||
type Future = BoxFuture<'static, Result<Self::Output, Self::Error>>;
|
type Future = BoxFuture<'static, Result<Self::Output, Self::Error>>;
|
||||||
|
|
||||||
fn upgrade_inbound(self, mut s: T, _: Self::Info) -> Self::Future {
|
fn upgrade_inbound(self, mut s: T, _: Self::Info) -> Self::Future {
|
||||||
let future = async move {
|
let future = async move {
|
||||||
let vec = read_one(&mut s, self.max_request_size).await?;
|
let vec = read_one(&mut s, self.max_request_size).await?;
|
||||||
match api::v1::light::Request::decode(&vec[..]) {
|
match api::v1::light::Request::decode(&vec[..]) {
|
||||||
@@ -1060,38 +1158,59 @@ pub struct OutboundProtocol {
|
|||||||
request: Vec<u8>,
|
request: Vec<u8>,
|
||||||
/// Local identifier for the request. Used to associate it with a response.
|
/// Local identifier for the request. Used to associate it with a response.
|
||||||
request_id: u64,
|
request_id: u64,
|
||||||
|
/// Kind of response expected for this request.
|
||||||
|
expected: ExpectedResponseTy,
|
||||||
/// The max. response length in bytes.
|
/// The max. response length in bytes.
|
||||||
max_response_size: usize,
|
max_response_size: usize,
|
||||||
/// The protocol to use for upgrade negotiation.
|
/// The protocol to use for upgrade negotiation.
|
||||||
protocol: Bytes,
|
protocol: Bytes,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl UpgradeInfo for OutboundProtocol {
|
/// Type of response expected from the remote for this request.
|
||||||
type Info = Bytes;
|
#[derive(Debug, Clone)]
|
||||||
type InfoIter = iter::Once<Self::Info>;
|
enum ExpectedResponseTy {
|
||||||
|
Light,
|
||||||
|
Block,
|
||||||
|
}
|
||||||
|
|
||||||
fn protocol_info(&self) -> Self::InfoIter {
|
impl UpgradeInfo for OutboundProtocol {
|
||||||
iter::once(self.protocol.clone())
|
type Info = Bytes;
|
||||||
}
|
type InfoIter = iter::Once<Self::Info>;
|
||||||
|
|
||||||
|
fn protocol_info(&self) -> Self::InfoIter {
|
||||||
|
iter::once(self.protocol.clone())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> OutboundUpgrade<T> for OutboundProtocol
|
impl<T> OutboundUpgrade<T> for OutboundProtocol
|
||||||
where
|
where
|
||||||
T: AsyncRead + AsyncWrite + Unpin + Send + 'static
|
T: AsyncRead + AsyncWrite + Unpin + Send + 'static
|
||||||
{
|
{
|
||||||
type Output = Event<T>;
|
type Output = Event<T>;
|
||||||
type Error = ReadOneError;
|
type Error = ReadOneError;
|
||||||
type Future = BoxFuture<'static, Result<Self::Output, Self::Error>>;
|
type Future = BoxFuture<'static, Result<Self::Output, Self::Error>>;
|
||||||
|
|
||||||
fn upgrade_outbound(self, mut s: T, _: Self::Info) -> Self::Future {
|
fn upgrade_outbound(self, mut s: T, _: Self::Info) -> Self::Future {
|
||||||
let future = async move {
|
let future = async move {
|
||||||
write_one(&mut s, &self.request).await?;
|
write_one(&mut s, &self.request).await?;
|
||||||
let vec = read_one(&mut s, self.max_response_size).await?;
|
let vec = read_one(&mut s, self.max_response_size).await?;
|
||||||
api::v1::light::Response::decode(&vec[..])
|
|
||||||
.map(|r| Event::Response(self.request_id, r))
|
match self.expected {
|
||||||
.map_err(|e| {
|
ExpectedResponseTy::Light => {
|
||||||
ReadOneError::Io(io::Error::new(io::ErrorKind::Other, e))
|
api::v1::light::Response::decode(&vec[..])
|
||||||
})
|
.map(|r| Event::Response(self.request_id, Response::Light(r)))
|
||||||
|
.map_err(|e| {
|
||||||
|
ReadOneError::Io(io::Error::new(io::ErrorKind::Other, e))
|
||||||
|
})
|
||||||
|
},
|
||||||
|
ExpectedResponseTy::Block => {
|
||||||
|
api::v1::BlockResponse::decode(&vec[..])
|
||||||
|
.map(|r| Event::Response(self.request_id, Response::Block(r)))
|
||||||
|
.map_err(|e| {
|
||||||
|
ReadOneError::Io(io::Error::new(io::ErrorKind::Other, e))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
future.boxed()
|
future.boxed()
|
||||||
}
|
}
|
||||||
@@ -1117,7 +1236,7 @@ mod tests {
|
|||||||
use crate::{
|
use crate::{
|
||||||
chain::Client,
|
chain::Client,
|
||||||
config::ProtocolId,
|
config::ProtocolId,
|
||||||
protocol::{api, light_dispatch::tests::{DummyFetchChecker, dummy_header}}
|
protocol::api,
|
||||||
};
|
};
|
||||||
use futures::{channel::oneshot, prelude::*};
|
use futures::{channel::oneshot, prelude::*};
|
||||||
use libp2p::{
|
use libp2p::{
|
||||||
@@ -1139,15 +1258,15 @@ mod tests {
|
|||||||
use sp_blockchain::{Error as ClientError};
|
use sp_blockchain::{Error as ClientError};
|
||||||
use sp_core::storage::ChildInfo;
|
use sp_core::storage::ChildInfo;
|
||||||
use std::{
|
use std::{
|
||||||
collections::HashSet,
|
collections::{HashMap, HashSet},
|
||||||
io,
|
io,
|
||||||
iter::{self, FromIterator},
|
iter::{self, FromIterator},
|
||||||
pin::Pin,
|
pin::Pin,
|
||||||
sync::Arc,
|
sync::Arc,
|
||||||
task::{Context, Poll}
|
task::{Context, Poll}
|
||||||
};
|
};
|
||||||
use sp_runtime::{generic::Header, traits::BlakeTwo256};
|
use sp_runtime::{generic::Header, traits::{BlakeTwo256, Block as BlockT, NumberFor}};
|
||||||
use super::{Event, LightClientHandler, Request, OutboundProtocol, PeerStatus};
|
use super::{Event, LightClientHandler, Request, Response, OutboundProtocol, PeerStatus};
|
||||||
use void::Void;
|
use void::Void;
|
||||||
|
|
||||||
const CHILD_INFO: ChildInfo<'static> = ChildInfo::new_default(b"foobarbaz");
|
const CHILD_INFO: ChildInfo<'static> = ChildInfo::new_default(b"foobarbaz");
|
||||||
@@ -1162,7 +1281,7 @@ mod tests {
|
|||||||
|
|
||||||
fn make_swarm(ok: bool, ps: sc_peerset::PeersetHandle, cf: super::Config) -> Swarm {
|
fn make_swarm(ok: bool, ps: sc_peerset::PeersetHandle, cf: super::Config) -> Swarm {
|
||||||
let client = Arc::new(substrate_test_runtime_client::new());
|
let client = Arc::new(substrate_test_runtime_client::new());
|
||||||
let checker = Arc::new(DummyFetchChecker::new(ok));
|
let checker = Arc::new(DummyFetchChecker { ok, _mark: std::marker::PhantomData });
|
||||||
let id_key = identity::Keypair::generate_ed25519();
|
let id_key = identity::Keypair::generate_ed25519();
|
||||||
let dh_key = Keypair::<X25519>::new().into_authentic(&id_key).unwrap();
|
let dh_key = Keypair::<X25519>::new().into_authentic(&id_key).unwrap();
|
||||||
let local_peer = id_key.public().into_peer_id();
|
let local_peer = id_key.public().into_peer_id();
|
||||||
@@ -1176,10 +1295,104 @@ mod tests {
|
|||||||
Swarm::new(transport, LightClientHandler::new(cf, client, checker, ps), local_peer)
|
Swarm::new(transport, LightClientHandler::new(cf, client, checker, ps), local_peer)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct DummyFetchChecker<B> {
|
||||||
|
ok: bool,
|
||||||
|
_mark: std::marker::PhantomData<B>
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<B: BlockT> fetcher::FetchChecker<B> for DummyFetchChecker<B> {
|
||||||
|
fn check_header_proof(
|
||||||
|
&self,
|
||||||
|
_request: &fetcher::RemoteHeaderRequest<B::Header>,
|
||||||
|
header: Option<B::Header>,
|
||||||
|
_remote_proof: fetcher::StorageProof,
|
||||||
|
) -> Result<B::Header, ClientError> {
|
||||||
|
match self.ok {
|
||||||
|
true if header.is_some() => Ok(header.unwrap()),
|
||||||
|
_ => Err(ClientError::Backend("Test error".into())),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn check_read_proof(
|
||||||
|
&self,
|
||||||
|
request: &fetcher::RemoteReadRequest<B::Header>,
|
||||||
|
_: fetcher::StorageProof,
|
||||||
|
) -> Result<HashMap<Vec<u8>, Option<Vec<u8>>>, ClientError> {
|
||||||
|
match self.ok {
|
||||||
|
true => Ok(request.keys
|
||||||
|
.iter()
|
||||||
|
.cloned()
|
||||||
|
.map(|k| (k, Some(vec![42])))
|
||||||
|
.collect()
|
||||||
|
),
|
||||||
|
false => Err(ClientError::Backend("Test error".into())),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn check_read_child_proof(
|
||||||
|
&self,
|
||||||
|
request: &fetcher::RemoteReadChildRequest<B::Header>,
|
||||||
|
_: fetcher::StorageProof,
|
||||||
|
) -> Result<HashMap<Vec<u8>, Option<Vec<u8>>>, ClientError> {
|
||||||
|
match self.ok {
|
||||||
|
true => Ok(request.keys
|
||||||
|
.iter()
|
||||||
|
.cloned()
|
||||||
|
.map(|k| (k, Some(vec![42])))
|
||||||
|
.collect()
|
||||||
|
),
|
||||||
|
false => Err(ClientError::Backend("Test error".into())),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn check_execution_proof(
|
||||||
|
&self,
|
||||||
|
_: &fetcher::RemoteCallRequest<B::Header>,
|
||||||
|
_: fetcher::StorageProof,
|
||||||
|
) -> Result<Vec<u8>, ClientError> {
|
||||||
|
match self.ok {
|
||||||
|
true => Ok(vec![42]),
|
||||||
|
false => Err(ClientError::Backend("Test error".into())),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn check_changes_proof(
|
||||||
|
&self,
|
||||||
|
_: &fetcher::RemoteChangesRequest<B::Header>,
|
||||||
|
_: fetcher::ChangesProof<B::Header>
|
||||||
|
) -> Result<Vec<(NumberFor<B>, u32)>, ClientError> {
|
||||||
|
match self.ok {
|
||||||
|
true => Ok(vec![(100.into(), 2)]),
|
||||||
|
false => Err(ClientError::Backend("Test error".into())),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn check_body_proof(
|
||||||
|
&self,
|
||||||
|
_: &fetcher::RemoteBodyRequest<B::Header>,
|
||||||
|
body: Vec<B::Extrinsic>
|
||||||
|
) -> Result<Vec<B::Extrinsic>, ClientError> {
|
||||||
|
match self.ok {
|
||||||
|
true => Ok(body),
|
||||||
|
false => Err(ClientError::Backend("Test error".into())),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn make_config() -> super::Config {
|
fn make_config() -> super::Config {
|
||||||
super::Config::new(&ProtocolId::from(&b"foo"[..]))
|
super::Config::new(&ProtocolId::from(&b"foo"[..]))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn dummy_header() -> sp_test_primitives::Header {
|
||||||
|
sp_test_primitives::Header {
|
||||||
|
parent_hash: Default::default(),
|
||||||
|
number: 0,
|
||||||
|
state_root: Default::default(),
|
||||||
|
extrinsics_root: Default::default(),
|
||||||
|
digest: Default::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
struct EmptyPollParams(PeerId);
|
struct EmptyPollParams(PeerId);
|
||||||
|
|
||||||
impl PollParameters for EmptyPollParams {
|
impl PollParameters for EmptyPollParams {
|
||||||
@@ -1222,7 +1435,7 @@ mod tests {
|
|||||||
) -> LightClientHandler<Block>
|
) -> LightClientHandler<Block>
|
||||||
{
|
{
|
||||||
let client = Arc::new(substrate_test_runtime_client::new());
|
let client = Arc::new(substrate_test_runtime_client::new());
|
||||||
let checker = Arc::new(DummyFetchChecker::new(ok));
|
let checker = Arc::new(DummyFetchChecker { ok, _mark: std::marker::PhantomData });
|
||||||
LightClientHandler::new(cf, client, checker, ps)
|
LightClientHandler::new(cf, client, checker, ps)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1349,7 +1562,7 @@ mod tests {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
behaviour.inject_node_event(peer.clone(), Event::Response(request_id, response));
|
behaviour.inject_node_event(peer.clone(), Event::Response(request_id, Response::Light(response)));
|
||||||
assert!(behaviour.peers.is_empty());
|
assert!(behaviour.peers.is_empty());
|
||||||
|
|
||||||
poll(&mut behaviour); // More progress
|
poll(&mut behaviour); // More progress
|
||||||
@@ -1378,7 +1591,7 @@ mod tests {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
behaviour.inject_node_event(peer.clone(), Event::Response(2347895932, response));
|
behaviour.inject_node_event(peer.clone(), Event::Response(2347895932, Response::Light(response)));
|
||||||
|
|
||||||
assert!(behaviour.peers.is_empty());
|
assert!(behaviour.peers.is_empty());
|
||||||
poll(&mut behaviour);
|
poll(&mut behaviour);
|
||||||
@@ -1420,7 +1633,7 @@ mod tests {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
behaviour.inject_node_event(peer.clone(), Event::Response(request_id, response));
|
behaviour.inject_node_event(peer.clone(), Event::Response(request_id, Response::Light(response)));
|
||||||
assert!(behaviour.peers.is_empty());
|
assert!(behaviour.peers.is_empty());
|
||||||
|
|
||||||
poll(&mut behaviour); // More progress
|
poll(&mut behaviour); // More progress
|
||||||
@@ -1472,7 +1685,7 @@ mod tests {
|
|||||||
response: Some(api::v1::light::response::Response::RemoteCallResponse(r))
|
response: Some(api::v1::light::response::Response::RemoteCallResponse(r))
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
behaviour.inject_node_event(responding_peer, Event::Response(request_id, response.clone()));
|
behaviour.inject_node_event(responding_peer, Event::Response(request_id, Response::Light(response.clone())));
|
||||||
assert_matches!(poll(&mut behaviour), Poll::Ready(NetworkBehaviourAction::SendEvent { .. }));
|
assert_matches!(poll(&mut behaviour), Poll::Ready(NetworkBehaviourAction::SendEvent { .. }));
|
||||||
assert_matches!(chan.1.try_recv(), Ok(None))
|
assert_matches!(chan.1.try_recv(), Ok(None))
|
||||||
}
|
}
|
||||||
@@ -1485,7 +1698,7 @@ mod tests {
|
|||||||
response: Some(api::v1::light::response::Response::RemoteCallResponse(r)),
|
response: Some(api::v1::light::response::Response::RemoteCallResponse(r)),
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
behaviour.inject_node_event(responding_peer, Event::Response(request_id, response));
|
behaviour.inject_node_event(responding_peer, Event::Response(request_id, Response::Light(response)));
|
||||||
assert_matches!(poll(&mut behaviour), Poll::Pending);
|
assert_matches!(poll(&mut behaviour), Poll::Pending);
|
||||||
assert_matches!(chan.1.try_recv(), Ok(Some(Err(ClientError::RemoteFetchFailed))))
|
assert_matches!(chan.1.try_recv(), Ok(Some(Err(ClientError::RemoteFetchFailed))))
|
||||||
}
|
}
|
||||||
@@ -1499,6 +1712,7 @@ mod tests {
|
|||||||
assert_eq!(1, behaviour.peers.len());
|
assert_eq!(1, behaviour.peers.len());
|
||||||
|
|
||||||
let response = match request {
|
let response = match request {
|
||||||
|
Request::Body { .. } => unimplemented!(),
|
||||||
Request::Header{..} => {
|
Request::Header{..} => {
|
||||||
let r = api::v1::light::RemoteHeaderResponse {
|
let r = api::v1::light::RemoteHeaderResponse {
|
||||||
header: dummy_header().encode(),
|
header: dummy_header().encode(),
|
||||||
@@ -1548,7 +1762,7 @@ mod tests {
|
|||||||
assert_eq!(1, behaviour.outstanding.len());
|
assert_eq!(1, behaviour.outstanding.len());
|
||||||
assert_eq!(1, *behaviour.outstanding.keys().next().unwrap());
|
assert_eq!(1, *behaviour.outstanding.keys().next().unwrap());
|
||||||
|
|
||||||
behaviour.inject_node_event(peer.clone(), Event::Response(1, response));
|
behaviour.inject_node_event(peer.clone(), Event::Response(1, Response::Light(response)));
|
||||||
|
|
||||||
poll(&mut behaviour);
|
poll(&mut behaviour);
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -25,31 +25,42 @@
|
|||||||
//! The methods of the [`NetworkService`] are implemented by sending a message over a channel,
|
//! The methods of the [`NetworkService`] are implemented by sending a message over a channel,
|
||||||
//! which is then processed by [`NetworkWorker::poll`].
|
//! which is then processed by [`NetworkWorker::poll`].
|
||||||
|
|
||||||
use std::{borrow::Cow, collections::{HashMap, HashSet}, fs, marker::PhantomData, io, path::Path, str};
|
use crate::{
|
||||||
use std::sync::{Arc, atomic::{AtomicBool, AtomicUsize, Ordering}};
|
behaviour::{Behaviour, BehaviourOut},
|
||||||
use std::pin::Pin;
|
config::{parse_addr, parse_str_addr, NonReservedPeerMode, Params, TransportConfig},
|
||||||
use std::task::Poll;
|
error::Error,
|
||||||
|
network_state::{
|
||||||
use sp_consensus::import_queue::{ImportQueue, Link};
|
NetworkState, NotConnectedPeer as NetworkStateNotConnectedPeer, Peer as NetworkStatePeer,
|
||||||
use sp_consensus::import_queue::{BlockImportResult, BlockImportError};
|
},
|
||||||
|
on_demand_layer::AlwaysBadChecker,
|
||||||
|
protocol::{self, event::Event, light_client_handler, sync::SyncState, PeerInfo, Protocol},
|
||||||
|
transport, ReputationChange,
|
||||||
|
};
|
||||||
use futures::{prelude::*, channel::mpsc};
|
use futures::{prelude::*, channel::mpsc};
|
||||||
use log::{warn, error, info, trace};
|
|
||||||
use libp2p::{PeerId, Multiaddr, kad::record};
|
|
||||||
use libp2p::swarm::{NetworkBehaviour, SwarmBuilder, SwarmEvent};
|
use libp2p::swarm::{NetworkBehaviour, SwarmBuilder, SwarmEvent};
|
||||||
|
use libp2p::{kad::record, Multiaddr, PeerId};
|
||||||
|
use log::{error, info, trace, warn};
|
||||||
use parking_lot::Mutex;
|
use parking_lot::Mutex;
|
||||||
|
use prometheus_endpoint::{
|
||||||
|
register, Counter, CounterVec, Gauge, GaugeVec, Opts, PrometheusError, Registry, U64,
|
||||||
|
};
|
||||||
use sc_peerset::PeersetHandle;
|
use sc_peerset::PeersetHandle;
|
||||||
use sp_runtime::{traits::{Block as BlockT, NumberFor}, ConsensusEngineId};
|
use sp_consensus::import_queue::{BlockImportError, BlockImportResult, ImportQueue, Link};
|
||||||
use prometheus_endpoint::{Registry, Counter, CounterVec, Gauge, GaugeVec, Opts, U64, register, PrometheusError};
|
use sp_runtime::{
|
||||||
|
traits::{Block as BlockT, NumberFor},
|
||||||
use crate::{behaviour::{Behaviour, BehaviourOut}, config::{parse_str_addr, parse_addr}};
|
ConsensusEngineId,
|
||||||
use crate::{transport, config::NonReservedPeerMode, ReputationChange};
|
};
|
||||||
use crate::config::{Params, TransportConfig};
|
use std::{
|
||||||
use crate::error::Error;
|
borrow::Cow,
|
||||||
use crate::network_state::{NetworkState, NotConnectedPeer as NetworkStateNotConnectedPeer, Peer as NetworkStatePeer};
|
collections::{HashMap, HashSet},
|
||||||
use crate::protocol::{self, Protocol, PeerInfo};
|
fs, io,
|
||||||
use crate::protocol::{event::Event, light_dispatch::{AlwaysBadChecker, RequestData}};
|
marker::PhantomData,
|
||||||
use crate::protocol::sync::SyncState;
|
path::Path,
|
||||||
|
pin::Pin,
|
||||||
|
str,
|
||||||
|
sync::{atomic::{AtomicBool, AtomicUsize, Ordering}, Arc},
|
||||||
|
task::Poll,
|
||||||
|
};
|
||||||
|
|
||||||
/// Minimum Requirements for a Hash within Networking
|
/// Minimum Requirements for a Hash within Networking
|
||||||
pub trait ExHashT: std::hash::Hash + Eq + std::fmt::Debug + Clone + Send + Sync + 'static {}
|
pub trait ExHashT: std::hash::Hash + Eq + std::fmt::Debug + Clone + Send + Sync + 'static {}
|
||||||
@@ -240,7 +251,6 @@ impl<B: BlockT + 'static, H: ExHashT> NetworkWorker<B, H> {
|
|||||||
max_parallel_downloads: params.network_config.max_parallel_downloads,
|
max_parallel_downloads: params.network_config.max_parallel_downloads,
|
||||||
},
|
},
|
||||||
params.chain.clone(),
|
params.chain.clone(),
|
||||||
checker.clone(),
|
|
||||||
params.transaction_pool,
|
params.transaction_pool,
|
||||||
params.finality_proof_provider.clone(),
|
params.finality_proof_provider.clone(),
|
||||||
params.finality_proof_request_builder,
|
params.finality_proof_request_builder,
|
||||||
@@ -773,7 +783,7 @@ pub struct NetworkWorker<B: BlockT + 'static, H: ExHashT> {
|
|||||||
/// Messages from the `NetworkService` and that must be processed.
|
/// Messages from the `NetworkService` and that must be processed.
|
||||||
from_worker: mpsc::UnboundedReceiver<ServiceToWorkerMsg<B, H>>,
|
from_worker: mpsc::UnboundedReceiver<ServiceToWorkerMsg<B, H>>,
|
||||||
/// Receiver for queries from the light client that must be processed.
|
/// Receiver for queries from the light client that must be processed.
|
||||||
light_client_rqs: Option<mpsc::UnboundedReceiver<RequestData<B>>>,
|
light_client_rqs: Option<mpsc::UnboundedReceiver<light_client_handler::Request<B>>>,
|
||||||
/// Senders for events that happen on the network.
|
/// Senders for events that happen on the network.
|
||||||
event_streams: Vec<mpsc::UnboundedSender<Event>>,
|
event_streams: Vec<mpsc::UnboundedSender<Event>>,
|
||||||
/// Prometheus network metrics.
|
/// Prometheus network metrics.
|
||||||
@@ -789,6 +799,7 @@ struct Metrics {
|
|||||||
import_queue_finality_proofs_submitted: Counter<U64>,
|
import_queue_finality_proofs_submitted: Counter<U64>,
|
||||||
import_queue_justifications_submitted: Counter<U64>,
|
import_queue_justifications_submitted: Counter<U64>,
|
||||||
is_major_syncing: Gauge<U64>,
|
is_major_syncing: Gauge<U64>,
|
||||||
|
issued_light_requests: Counter<U64>,
|
||||||
kbuckets_num_nodes: Gauge<U64>,
|
kbuckets_num_nodes: Gauge<U64>,
|
||||||
network_per_sec_bytes: GaugeVec<U64>,
|
network_per_sec_bytes: GaugeVec<U64>,
|
||||||
notifications_total: CounterVec<U64>,
|
notifications_total: CounterVec<U64>,
|
||||||
@@ -822,6 +833,10 @@ impl Metrics {
|
|||||||
is_major_syncing: register(Gauge::new(
|
is_major_syncing: register(Gauge::new(
|
||||||
"sub_libp2p_is_major_syncing", "Whether the node is performing a major sync or not.",
|
"sub_libp2p_is_major_syncing", "Whether the node is performing a major sync or not.",
|
||||||
)?, registry)?,
|
)?, registry)?,
|
||||||
|
issued_light_requests: register(Counter::new(
|
||||||
|
"issued_light_requests",
|
||||||
|
"Number of light client requests that our node has issued.",
|
||||||
|
)?, registry)?,
|
||||||
kbuckets_num_nodes: register(Gauge::new(
|
kbuckets_num_nodes: register(Gauge::new(
|
||||||
"sub_libp2p_kbuckets_num_nodes", "Number of nodes in the Kademlia k-buckets"
|
"sub_libp2p_kbuckets_num_nodes", "Number of nodes in the Kademlia k-buckets"
|
||||||
)?, registry)?,
|
)?, registry)?,
|
||||||
@@ -897,7 +912,13 @@ impl<B: BlockT + 'static, H: ExHashT> Future for NetworkWorker<B, H> {
|
|||||||
// Check for new incoming light client requests.
|
// Check for new incoming light client requests.
|
||||||
if let Some(light_client_rqs) = this.light_client_rqs.as_mut() {
|
if let Some(light_client_rqs) = this.light_client_rqs.as_mut() {
|
||||||
while let Poll::Ready(Some(rq)) = light_client_rqs.poll_next_unpin(cx) {
|
while let Poll::Ready(Some(rq)) = light_client_rqs.poll_next_unpin(cx) {
|
||||||
this.network_service.user_protocol_mut().add_light_client_request(rq);
|
// This can error if there are too many queued requests already.
|
||||||
|
if this.network_service.light_client_request(rq).is_err() {
|
||||||
|
log::warn!("Couldn't start light client request: too many pending requests");
|
||||||
|
}
|
||||||
|
if let Some(metrics) = this.metrics.as_ref() {
|
||||||
|
metrics.issued_light_requests.inc();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user