mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-09 20:11:09 +00:00
Network sync refactoring (part 4) (#11412)
* Remove direct dependency of `sc-network` on `sc-network-light` * Move `WarpSyncProvider` trait and surrounding data structures into `sc-network-common` * Move `WarpSyncProvider` trait and surrounding data structures into `sc-network-common` * Create `sync` module in `sc-network-common`, create `ChainSync` trait there (not used yet), move a bunch of associated data structures from `sc-network-sync` * Switch from concrete implementation to `ChainSync` trait from `sc-network-common` * Introduce `OpaqueStateRequest`/`OpaqueStateResponse` to remove generics from `StateSync` trait * Introduce `OpaqueBlockRequest`/`OpaqueBlockResponse`, make `scheme` module of `sc-network-sync` private * Surface `sc-network-sync` into `sc-service` and make `sc-network` not depend on it anymore * Remove now unnecessary dependency from `sc-network` * Replace crate links with just text since dependencies are gone now * Remove `warp_sync` re-export from `sc-network-common` * Update copyright in network-related files * Address review comments about documentation * Apply review suggestion * Rename `extra_requests` module to `metrics` Co-authored-by: Bastian Köcher <info@kchr.de>
This commit is contained in:
Generated
+10
-3
@@ -8429,6 +8429,7 @@ dependencies = [
|
||||
"sc-consensus",
|
||||
"sc-keystore",
|
||||
"sc-network",
|
||||
"sc-network-common",
|
||||
"sc-network-gossip",
|
||||
"sc-network-test",
|
||||
"sc-telemetry",
|
||||
@@ -8553,7 +8554,6 @@ dependencies = [
|
||||
"sp-blockchain",
|
||||
"sp-consensus",
|
||||
"sp-core",
|
||||
"sp-finality-grandpa",
|
||||
"sp-runtime",
|
||||
"sp-test-primitives",
|
||||
"sp-tracing",
|
||||
@@ -8571,12 +8571,17 @@ dependencies = [
|
||||
name = "sc-network-common"
|
||||
version = "0.10.0-dev"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"futures",
|
||||
"libp2p",
|
||||
"parity-scale-codec",
|
||||
"prost-build",
|
||||
"sc-consensus",
|
||||
"sc-peerset",
|
||||
"smallvec",
|
||||
"sp-consensus",
|
||||
"sp-finality-grandpa",
|
||||
"sp-runtime",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -8621,8 +8626,6 @@ dependencies = [
|
||||
name = "sc-network-sync"
|
||||
version = "0.10.0-dev"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"either",
|
||||
"fork-tree",
|
||||
"futures",
|
||||
"libp2p",
|
||||
@@ -8667,6 +8670,8 @@ dependencies = [
|
||||
"sc-consensus",
|
||||
"sc-network",
|
||||
"sc-network-common",
|
||||
"sc-network-light",
|
||||
"sc-network-sync",
|
||||
"sc-service",
|
||||
"sp-blockchain",
|
||||
"sp-consensus",
|
||||
@@ -8849,6 +8854,8 @@ dependencies = [
|
||||
"sc-keystore",
|
||||
"sc-network",
|
||||
"sc-network-common",
|
||||
"sc-network-light",
|
||||
"sc-network-sync",
|
||||
"sc-offchain",
|
||||
"sc-rpc",
|
||||
"sc-rpc-server",
|
||||
|
||||
@@ -28,7 +28,6 @@ use sc_chain_spec::{ChainSpec, GenericChainSpec};
|
||||
use sc_client_api::HeaderBackend;
|
||||
use sc_consensus::BoxJustificationImport;
|
||||
use sc_keystore::LocalKeystore;
|
||||
use sc_network::config::ProtocolConfig;
|
||||
use sc_network_test::{
|
||||
Block, BlockImportAdapter, FullPeerConfig, PassThroughVerifier, Peer, PeersClient,
|
||||
TestNetFactory,
|
||||
@@ -111,6 +110,7 @@ pub(crate) struct PeerData {
|
||||
pub(crate) beefy_link_half: Mutex<Option<BeefyLinkHalf>>,
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub(crate) struct BeefyTestNet {
|
||||
peers: Vec<BeefyPeer>,
|
||||
}
|
||||
@@ -166,17 +166,7 @@ impl TestNetFactory for BeefyTestNet {
|
||||
type BlockImport = PeersClient;
|
||||
type PeerData = PeerData;
|
||||
|
||||
/// Create new test network with peers and given config.
|
||||
fn from_config(_config: &ProtocolConfig) -> Self {
|
||||
BeefyTestNet { peers: Vec::new() }
|
||||
}
|
||||
|
||||
fn make_verifier(
|
||||
&self,
|
||||
_client: PeersClient,
|
||||
_cfg: &ProtocolConfig,
|
||||
_: &PeerData,
|
||||
) -> Self::Verifier {
|
||||
fn make_verifier(&self, _client: PeersClient, _: &PeerData) -> Self::Verifier {
|
||||
PassThroughVerifier::new(false) // use non-instant finality.
|
||||
}
|
||||
|
||||
|
||||
@@ -566,7 +566,6 @@ mod tests {
|
||||
use sc_consensus::BoxJustificationImport;
|
||||
use sc_consensus_slots::{BackoffAuthoringOnFinalizedHeadLagging, SimpleSlotWorker};
|
||||
use sc_keystore::LocalKeystore;
|
||||
use sc_network::config::ProtocolConfig;
|
||||
use sc_network_test::{Block as TestBlock, *};
|
||||
use sp_application_crypto::key_types::AURA;
|
||||
use sp_consensus::{
|
||||
@@ -645,6 +644,7 @@ mod tests {
|
||||
>;
|
||||
type AuraPeer = Peer<(), PeersClient>;
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct AuraTestNet {
|
||||
peers: Vec<AuraPeer>,
|
||||
}
|
||||
@@ -654,17 +654,7 @@ mod tests {
|
||||
type PeerData = ();
|
||||
type BlockImport = PeersClient;
|
||||
|
||||
/// Create new test network with peers and given config.
|
||||
fn from_config(_config: &ProtocolConfig) -> Self {
|
||||
AuraTestNet { peers: Vec::new() }
|
||||
}
|
||||
|
||||
fn make_verifier(
|
||||
&self,
|
||||
client: PeersClient,
|
||||
_cfg: &ProtocolConfig,
|
||||
_peer_data: &(),
|
||||
) -> Self::Verifier {
|
||||
fn make_verifier(&self, client: PeersClient, _peer_data: &()) -> Self::Verifier {
|
||||
let client = client.as_client();
|
||||
let slot_duration = slot_duration(&*client).expect("slot duration available");
|
||||
|
||||
|
||||
@@ -29,7 +29,6 @@ use sc_client_api::{backend::TransactionFor, BlockchainEvents, Finalizer};
|
||||
use sc_consensus::{BoxBlockImport, BoxJustificationImport};
|
||||
use sc_consensus_slots::BackoffAuthoringOnFinalizedHeadLagging;
|
||||
use sc_keystore::LocalKeystore;
|
||||
use sc_network::config::ProtocolConfig;
|
||||
use sc_network_test::{Block as TestBlock, *};
|
||||
use sp_application_crypto::key_types::BABE;
|
||||
use sp_consensus::{AlwaysCanAuthor, DisableProofRecording, NoNetwork as DummyOracle, Proposal};
|
||||
@@ -220,6 +219,7 @@ where
|
||||
|
||||
type BabePeer = Peer<Option<PeerData>, BabeBlockImport>;
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct BabeTestNet {
|
||||
peers: Vec<BabePeer>,
|
||||
}
|
||||
@@ -278,12 +278,6 @@ impl TestNetFactory for BabeTestNet {
|
||||
type PeerData = Option<PeerData>;
|
||||
type BlockImport = BabeBlockImport;
|
||||
|
||||
/// Create new test network with peers and given config.
|
||||
fn from_config(_config: &ProtocolConfig) -> Self {
|
||||
debug!(target: "babe", "Creating test network from config");
|
||||
BabeTestNet { peers: Vec::new() }
|
||||
}
|
||||
|
||||
fn make_block_import(
|
||||
&self,
|
||||
client: PeersClient,
|
||||
@@ -309,12 +303,7 @@ impl TestNetFactory for BabeTestNet {
|
||||
)
|
||||
}
|
||||
|
||||
fn make_verifier(
|
||||
&self,
|
||||
client: PeersClient,
|
||||
_cfg: &ProtocolConfig,
|
||||
maybe_link: &Option<PeerData>,
|
||||
) -> Self::Verifier {
|
||||
fn make_verifier(&self, client: PeersClient, maybe_link: &Option<PeerData>) -> Self::Verifier {
|
||||
use substrate_test_runtime_client::DefaultTestClientBuilderExt;
|
||||
|
||||
let client = client.as_client();
|
||||
|
||||
@@ -36,6 +36,7 @@ sc-consensus = { version = "0.10.0-dev", path = "../consensus/common" }
|
||||
sc-keystore = { version = "4.0.0-dev", path = "../keystore" }
|
||||
sc-network = { version = "0.10.0-dev", path = "../network" }
|
||||
sc-network-gossip = { version = "0.10.0-dev", path = "../network-gossip" }
|
||||
sc-network-common = { version = "0.10.0-dev", path = "../network/common" }
|
||||
sc-telemetry = { version = "4.0.0-dev", path = "../telemetry" }
|
||||
sc-utils = { version = "4.0.0-dev", path = "../utils" }
|
||||
sp-api = { version = "4.0.0-dev", path = "../../primitives/api" }
|
||||
|
||||
@@ -28,7 +28,7 @@ use sc_consensus::{
|
||||
BlockImport, BlockImportParams, BoxJustificationImport, ForkChoiceStrategy, ImportResult,
|
||||
ImportedAux,
|
||||
};
|
||||
use sc_network::config::{ProtocolConfig, Role};
|
||||
use sc_network::config::Role;
|
||||
use sc_network_test::{
|
||||
Block, BlockImportAdapter, FullPeerConfig, Hash, PassThroughVerifier, Peer, PeersClient,
|
||||
PeersFullClient, TestClient, TestNetFactory,
|
||||
@@ -73,6 +73,7 @@ type GrandpaBlockImport = crate::GrandpaBlockImport<
|
||||
LongestChain<substrate_test_runtime_client::Backend, Block>,
|
||||
>;
|
||||
|
||||
#[derive(Default)]
|
||||
struct GrandpaTestNet {
|
||||
peers: Vec<GrandpaPeer>,
|
||||
test_config: TestApi,
|
||||
@@ -110,16 +111,6 @@ impl TestNetFactory for GrandpaTestNet {
|
||||
type PeerData = PeerData;
|
||||
type BlockImport = GrandpaBlockImport;
|
||||
|
||||
/// Create new test network with peers and given config.
|
||||
fn from_config(_config: &ProtocolConfig) -> Self {
|
||||
GrandpaTestNet { peers: Vec::new(), test_config: Default::default() }
|
||||
}
|
||||
|
||||
fn default_config() -> ProtocolConfig {
|
||||
// This is unused.
|
||||
ProtocolConfig::default()
|
||||
}
|
||||
|
||||
fn add_full_peer(&mut self) {
|
||||
self.add_full_peer_with_config(FullPeerConfig {
|
||||
notifications_protocols: vec![grandpa_protocol_name::NAME.into()],
|
||||
@@ -128,12 +119,7 @@ impl TestNetFactory for GrandpaTestNet {
|
||||
})
|
||||
}
|
||||
|
||||
fn make_verifier(
|
||||
&self,
|
||||
_client: PeersClient,
|
||||
_cfg: &ProtocolConfig,
|
||||
_: &PeerData,
|
||||
) -> Self::Verifier {
|
||||
fn make_verifier(&self, _client: PeersClient, _: &PeerData) -> Self::Verifier {
|
||||
PassThroughVerifier::new(false) // use non-instant finality.
|
||||
}
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@ use crate::{
|
||||
BlockNumberOps, GrandpaJustification, SharedAuthoritySet,
|
||||
};
|
||||
use sc_client_api::Backend as ClientBackend;
|
||||
use sc_network::warp_request_handler::{EncodedProof, VerificationResult, WarpSyncProvider};
|
||||
use sc_network_common::sync::warp::{EncodedProof, VerificationResult, WarpSyncProvider};
|
||||
use sp_blockchain::{Backend as BlockchainBackend, HeaderBackend};
|
||||
use sp_finality_grandpa::{AuthorityList, SetId, GRANDPA_ENGINE_ID};
|
||||
use sp_runtime::{
|
||||
|
||||
@@ -51,15 +51,12 @@ sc-block-builder = { version = "0.10.0-dev", path = "../block-builder" }
|
||||
sc-client-api = { version = "4.0.0-dev", path = "../api" }
|
||||
sc-consensus = { version = "0.10.0-dev", path = "../consensus/common" }
|
||||
sc-network-common = { version = "0.10.0-dev", path = "./common" }
|
||||
sc-network-light = { version = "0.10.0-dev", path = "./light" }
|
||||
sc-network-sync = { version = "0.10.0-dev", path = "./sync" }
|
||||
sc-peerset = { version = "4.0.0-dev", path = "../peerset" }
|
||||
sc-utils = { version = "4.0.0-dev", path = "../utils" }
|
||||
sp-arithmetic = { version = "5.0.0", path = "../../primitives/arithmetic" }
|
||||
sp-blockchain = { version = "4.0.0-dev", path = "../../primitives/blockchain" }
|
||||
sp-consensus = { version = "0.10.0-dev", path = "../../primitives/consensus/common" }
|
||||
sp-core = { version = "6.0.0", path = "../../primitives/core" }
|
||||
sp-finality-grandpa = { version = "4.0.0-dev", path = "../../primitives/finality-grandpa" }
|
||||
sp-runtime = { version = "6.0.0", path = "../../primitives/runtime" }
|
||||
|
||||
[dev-dependencies]
|
||||
@@ -67,6 +64,8 @@ assert_matches = "1.3"
|
||||
async-std = "1.11.0"
|
||||
rand = "0.7.2"
|
||||
tempfile = "3.1.0"
|
||||
sc-network-light = { version = "0.10.0-dev", path = "./light" }
|
||||
sc-network-sync = { version = "0.10.0-dev", path = "./sync" }
|
||||
sp-test-primitives = { version = "2.0.0", path = "../../primitives/test-primitives" }
|
||||
sp-tracing = { version = "5.0.0", path = "../../primitives/tracing" }
|
||||
substrate-test-runtime = { version = "2.0.0", path = "../../test-utils/runtime" }
|
||||
|
||||
@@ -17,10 +17,15 @@ targets = ["x86_64-unknown-linux-gnu"]
|
||||
prost-build = "0.10"
|
||||
|
||||
[dependencies]
|
||||
bitflags = "1.3.2"
|
||||
codec = { package = "parity-scale-codec", version = "3.0.0", features = [
|
||||
"derive",
|
||||
] }
|
||||
futures = "0.3.21"
|
||||
libp2p = "0.46.1"
|
||||
smallvec = "1.8.0"
|
||||
sc-consensus = { version = "0.10.0-dev", path = "../../consensus/common" }
|
||||
sc-peerset = { version = "4.0.0-dev", path = "../../peerset" }
|
||||
sp-consensus = { version = "0.10.0-dev", path = "../../../primitives/consensus/common" }
|
||||
sp-finality-grandpa = { version = "4.0.0-dev", path = "../../../primitives/finality-grandpa" }
|
||||
sp-runtime = { version = "6.0.0", path = "../../../primitives/runtime" }
|
||||
|
||||
@@ -21,3 +21,4 @@
|
||||
pub mod config;
|
||||
pub mod message;
|
||||
pub mod request_responses;
|
||||
pub mod sync;
|
||||
|
||||
@@ -0,0 +1,394 @@
|
||||
// This file is part of Substrate.
|
||||
|
||||
// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd.
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
//! Abstract interfaces and data structures related to network sync.
|
||||
|
||||
pub mod message;
|
||||
pub mod metrics;
|
||||
pub mod warp;
|
||||
|
||||
use libp2p::PeerId;
|
||||
use message::{BlockAnnounce, BlockData, BlockRequest, BlockResponse};
|
||||
use sc_consensus::{BlockImportError, BlockImportStatus, IncomingBlock};
|
||||
use sp_consensus::BlockOrigin;
|
||||
use sp_runtime::{
|
||||
traits::{Block as BlockT, NumberFor},
|
||||
Justifications,
|
||||
};
|
||||
use std::{any::Any, fmt, fmt::Formatter, task::Poll};
|
||||
use warp::{EncodedProof, WarpProofRequest, WarpSyncProgress};
|
||||
|
||||
/// The sync status of a peer we are trying to sync with
|
||||
#[derive(Debug)]
|
||||
pub struct PeerInfo<Block: BlockT> {
|
||||
/// Their best block hash.
|
||||
pub best_hash: Block::Hash,
|
||||
/// Their best block number.
|
||||
pub best_number: NumberFor<Block>,
|
||||
}
|
||||
|
||||
/// Reported sync state.
|
||||
#[derive(Clone, Eq, PartialEq, Debug)]
|
||||
pub enum SyncState {
|
||||
/// Initial sync is complete, keep-up sync is active.
|
||||
Idle,
|
||||
/// Actively catching up with the chain.
|
||||
Downloading,
|
||||
}
|
||||
|
||||
/// Reported state download progress.
|
||||
#[derive(Clone, Eq, PartialEq, Debug)]
|
||||
pub struct StateDownloadProgress {
|
||||
/// Estimated download percentage.
|
||||
pub percentage: u32,
|
||||
/// Total state size in bytes downloaded so far.
|
||||
pub size: u64,
|
||||
}
|
||||
|
||||
/// Syncing status and statistics.
|
||||
#[derive(Clone)]
|
||||
pub struct SyncStatus<Block: BlockT> {
|
||||
/// Current global sync state.
|
||||
pub state: SyncState,
|
||||
/// Target sync block number.
|
||||
pub best_seen_block: Option<NumberFor<Block>>,
|
||||
/// Number of peers participating in syncing.
|
||||
pub num_peers: u32,
|
||||
/// Number of blocks queued for import
|
||||
pub queued_blocks: u32,
|
||||
/// State sync status in progress, if any.
|
||||
pub state_sync: Option<StateDownloadProgress>,
|
||||
/// Warp sync in progress, if any.
|
||||
pub warp_sync: Option<WarpSyncProgress<Block>>,
|
||||
}
|
||||
|
||||
/// A peer did not behave as expected and should be reported.
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct BadPeer(pub PeerId, pub sc_peerset::ReputationChange);
|
||||
|
||||
impl fmt::Display for BadPeer {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "Bad peer {}; Reputation change: {:?}", self.0, self.1)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::error::Error for BadPeer {}
|
||||
|
||||
/// Result of [`ChainSync::on_block_data`].
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub enum OnBlockData<Block: BlockT> {
|
||||
/// The block should be imported.
|
||||
Import(BlockOrigin, Vec<IncomingBlock<Block>>),
|
||||
/// A new block request needs to be made to the given peer.
|
||||
Request(PeerId, BlockRequest<Block>),
|
||||
}
|
||||
|
||||
/// Result of [`ChainSync::on_block_justification`].
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub enum OnBlockJustification<Block: BlockT> {
|
||||
/// The justification needs no further handling.
|
||||
Nothing,
|
||||
/// The justification should be imported.
|
||||
Import {
|
||||
peer: PeerId,
|
||||
hash: Block::Hash,
|
||||
number: NumberFor<Block>,
|
||||
justifications: Justifications,
|
||||
},
|
||||
}
|
||||
|
||||
/// Result of [`ChainSync::on_state_data`].
|
||||
#[derive(Debug)]
|
||||
pub enum OnStateData<Block: BlockT> {
|
||||
/// The block and state that should be imported.
|
||||
Import(BlockOrigin, IncomingBlock<Block>),
|
||||
/// A new state request needs to be made to the given peer.
|
||||
Continue,
|
||||
}
|
||||
|
||||
/// Result of [`ChainSync::poll_block_announce_validation`].
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub enum PollBlockAnnounceValidation<H> {
|
||||
/// The announcement failed at validation.
|
||||
///
|
||||
/// The peer reputation should be decreased.
|
||||
Failure {
|
||||
/// Who sent the processed block announcement?
|
||||
who: PeerId,
|
||||
/// Should the peer be disconnected?
|
||||
disconnect: bool,
|
||||
},
|
||||
/// The announcement does not require further handling.
|
||||
Nothing {
|
||||
/// Who sent the processed block announcement?
|
||||
who: PeerId,
|
||||
/// Was this their new best block?
|
||||
is_best: bool,
|
||||
/// The announcement.
|
||||
announce: BlockAnnounce<H>,
|
||||
},
|
||||
/// The announcement header should be imported.
|
||||
ImportHeader {
|
||||
/// Who sent the processed block announcement?
|
||||
who: PeerId,
|
||||
/// Was this their new best block?
|
||||
is_best: bool,
|
||||
/// The announcement.
|
||||
announce: BlockAnnounce<H>,
|
||||
},
|
||||
/// The block announcement should be skipped.
|
||||
Skip,
|
||||
}
|
||||
|
||||
/// Operation mode.
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub enum SyncMode {
|
||||
// Sync headers only
|
||||
Light,
|
||||
// Sync headers and block bodies
|
||||
Full,
|
||||
// Sync headers and the last finalied state
|
||||
LightState { storage_chain_mode: bool, skip_proofs: bool },
|
||||
// Warp sync mode.
|
||||
Warp,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Metrics {
|
||||
pub queued_blocks: u32,
|
||||
pub fork_targets: u32,
|
||||
pub justifications: metrics::Metrics,
|
||||
}
|
||||
|
||||
/// Wrapper for implementation-specific state request.
|
||||
///
|
||||
/// NOTE: Implementation must be able to encode and decode it for network purposes.
|
||||
pub struct OpaqueStateRequest(pub Box<dyn Any + Send>);
|
||||
|
||||
impl fmt::Debug for OpaqueStateRequest {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("OpaqueStateRequest").finish()
|
||||
}
|
||||
}
|
||||
|
||||
/// Wrapper for implementation-specific state response.
|
||||
///
|
||||
/// NOTE: Implementation must be able to encode and decode it for network purposes.
|
||||
pub struct OpaqueStateResponse(pub Box<dyn Any + Send>);
|
||||
|
||||
impl fmt::Debug for OpaqueStateResponse {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("OpaqueStateResponse").finish()
|
||||
}
|
||||
}
|
||||
|
||||
/// Wrapper for implementation-specific block request.
|
||||
///
|
||||
/// NOTE: Implementation must be able to encode and decode it for network purposes.
|
||||
pub struct OpaqueBlockRequest(pub Box<dyn Any + Send>);
|
||||
|
||||
impl fmt::Debug for OpaqueBlockRequest {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("OpaqueBlockRequest").finish()
|
||||
}
|
||||
}
|
||||
|
||||
/// Wrapper for implementation-specific block response.
|
||||
///
|
||||
/// NOTE: Implementation must be able to encode and decode it for network purposes.
|
||||
pub struct OpaqueBlockResponse(pub Box<dyn Any + Send>);
|
||||
|
||||
impl fmt::Debug for OpaqueBlockResponse {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("OpaqueBlockResponse").finish()
|
||||
}
|
||||
}
|
||||
|
||||
/// Something that represents the syncing strategy to download past and future blocks of the chain.
|
||||
pub trait ChainSync<Block: BlockT>: Send {
|
||||
/// Returns the state of the sync of the given peer.
|
||||
///
|
||||
/// Returns `None` if the peer is unknown.
|
||||
fn peer_info(&self, who: &PeerId) -> Option<PeerInfo<Block>>;
|
||||
|
||||
/// Returns the current sync status.
|
||||
fn status(&self) -> SyncStatus<Block>;
|
||||
|
||||
/// Number of active forks requests. This includes
|
||||
/// requests that are pending or could be issued right away.
|
||||
fn num_sync_requests(&self) -> usize;
|
||||
|
||||
/// Number of downloaded blocks.
|
||||
fn num_downloaded_blocks(&self) -> usize;
|
||||
|
||||
/// Returns the current number of peers stored within this state machine.
|
||||
fn num_peers(&self) -> usize;
|
||||
|
||||
/// Handle a new connected peer.
|
||||
///
|
||||
/// Call this method whenever we connect to a new peer.
|
||||
fn new_peer(
|
||||
&mut self,
|
||||
who: PeerId,
|
||||
best_hash: Block::Hash,
|
||||
best_number: NumberFor<Block>,
|
||||
) -> Result<Option<BlockRequest<Block>>, BadPeer>;
|
||||
|
||||
/// Signal that a new best block has been imported.
|
||||
fn update_chain_info(&mut self, best_hash: &Block::Hash, best_number: NumberFor<Block>);
|
||||
|
||||
/// Schedule a justification request for the given block.
|
||||
fn request_justification(&mut self, hash: &Block::Hash, number: NumberFor<Block>);
|
||||
|
||||
/// Clear all pending justification requests.
|
||||
fn clear_justification_requests(&mut self);
|
||||
|
||||
/// Request syncing for the given block from given set of peers.
|
||||
fn set_sync_fork_request(
|
||||
&mut self,
|
||||
peers: Vec<PeerId>,
|
||||
hash: &Block::Hash,
|
||||
number: NumberFor<Block>,
|
||||
);
|
||||
|
||||
/// Get an iterator over all scheduled justification requests.
|
||||
fn justification_requests(
|
||||
&mut self,
|
||||
) -> Box<dyn Iterator<Item = (PeerId, BlockRequest<Block>)> + '_>;
|
||||
|
||||
/// Get an iterator over all block requests of all peers.
|
||||
fn block_requests(&mut self) -> Box<dyn Iterator<Item = (&PeerId, BlockRequest<Block>)> + '_>;
|
||||
|
||||
/// Get a state request, if any.
|
||||
fn state_request(&mut self) -> Option<(PeerId, OpaqueStateRequest)>;
|
||||
|
||||
/// Get a warp sync request, if any.
|
||||
fn warp_sync_request(&mut self) -> Option<(PeerId, WarpProofRequest<Block>)>;
|
||||
|
||||
/// Handle a response from the remote to a block request that we made.
|
||||
///
|
||||
/// `request` must be the original request that triggered `response`.
|
||||
/// or `None` if data comes from the block announcement.
|
||||
///
|
||||
/// If this corresponds to a valid block, this outputs the block that
|
||||
/// must be imported in the import queue.
|
||||
fn on_block_data(
|
||||
&mut self,
|
||||
who: &PeerId,
|
||||
request: Option<BlockRequest<Block>>,
|
||||
response: BlockResponse<Block>,
|
||||
) -> Result<OnBlockData<Block>, BadPeer>;
|
||||
|
||||
/// Handle a response from the remote to a state request that we made.
|
||||
fn on_state_data(
|
||||
&mut self,
|
||||
who: &PeerId,
|
||||
response: OpaqueStateResponse,
|
||||
) -> Result<OnStateData<Block>, BadPeer>;
|
||||
|
||||
/// Handle a response from the remote to a warp proof request that we made.
|
||||
fn on_warp_sync_data(&mut self, who: &PeerId, response: EncodedProof) -> Result<(), BadPeer>;
|
||||
|
||||
/// Handle a response from the remote to a justification request that we made.
|
||||
///
|
||||
/// `request` must be the original request that triggered `response`.
|
||||
fn on_block_justification(
|
||||
&mut self,
|
||||
who: PeerId,
|
||||
response: BlockResponse<Block>,
|
||||
) -> Result<OnBlockJustification<Block>, BadPeer>;
|
||||
|
||||
/// A batch of blocks have been processed, with or without errors.
|
||||
///
|
||||
/// Call this when a batch of blocks have been processed by the import
|
||||
/// queue, with or without errors.
|
||||
fn on_blocks_processed(
|
||||
&mut self,
|
||||
imported: usize,
|
||||
count: usize,
|
||||
results: Vec<(Result<BlockImportStatus<NumberFor<Block>>, BlockImportError>, Block::Hash)>,
|
||||
) -> Box<dyn Iterator<Item = Result<(PeerId, BlockRequest<Block>), BadPeer>>>;
|
||||
|
||||
/// Call this when a justification has been processed by the import queue,
|
||||
/// with or without errors.
|
||||
fn on_justification_import(
|
||||
&mut self,
|
||||
hash: Block::Hash,
|
||||
number: NumberFor<Block>,
|
||||
success: bool,
|
||||
);
|
||||
|
||||
/// Notify about finalization of the given block.
|
||||
fn on_block_finalized(&mut self, hash: &Block::Hash, number: NumberFor<Block>);
|
||||
|
||||
/// Push a block announce validation.
|
||||
///
|
||||
/// It is required that [`ChainSync::poll_block_announce_validation`] is called
|
||||
/// to check for finished block announce validations.
|
||||
fn push_block_announce_validation(
|
||||
&mut self,
|
||||
who: PeerId,
|
||||
hash: Block::Hash,
|
||||
announce: BlockAnnounce<Block::Header>,
|
||||
is_best: bool,
|
||||
);
|
||||
|
||||
/// Poll block announce validation.
|
||||
///
|
||||
/// Block announce validations can be pushed by using
|
||||
/// [`ChainSync::push_block_announce_validation`].
|
||||
///
|
||||
/// This should be polled until it returns [`Poll::Pending`].
|
||||
///
|
||||
/// If [`PollBlockAnnounceValidation::ImportHeader`] is returned, then the caller MUST try to
|
||||
/// import passed header (call `on_block_data`). The network request isn't sent in this case.
|
||||
fn poll_block_announce_validation(
|
||||
&mut self,
|
||||
cx: &mut std::task::Context,
|
||||
) -> Poll<PollBlockAnnounceValidation<Block::Header>>;
|
||||
|
||||
/// Call when a peer has disconnected.
|
||||
/// Canceled obsolete block request may result in some blocks being ready for
|
||||
/// import, so this functions checks for such blocks and returns them.
|
||||
fn peer_disconnected(&mut self, who: &PeerId) -> Option<OnBlockData<Block>>;
|
||||
|
||||
/// Return some key metrics.
|
||||
fn metrics(&self) -> Metrics;
|
||||
|
||||
/// Create implementation-specific block request.
|
||||
fn create_opaque_block_request(&self, request: &BlockRequest<Block>) -> OpaqueBlockRequest;
|
||||
|
||||
/// Encode implementation-specific block request.
|
||||
fn encode_block_request(&self, request: &OpaqueBlockRequest) -> Result<Vec<u8>, String>;
|
||||
|
||||
/// Decode implementation-specific block response.
|
||||
fn decode_block_response(&self, response: &[u8]) -> Result<OpaqueBlockResponse, String>;
|
||||
|
||||
/// Access blocks from implementation-specific block response.
|
||||
fn block_response_into_blocks(
|
||||
&self,
|
||||
request: &BlockRequest<Block>,
|
||||
response: OpaqueBlockResponse,
|
||||
) -> Result<Vec<BlockData<Block>>, String>;
|
||||
|
||||
/// Encode implementation-specific state request.
|
||||
fn encode_state_request(&self, request: &OpaqueStateRequest) -> Result<Vec<u8>, String>;
|
||||
|
||||
/// Decode implementation-specific state response.
|
||||
fn decode_state_response(&self, response: &[u8]) -> Result<OpaqueStateResponse, String>;
|
||||
}
|
||||
+1
-1
@@ -124,8 +124,8 @@ impl<H: HeaderT> BlockAnnounce<H> {
|
||||
/// Generic types.
|
||||
pub mod generic {
|
||||
use super::{BlockAttributes, BlockState, Direction};
|
||||
use crate::message::RequestId;
|
||||
use codec::{Decode, Encode, Input, Output};
|
||||
use sc_network_common::message::RequestId;
|
||||
use sp_runtime::{EncodedJustification, Justifications};
|
||||
|
||||
/// Block data sent in the response.
|
||||
@@ -0,0 +1,25 @@
|
||||
// This file is part of Substrate.
|
||||
|
||||
// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd.
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Metrics {
|
||||
pub pending_requests: u32,
|
||||
pub active_requests: u32,
|
||||
pub importing_requests: u32,
|
||||
pub failed_requests: u32,
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
// Copyright 2022 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Substrate.
|
||||
|
||||
// Substrate is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Substrate is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Substrate. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
use codec::{Decode, Encode};
|
||||
pub use sp_finality_grandpa::{AuthorityList, SetId};
|
||||
use sp_runtime::traits::{Block as BlockT, NumberFor};
|
||||
use std::fmt;
|
||||
|
||||
/// Scale-encoded warp sync proof response.
|
||||
pub struct EncodedProof(pub Vec<u8>);
|
||||
|
||||
/// Warp sync request
|
||||
#[derive(Encode, Decode, Debug)]
|
||||
pub struct WarpProofRequest<B: BlockT> {
|
||||
/// Start collecting proofs from this block.
|
||||
pub begin: B::Hash,
|
||||
}
|
||||
|
||||
/// Proof verification result.
|
||||
pub enum VerificationResult<Block: BlockT> {
|
||||
/// Proof is valid, but the target was not reached.
|
||||
Partial(SetId, AuthorityList, Block::Hash),
|
||||
/// Target finality is proved.
|
||||
Complete(SetId, AuthorityList, Block::Header),
|
||||
}
|
||||
|
||||
/// Warp sync backend. Handles retrieveing and verifying warp sync proofs.
|
||||
pub trait WarpSyncProvider<Block: BlockT>: Send + Sync {
|
||||
/// Generate proof starting at given block hash. The proof is accumulated until maximum proof
|
||||
/// size is reached.
|
||||
fn generate(
|
||||
&self,
|
||||
start: Block::Hash,
|
||||
) -> Result<EncodedProof, Box<dyn std::error::Error + Send + Sync>>;
|
||||
/// Verify warp proof against current set of authorities.
|
||||
fn verify(
|
||||
&self,
|
||||
proof: &EncodedProof,
|
||||
set_id: SetId,
|
||||
authorities: AuthorityList,
|
||||
) -> Result<VerificationResult<Block>, Box<dyn std::error::Error + Send + Sync>>;
|
||||
/// Get current list of authorities. This is supposed to be genesis authorities when starting
|
||||
/// sync.
|
||||
fn current_authorities(&self) -> AuthorityList;
|
||||
}
|
||||
|
||||
/// Reported warp sync phase.
|
||||
#[derive(Clone, Eq, PartialEq, Debug)]
|
||||
pub enum WarpSyncPhase<Block: BlockT> {
|
||||
/// Waiting for peers to connect.
|
||||
AwaitingPeers,
|
||||
/// Downloading and verifying grandpa warp proofs.
|
||||
DownloadingWarpProofs,
|
||||
/// Downloading state data.
|
||||
DownloadingState,
|
||||
/// Importing state.
|
||||
ImportingState,
|
||||
/// Downloading block history.
|
||||
DownloadingBlocks(NumberFor<Block>),
|
||||
}
|
||||
|
||||
impl<Block: BlockT> fmt::Display for WarpSyncPhase<Block> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
Self::AwaitingPeers => write!(f, "Waiting for peers"),
|
||||
Self::DownloadingWarpProofs => write!(f, "Downloading finality proofs"),
|
||||
Self::DownloadingState => write!(f, "Downloading state"),
|
||||
Self::ImportingState => write!(f, "Importing state"),
|
||||
Self::DownloadingBlocks(n) => write!(f, "Downloading block history (#{})", n),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Reported warp sync progress.
|
||||
#[derive(Clone, Eq, PartialEq, Debug)]
|
||||
pub struct WarpSyncProgress<Block: BlockT> {
|
||||
/// Estimated download percentage.
|
||||
pub phase: WarpSyncPhase<Block>,
|
||||
/// Total bytes downloaded so far.
|
||||
pub total_bytes: u64,
|
||||
}
|
||||
@@ -38,7 +38,7 @@ use libp2p::{
|
||||
NetworkBehaviour,
|
||||
};
|
||||
use log::debug;
|
||||
use prost::Message;
|
||||
|
||||
use sc_client_api::{BlockBackend, ProofProvider};
|
||||
use sc_consensus::import_queue::{IncomingBlock, Origin};
|
||||
use sc_network_common::{config::ProtocolId, request_responses::ProtocolConfig};
|
||||
@@ -382,42 +382,44 @@ where
|
||||
.events
|
||||
.push_back(BehaviourOut::JustificationImport(origin, hash, nb, justification)),
|
||||
CustomMessageOutcome::BlockRequest { target, request, pending_response } => {
|
||||
let mut buf = Vec::with_capacity(request.encoded_len());
|
||||
if let Err(err) = request.encode(&mut buf) {
|
||||
log::warn!(
|
||||
target: "sync",
|
||||
"Failed to encode block request {:?}: {:?}",
|
||||
request, err
|
||||
);
|
||||
return
|
||||
match self.substrate.encode_block_request(&request) {
|
||||
Ok(data) => {
|
||||
self.request_responses.send_request(
|
||||
&target,
|
||||
&self.block_request_protocol_name,
|
||||
data,
|
||||
pending_response,
|
||||
IfDisconnected::ImmediateError,
|
||||
);
|
||||
},
|
||||
Err(err) => {
|
||||
log::warn!(
|
||||
target: "sync",
|
||||
"Failed to encode block request {:?}: {:?}",
|
||||
request, err
|
||||
);
|
||||
},
|
||||
}
|
||||
|
||||
self.request_responses.send_request(
|
||||
&target,
|
||||
&self.block_request_protocol_name,
|
||||
buf,
|
||||
pending_response,
|
||||
IfDisconnected::ImmediateError,
|
||||
);
|
||||
},
|
||||
CustomMessageOutcome::StateRequest { target, request, pending_response } => {
|
||||
let mut buf = Vec::with_capacity(request.encoded_len());
|
||||
if let Err(err) = request.encode(&mut buf) {
|
||||
log::warn!(
|
||||
target: "sync",
|
||||
"Failed to encode state request {:?}: {:?}",
|
||||
request, err
|
||||
);
|
||||
return
|
||||
match self.substrate.encode_state_request(&request) {
|
||||
Ok(data) => {
|
||||
self.request_responses.send_request(
|
||||
&target,
|
||||
&self.state_request_protocol_name,
|
||||
data,
|
||||
pending_response,
|
||||
IfDisconnected::ImmediateError,
|
||||
);
|
||||
},
|
||||
Err(err) => {
|
||||
log::warn!(
|
||||
target: "sync",
|
||||
"Failed to encode state request {:?}: {:?}",
|
||||
request, err
|
||||
);
|
||||
},
|
||||
}
|
||||
|
||||
self.request_responses.send_request(
|
||||
&target,
|
||||
&self.state_request_protocol_name,
|
||||
buf,
|
||||
pending_response,
|
||||
IfDisconnected::ImmediateError,
|
||||
);
|
||||
},
|
||||
CustomMessageOutcome::WarpSyncRequest { target, request, pending_response } =>
|
||||
match &self.warp_sync_protocol_name {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2021 Parity Technologies (UK) Ltd.
|
||||
// Copyright 2022 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Substrate.
|
||||
|
||||
// Substrate is free software: you can redistribute it and/or modify
|
||||
@@ -118,8 +118,7 @@ where
|
||||
|
||||
fn upgrade_outbound(self, mut socket: TSocket, _info: Self::Info) -> Self::Future {
|
||||
Box::pin(async move {
|
||||
let mut data = Vec::with_capacity(self.encoded_len());
|
||||
self.encode(&mut data)?;
|
||||
let data = self.encode_to_vec();
|
||||
upgrade::write_length_prefixed(&mut socket, data).await
|
||||
})
|
||||
}
|
||||
|
||||
@@ -26,16 +26,11 @@ pub use sc_network_common::{
|
||||
request_responses::{
|
||||
IncomingRequest, OutgoingResponse, ProtocolConfig as RequestResponseConfig,
|
||||
},
|
||||
sync::warp::WarpSyncProvider,
|
||||
};
|
||||
pub use sc_network_sync::warp_request_handler::WarpSyncProvider;
|
||||
|
||||
pub use libp2p::{build_multiaddr, core::PublicKey, identity};
|
||||
|
||||
// Note: this re-export shouldn't be part of the public API of the crate and will be removed in
|
||||
// the future.
|
||||
#[doc(hidden)]
|
||||
pub use crate::protocol::ProtocolConfig;
|
||||
|
||||
use crate::ExHashT;
|
||||
|
||||
use core::{fmt, iter};
|
||||
@@ -46,7 +41,7 @@ use libp2p::{
|
||||
};
|
||||
use prometheus_endpoint::Registry;
|
||||
use sc_consensus::ImportQueue;
|
||||
use sp_consensus::block_validation::BlockAnnounceValidator;
|
||||
use sc_network_common::sync::ChainSync;
|
||||
use sp_runtime::traits::Block as BlockT;
|
||||
use std::{
|
||||
borrow::Cow,
|
||||
@@ -101,8 +96,14 @@ where
|
||||
/// valid.
|
||||
pub import_queue: Box<dyn ImportQueue<B>>,
|
||||
|
||||
/// Type to check incoming block announcements.
|
||||
pub block_announce_validator: Box<dyn BlockAnnounceValidator<B> + Send>,
|
||||
/// Factory function that creates a new instance of chain sync.
|
||||
pub create_chain_sync: Box<
|
||||
dyn FnOnce(
|
||||
sc_network_common::sync::SyncMode,
|
||||
Arc<Client>,
|
||||
Option<Arc<dyn WarpSyncProvider<B>>>,
|
||||
) -> crate::error::Result<Box<dyn ChainSync<B>>>,
|
||||
>,
|
||||
|
||||
/// Registry for recording prometheus metrics to.
|
||||
pub metrics_registry: Option<Registry>,
|
||||
@@ -114,26 +115,26 @@ where
|
||||
/// block requests, if enabled.
|
||||
///
|
||||
/// Can be constructed either via
|
||||
/// [`sc_network_sync::block_request_handler::generate_protocol_config`] allowing outgoing but
|
||||
/// not incoming requests, or constructed via [`sc_network_sync::block_request_handler::
|
||||
/// BlockRequestHandler::new`] allowing both outgoing and incoming requests.
|
||||
/// `sc_network_sync::block_request_handler::generate_protocol_config` allowing outgoing but
|
||||
/// not incoming requests, or constructed via `sc_network_sync::block_request_handler::
|
||||
/// BlockRequestHandler::new` allowing both outgoing and incoming requests.
|
||||
pub block_request_protocol_config: RequestResponseConfig,
|
||||
|
||||
/// Request response configuration for the light client request protocol.
|
||||
///
|
||||
/// Can be constructed either via
|
||||
/// [`sc_network_light::light_client_requests::generate_protocol_config`] allowing outgoing but
|
||||
/// `sc_network_light::light_client_requests::generate_protocol_config` allowing outgoing but
|
||||
/// not incoming requests, or constructed via
|
||||
/// [`sc_network_light::light_client_requests::handler::LightClientRequestHandler::new`]
|
||||
/// `sc_network_light::light_client_requests::handler::LightClientRequestHandler::new`
|
||||
/// allowing both outgoing and incoming requests.
|
||||
pub light_client_request_protocol_config: RequestResponseConfig,
|
||||
|
||||
/// Request response configuration for the state request protocol.
|
||||
///
|
||||
/// Can be constructed either via
|
||||
/// [`sc_network_sync::block_request_handler::generate_protocol_config`] allowing outgoing but
|
||||
/// `sc_network_sync::state_request_handler::generate_protocol_config` allowing outgoing but
|
||||
/// not incoming requests, or constructed via
|
||||
/// [`crate::state_request_handler::StateRequestHandler::new`] allowing
|
||||
/// `sc_network_sync::state_request_handler::StateRequestHandler::new` allowing
|
||||
/// both outgoing and incoming requests.
|
||||
pub state_request_protocol_config: RequestResponseConfig,
|
||||
|
||||
|
||||
@@ -266,13 +266,9 @@ pub use protocol::{
|
||||
event::{DhtEvent, Event, ObservedRole},
|
||||
PeerInfo,
|
||||
};
|
||||
pub use sc_network_light::light_client_requests;
|
||||
pub use sc_network_sync::{
|
||||
block_request_handler,
|
||||
state::StateDownloadProgress,
|
||||
state_request_handler,
|
||||
pub use sc_network_common::sync::{
|
||||
warp::{WarpSyncPhase, WarpSyncProgress},
|
||||
warp_request_handler, SyncState,
|
||||
StateDownloadProgress, SyncState,
|
||||
};
|
||||
pub use service::{
|
||||
DecodingError, IfDisconnected, KademliaKey, Keypair, NetworkService, NetworkWorker,
|
||||
|
||||
@@ -20,7 +20,6 @@ use crate::{
|
||||
config, error,
|
||||
request_responses::RequestFailure,
|
||||
utils::{interval, LruHashSet},
|
||||
warp_request_handler::{EncodedProof, WarpSyncProvider},
|
||||
};
|
||||
|
||||
use bytes::Bytes;
|
||||
@@ -42,21 +41,23 @@ use message::{
|
||||
};
|
||||
use notifications::{Notifications, NotificationsOut};
|
||||
use prometheus_endpoint::{register, Gauge, GaugeVec, Opts, PrometheusError, Registry, U64};
|
||||
use prost::Message as _;
|
||||
use sc_client_api::{BlockBackend, HeaderBackend, ProofProvider};
|
||||
use sc_consensus::import_queue::{BlockImportError, BlockImportStatus, IncomingBlock, Origin};
|
||||
use sc_network_common::config::ProtocolId;
|
||||
use sc_network_sync::{
|
||||
message::{
|
||||
BlockAnnounce, BlockAttributes, BlockData, BlockRequest, BlockResponse, BlockState,
|
||||
FromBlock,
|
||||
use sc_network_common::{
|
||||
config::ProtocolId,
|
||||
sync::{
|
||||
message::{
|
||||
BlockAnnounce, BlockAttributes, BlockData, BlockRequest, BlockResponse, BlockState,
|
||||
},
|
||||
warp::{EncodedProof, WarpProofRequest},
|
||||
BadPeer, ChainSync, OnBlockData, OnBlockJustification, OnStateData, OpaqueBlockRequest,
|
||||
OpaqueBlockResponse, OpaqueStateRequest, OpaqueStateResponse, PollBlockAnnounceValidation,
|
||||
SyncStatus,
|
||||
},
|
||||
schema::v1::StateResponse,
|
||||
BadPeer, ChainSync, OnBlockData, OnBlockJustification, OnStateData,
|
||||
PollBlockAnnounceValidation, Status as SyncStatus,
|
||||
};
|
||||
use sp_arithmetic::traits::SaturatedConversion;
|
||||
use sp_consensus::{block_validation::BlockAnnounceValidator, BlockOrigin};
|
||||
use sp_blockchain::HeaderMetadata;
|
||||
use sp_consensus::BlockOrigin;
|
||||
use sp_runtime::{
|
||||
generic::BlockId,
|
||||
traits::{Block as BlockT, CheckedSub, Header as HeaderT, NumberFor, Zero},
|
||||
@@ -79,7 +80,6 @@ pub mod event;
|
||||
pub mod message;
|
||||
|
||||
pub use notifications::{NotificationsSink, NotifsHandlerError, Ready};
|
||||
use sp_blockchain::HeaderMetadata;
|
||||
|
||||
/// Interval at which we perform time based maintenance
|
||||
const TICK_TIMEOUT: time::Duration = time::Duration::from_millis(1100);
|
||||
@@ -167,11 +167,12 @@ pub struct Protocol<B: BlockT, Client> {
|
||||
tick_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,
|
||||
/// Assigned roles.
|
||||
roles: Roles,
|
||||
genesis_hash: B::Hash,
|
||||
/// State machine that handles the list of in-progress requests. Only full node peers are
|
||||
/// registered.
|
||||
sync: ChainSync<B, Client>,
|
||||
chain_sync: Box<dyn ChainSync<B>>,
|
||||
// All connected peers. Contains both full and light node peers.
|
||||
peers: HashMap<PeerId, Peer<B>>,
|
||||
chain: Arc<Client>,
|
||||
@@ -231,38 +232,6 @@ pub struct PeerInfo<B: BlockT> {
|
||||
pub best_number: <B::Header as HeaderT>::Number,
|
||||
}
|
||||
|
||||
/// Configuration for the Substrate-specific part of the networking layer.
|
||||
#[derive(Clone)]
|
||||
pub struct ProtocolConfig {
|
||||
/// Assigned roles.
|
||||
pub roles: Roles,
|
||||
/// Maximum number of peers to ask the same blocks in parallel.
|
||||
pub max_parallel_downloads: u32,
|
||||
/// Enable state sync.
|
||||
pub sync_mode: config::SyncMode,
|
||||
}
|
||||
|
||||
impl ProtocolConfig {
|
||||
fn sync_mode(&self) -> sc_network_sync::SyncMode {
|
||||
if self.roles.is_light() {
|
||||
sc_network_sync::SyncMode::Light
|
||||
} else {
|
||||
match self.sync_mode {
|
||||
config::SyncMode::Full => sc_network_sync::SyncMode::Full,
|
||||
config::SyncMode::Fast { skip_proofs, storage_chain_mode } =>
|
||||
sc_network_sync::SyncMode::LightState { skip_proofs, storage_chain_mode },
|
||||
config::SyncMode::Warp => sc_network_sync::SyncMode::Warp,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for ProtocolConfig {
|
||||
fn default() -> ProtocolConfig {
|
||||
Self { roles: Roles::FULL, max_parallel_downloads: 5, sync_mode: config::SyncMode::Full }
|
||||
}
|
||||
}
|
||||
|
||||
/// Handshake sent when we open a block announces substream.
|
||||
#[derive(Debug, PartialEq, Eq, Clone, Encode, Decode)]
|
||||
struct BlockAnnouncesHandshake<B: BlockT> {
|
||||
@@ -278,12 +247,12 @@ struct BlockAnnouncesHandshake<B: BlockT> {
|
||||
|
||||
impl<B: BlockT> BlockAnnouncesHandshake<B> {
|
||||
fn build(
|
||||
protocol_config: &ProtocolConfig,
|
||||
roles: Roles,
|
||||
best_number: NumberFor<B>,
|
||||
best_hash: B::Hash,
|
||||
genesis_hash: B::Hash,
|
||||
) -> Self {
|
||||
Self { genesis_hash, roles: protocol_config.roles, best_number, best_hash }
|
||||
Self { genesis_hash, roles, best_number, best_hash }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -300,24 +269,15 @@ where
|
||||
{
|
||||
/// Create a new instance.
|
||||
pub fn new(
|
||||
config: ProtocolConfig,
|
||||
roles: Roles,
|
||||
chain: Arc<Client>,
|
||||
protocol_id: ProtocolId,
|
||||
network_config: &config::NetworkConfiguration,
|
||||
notifications_protocols_handshakes: Vec<Vec<u8>>,
|
||||
block_announce_validator: Box<dyn BlockAnnounceValidator<B> + Send>,
|
||||
metrics_registry: Option<&Registry>,
|
||||
warp_sync_provider: Option<Arc<dyn WarpSyncProvider<B>>>,
|
||||
) -> error::Result<(Protocol<B, Client>, sc_peerset::PeersetHandle, Vec<(PeerId, Multiaddr)>)> {
|
||||
chain_sync: Box<dyn ChainSync<B>>,
|
||||
) -> error::Result<(Self, sc_peerset::PeersetHandle, Vec<(PeerId, Multiaddr)>)> {
|
||||
let info = chain.info();
|
||||
let sync = ChainSync::new(
|
||||
config.sync_mode(),
|
||||
chain.clone(),
|
||||
block_announce_validator,
|
||||
config.max_parallel_downloads,
|
||||
warp_sync_provider,
|
||||
)
|
||||
.map_err(Box::new)?;
|
||||
|
||||
let boot_node_ids = {
|
||||
let mut list = HashSet::new();
|
||||
@@ -405,7 +365,7 @@ where
|
||||
let genesis_hash = info.genesis_hash;
|
||||
|
||||
let block_announces_handshake =
|
||||
BlockAnnouncesHandshake::<B>::build(&config, best_number, best_hash, genesis_hash)
|
||||
BlockAnnouncesHandshake::<B>::build(roles, best_number, best_hash, genesis_hash)
|
||||
.encode();
|
||||
|
||||
let sync_protocol_config = notifications::ProtocolConfig {
|
||||
@@ -438,11 +398,11 @@ where
|
||||
let protocol = Self {
|
||||
tick_timeout: Box::pin(interval(TICK_TIMEOUT)),
|
||||
pending_messages: VecDeque::new(),
|
||||
config,
|
||||
roles,
|
||||
peers: HashMap::new(),
|
||||
chain,
|
||||
genesis_hash: info.genesis_hash,
|
||||
sync,
|
||||
chain_sync,
|
||||
important_peers,
|
||||
default_peers_set_num_full: network_config.default_peers_set_num_full as usize,
|
||||
default_peers_set_num_light: {
|
||||
@@ -510,49 +470,49 @@ where
|
||||
|
||||
/// Current global sync state.
|
||||
pub fn sync_state(&self) -> SyncStatus<B> {
|
||||
self.sync.status()
|
||||
self.chain_sync.status()
|
||||
}
|
||||
|
||||
/// Target sync block number.
|
||||
pub fn best_seen_block(&self) -> Option<NumberFor<B>> {
|
||||
self.sync.status().best_seen_block
|
||||
self.chain_sync.status().best_seen_block
|
||||
}
|
||||
|
||||
/// Number of peers participating in syncing.
|
||||
pub fn num_sync_peers(&self) -> u32 {
|
||||
self.sync.status().num_peers
|
||||
self.chain_sync.status().num_peers
|
||||
}
|
||||
|
||||
/// Number of blocks in the import queue.
|
||||
pub fn num_queued_blocks(&self) -> u32 {
|
||||
self.sync.status().queued_blocks
|
||||
self.chain_sync.status().queued_blocks
|
||||
}
|
||||
|
||||
/// Number of downloaded blocks.
|
||||
pub fn num_downloaded_blocks(&self) -> usize {
|
||||
self.sync.num_downloaded_blocks()
|
||||
self.chain_sync.num_downloaded_blocks()
|
||||
}
|
||||
|
||||
/// Number of active sync requests.
|
||||
pub fn num_sync_requests(&self) -> usize {
|
||||
self.sync.num_sync_requests()
|
||||
self.chain_sync.num_sync_requests()
|
||||
}
|
||||
|
||||
/// Inform sync about new best imported block.
|
||||
pub fn new_best_block_imported(&mut self, hash: B::Hash, number: NumberFor<B>) {
|
||||
debug!(target: "sync", "New best block imported {:?}/#{}", hash, number);
|
||||
|
||||
self.sync.update_chain_info(&hash, number);
|
||||
self.chain_sync.update_chain_info(&hash, number);
|
||||
|
||||
self.behaviour.set_notif_protocol_handshake(
|
||||
HARDCODED_PEERSETS_SYNC,
|
||||
BlockAnnouncesHandshake::<B>::build(&self.config, number, hash, self.genesis_hash)
|
||||
BlockAnnouncesHandshake::<B>::build(self.roles, number, hash, self.genesis_hash)
|
||||
.encode(),
|
||||
);
|
||||
}
|
||||
|
||||
fn update_peer_info(&mut self, who: &PeerId) {
|
||||
if let Some(info) = self.sync.peer_info(who) {
|
||||
if let Some(info) = self.chain_sync.peer_info(who) {
|
||||
if let Some(ref mut peer) = self.peers.get_mut(who) {
|
||||
peer.info.best_hash = info.best_hash;
|
||||
peer.info.best_number = info.best_number;
|
||||
@@ -565,14 +525,6 @@ where
|
||||
self.peers.iter().map(|(id, peer)| (id, &peer.info))
|
||||
}
|
||||
|
||||
fn prepare_block_request(
|
||||
&mut self,
|
||||
who: PeerId,
|
||||
request: BlockRequest<B>,
|
||||
) -> CustomMessageOutcome<B> {
|
||||
prepare_block_request::<B>(&mut self.peers, who, request)
|
||||
}
|
||||
|
||||
/// Called by peer when it is disconnecting.
|
||||
///
|
||||
/// Returns a result if the handshake of this peer was indeed accepted.
|
||||
@@ -584,7 +536,9 @@ where
|
||||
}
|
||||
|
||||
if let Some(_peer_data) = self.peers.remove(&peer) {
|
||||
if let Some(OnBlockData::Import(origin, blocks)) = self.sync.peer_disconnected(&peer) {
|
||||
if let Some(OnBlockData::Import(origin, blocks)) =
|
||||
self.chain_sync.peer_disconnected(&peer)
|
||||
{
|
||||
self.pending_messages
|
||||
.push_back(CustomMessageOutcome::BlockImport(origin, blocks));
|
||||
}
|
||||
@@ -605,62 +559,9 @@ where
|
||||
&mut self,
|
||||
peer_id: PeerId,
|
||||
request: BlockRequest<B>,
|
||||
response: sc_network_sync::schema::v1::BlockResponse,
|
||||
response: OpaqueBlockResponse,
|
||||
) -> CustomMessageOutcome<B> {
|
||||
let blocks = response
|
||||
.blocks
|
||||
.into_iter()
|
||||
.map(|block_data| {
|
||||
Ok(BlockData::<B> {
|
||||
hash: Decode::decode(&mut block_data.hash.as_ref())?,
|
||||
header: if !block_data.header.is_empty() {
|
||||
Some(Decode::decode(&mut block_data.header.as_ref())?)
|
||||
} else {
|
||||
None
|
||||
},
|
||||
body: if request.fields.contains(BlockAttributes::BODY) {
|
||||
Some(
|
||||
block_data
|
||||
.body
|
||||
.iter()
|
||||
.map(|body| Decode::decode(&mut body.as_ref()))
|
||||
.collect::<Result<Vec<_>, _>>()?,
|
||||
)
|
||||
} else {
|
||||
None
|
||||
},
|
||||
indexed_body: if request.fields.contains(BlockAttributes::INDEXED_BODY) {
|
||||
Some(block_data.indexed_body)
|
||||
} else {
|
||||
None
|
||||
},
|
||||
receipt: if !block_data.receipt.is_empty() {
|
||||
Some(block_data.receipt)
|
||||
} else {
|
||||
None
|
||||
},
|
||||
message_queue: if !block_data.message_queue.is_empty() {
|
||||
Some(block_data.message_queue)
|
||||
} else {
|
||||
None
|
||||
},
|
||||
justification: if !block_data.justification.is_empty() {
|
||||
Some(block_data.justification)
|
||||
} else if block_data.is_empty_justification {
|
||||
Some(Vec::new())
|
||||
} else {
|
||||
None
|
||||
},
|
||||
justifications: if !block_data.justifications.is_empty() {
|
||||
Some(DecodeAll::decode_all(&mut block_data.justifications.as_ref())?)
|
||||
} else {
|
||||
None
|
||||
},
|
||||
})
|
||||
})
|
||||
.collect::<Result<Vec<_>, codec::Error>>();
|
||||
|
||||
let blocks = match blocks {
|
||||
let blocks = match self.chain_sync.block_response_into_blocks(&request, response) {
|
||||
Ok(blocks) => blocks,
|
||||
Err(err) => {
|
||||
debug!(target: "sync", "Failed to decode block response from {}: {}", peer_id, err);
|
||||
@@ -690,7 +591,7 @@ where
|
||||
);
|
||||
|
||||
if request.fields == BlockAttributes::JUSTIFICATION {
|
||||
match self.sync.on_block_justification(peer_id, block_response) {
|
||||
match self.chain_sync.on_block_justification(peer_id, block_response) {
|
||||
Ok(OnBlockJustification::Nothing) => CustomMessageOutcome::None,
|
||||
Ok(OnBlockJustification::Import { peer, hash, number, justifications }) =>
|
||||
CustomMessageOutcome::JustificationImport(peer, hash, number, justifications),
|
||||
@@ -701,10 +602,11 @@ where
|
||||
},
|
||||
}
|
||||
} else {
|
||||
match self.sync.on_block_data(&peer_id, Some(request), block_response) {
|
||||
match self.chain_sync.on_block_data(&peer_id, Some(request), block_response) {
|
||||
Ok(OnBlockData::Import(origin, blocks)) =>
|
||||
CustomMessageOutcome::BlockImport(origin, blocks),
|
||||
Ok(OnBlockData::Request(peer, req)) => self.prepare_block_request(peer, req),
|
||||
Ok(OnBlockData::Request(peer, req)) =>
|
||||
prepare_block_request(self.chain_sync.as_ref(), &mut self.peers, peer, req),
|
||||
Err(BadPeer(id, repu)) => {
|
||||
self.behaviour.disconnect_peer(&id, HARDCODED_PEERSETS_SYNC);
|
||||
self.peerset_handle.report_peer(id, repu);
|
||||
@@ -719,9 +621,9 @@ where
|
||||
pub fn on_state_response(
|
||||
&mut self,
|
||||
peer_id: PeerId,
|
||||
response: StateResponse,
|
||||
response: OpaqueStateResponse,
|
||||
) -> CustomMessageOutcome<B> {
|
||||
match self.sync.on_state_data(&peer_id, response) {
|
||||
match self.chain_sync.on_state_data(&peer_id, response) {
|
||||
Ok(OnStateData::Import(origin, block)) =>
|
||||
CustomMessageOutcome::BlockImport(origin, vec![block]),
|
||||
Ok(OnStateData::Continue) => CustomMessageOutcome::None,
|
||||
@@ -738,9 +640,9 @@ where
|
||||
pub fn on_warp_sync_response(
|
||||
&mut self,
|
||||
peer_id: PeerId,
|
||||
response: crate::warp_request_handler::EncodedProof,
|
||||
response: EncodedProof,
|
||||
) -> CustomMessageOutcome<B> {
|
||||
match self.sync.on_warp_sync_data(&peer_id, response) {
|
||||
match self.chain_sync.on_warp_sync_data(&peer_id, response) {
|
||||
Ok(()) => CustomMessageOutcome::None,
|
||||
Err(BadPeer(id, repu)) => {
|
||||
self.behaviour.disconnect_peer(&id, HARDCODED_PEERSETS_SYNC);
|
||||
@@ -798,7 +700,7 @@ where
|
||||
return Err(())
|
||||
}
|
||||
|
||||
if self.config.roles.is_light() {
|
||||
if self.roles.is_light() {
|
||||
// we're not interested in light peers
|
||||
if status.roles.is_light() {
|
||||
debug!(target: "sync", "Peer {} is unable to serve light requests", who);
|
||||
@@ -821,14 +723,15 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
if status.roles.is_full() && self.sync.num_peers() >= self.default_peers_set_num_full {
|
||||
if status.roles.is_full() && self.chain_sync.num_peers() >= self.default_peers_set_num_full
|
||||
{
|
||||
debug!(target: "sync", "Too many full nodes, rejecting {}", who);
|
||||
self.behaviour.disconnect_peer(&who, HARDCODED_PEERSETS_SYNC);
|
||||
return Err(())
|
||||
}
|
||||
|
||||
if status.roles.is_light() &&
|
||||
(self.peers.len() - self.sync.num_peers()) >= self.default_peers_set_num_light
|
||||
(self.peers.len() - self.chain_sync.num_peers()) >= self.default_peers_set_num_light
|
||||
{
|
||||
// Make sure that not all slots are occupied by light clients.
|
||||
debug!(target: "sync", "Too many light nodes, rejecting {}", who);
|
||||
@@ -849,7 +752,7 @@ where
|
||||
};
|
||||
|
||||
let req = if peer.info.roles.is_full() {
|
||||
match self.sync.new_peer(who, peer.info.best_hash, peer.info.best_number) {
|
||||
match self.chain_sync.new_peer(who, peer.info.best_hash, peer.info.best_number) {
|
||||
Ok(req) => req,
|
||||
Err(BadPeer(id, repu)) => {
|
||||
self.behaviour.disconnect_peer(&id, HARDCODED_PEERSETS_SYNC);
|
||||
@@ -868,8 +771,12 @@ where
|
||||
.push_back(CustomMessageOutcome::PeerNewBest(who, status.best_number));
|
||||
|
||||
if let Some(req) = req {
|
||||
let event = self.prepare_block_request(who, req);
|
||||
self.pending_messages.push_back(event);
|
||||
self.pending_messages.push_back(prepare_block_request(
|
||||
self.chain_sync.as_ref(),
|
||||
&mut self.peers,
|
||||
who,
|
||||
req,
|
||||
));
|
||||
}
|
||||
|
||||
Ok(())
|
||||
@@ -953,7 +860,7 @@ where
|
||||
};
|
||||
|
||||
if peer.info.roles.is_full() {
|
||||
self.sync.push_block_announce_validation(who, hash, announce, is_best);
|
||||
self.chain_sync.push_block_announce_validation(who, hash, announce, is_best);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1010,7 +917,7 @@ where
|
||||
|
||||
// to import header from announced block let's construct response to request that normally
|
||||
// would have been sent over network (but it is not in our case)
|
||||
let blocks_to_import = self.sync.on_block_data(
|
||||
let blocks_to_import = self.chain_sync.on_block_data(
|
||||
&who,
|
||||
None,
|
||||
BlockResponse::<B> {
|
||||
@@ -1035,7 +942,8 @@ where
|
||||
match blocks_to_import {
|
||||
Ok(OnBlockData::Import(origin, blocks)) =>
|
||||
CustomMessageOutcome::BlockImport(origin, blocks),
|
||||
Ok(OnBlockData::Request(peer, req)) => self.prepare_block_request(peer, req),
|
||||
Ok(OnBlockData::Request(peer, req)) =>
|
||||
prepare_block_request(self.chain_sync.as_ref(), &mut self.peers, peer, req),
|
||||
Err(BadPeer(id, repu)) => {
|
||||
self.behaviour.disconnect_peer(&id, HARDCODED_PEERSETS_SYNC);
|
||||
self.peerset_handle.report_peer(id, repu);
|
||||
@@ -1047,7 +955,7 @@ where
|
||||
/// Call this when a block has been finalized. The sync layer may have some additional
|
||||
/// requesting to perform.
|
||||
pub fn on_block_finalized(&mut self, hash: B::Hash, header: &B::Header) {
|
||||
self.sync.on_block_finalized(&hash, *header.number())
|
||||
self.chain_sync.on_block_finalized(&hash, *header.number())
|
||||
}
|
||||
|
||||
/// Request a justification for the given block.
|
||||
@@ -1055,12 +963,12 @@ where
|
||||
/// Uses `protocol` to queue a new justification request and tries to dispatch all pending
|
||||
/// requests.
|
||||
pub fn request_justification(&mut self, hash: &B::Hash, number: NumberFor<B>) {
|
||||
self.sync.request_justification(hash, number)
|
||||
self.chain_sync.request_justification(hash, number)
|
||||
}
|
||||
|
||||
/// Clear all pending justification requests.
|
||||
pub fn clear_justification_requests(&mut self) {
|
||||
self.sync.clear_justification_requests();
|
||||
self.chain_sync.clear_justification_requests();
|
||||
}
|
||||
|
||||
/// Request syncing for the given block from given set of peers.
|
||||
@@ -1072,7 +980,7 @@ where
|
||||
hash: &B::Hash,
|
||||
number: NumberFor<B>,
|
||||
) {
|
||||
self.sync.set_sync_fork_request(peers, hash, number)
|
||||
self.chain_sync.set_sync_fork_request(peers, hash, number)
|
||||
}
|
||||
|
||||
/// A batch of blocks have been processed, with or without errors.
|
||||
@@ -1084,11 +992,12 @@ where
|
||||
count: usize,
|
||||
results: Vec<(Result<BlockImportStatus<NumberFor<B>>, BlockImportError>, B::Hash)>,
|
||||
) {
|
||||
let results = self.sync.on_blocks_processed(imported, count, results);
|
||||
let results = self.chain_sync.on_blocks_processed(imported, count, results);
|
||||
for result in results {
|
||||
match result {
|
||||
Ok((id, req)) => {
|
||||
self.pending_messages.push_back(prepare_block_request(
|
||||
self.chain_sync.as_ref(),
|
||||
&mut self.peers,
|
||||
id,
|
||||
req,
|
||||
@@ -1111,7 +1020,7 @@ where
|
||||
number: NumberFor<B>,
|
||||
success: bool,
|
||||
) {
|
||||
self.sync.on_justification_import(hash, number, success);
|
||||
self.chain_sync.on_justification_import(hash, number, success);
|
||||
if !success {
|
||||
info!("💔 Invalid justification provided by {} for #{}", who, hash);
|
||||
self.behaviour.disconnect_peer(&who, HARDCODED_PEERSETS_SYNC);
|
||||
@@ -1228,12 +1137,22 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
/// Encode implementation-specific block request.
|
||||
pub fn encode_block_request(&self, request: &OpaqueBlockRequest) -> Result<Vec<u8>, String> {
|
||||
self.chain_sync.encode_block_request(request)
|
||||
}
|
||||
|
||||
/// Encode implementation-specific state request.
|
||||
pub fn encode_state_request(&self, request: &OpaqueStateRequest) -> Result<Vec<u8>, String> {
|
||||
self.chain_sync.encode_state_request(request)
|
||||
}
|
||||
|
||||
fn report_metrics(&self) {
|
||||
if let Some(metrics) = &self.metrics {
|
||||
let n = u64::try_from(self.peers.len()).unwrap_or(std::u64::MAX);
|
||||
metrics.peers.set(n);
|
||||
|
||||
let m = self.sync.metrics();
|
||||
let m = self.chain_sync.metrics();
|
||||
|
||||
metrics.fork_targets.set(m.fork_targets.into());
|
||||
metrics.queued_blocks.set(m.queued_blocks.into());
|
||||
@@ -1259,6 +1178,7 @@ where
|
||||
}
|
||||
|
||||
fn prepare_block_request<B: BlockT>(
|
||||
chain_sync: &dyn ChainSync<B>,
|
||||
peers: &mut HashMap<PeerId, Peer<B>>,
|
||||
who: PeerId,
|
||||
request: BlockRequest<B>,
|
||||
@@ -1269,19 +1189,7 @@ fn prepare_block_request<B: BlockT>(
|
||||
peer.request = Some((PeerRequest::Block(request.clone()), rx));
|
||||
}
|
||||
|
||||
let request = sc_network_sync::schema::v1::BlockRequest {
|
||||
fields: request.fields.to_be_u32(),
|
||||
from_block: match request.from {
|
||||
FromBlock::Hash(h) =>
|
||||
Some(sc_network_sync::schema::v1::block_request::FromBlock::Hash(h.encode())),
|
||||
FromBlock::Number(n) =>
|
||||
Some(sc_network_sync::schema::v1::block_request::FromBlock::Number(n.encode())),
|
||||
},
|
||||
to_block: request.to.map(|h| h.encode()).unwrap_or_default(),
|
||||
direction: request.direction as i32,
|
||||
max_blocks: request.max.unwrap_or(0),
|
||||
support_multiple_justifications: true,
|
||||
};
|
||||
let request = chain_sync.create_opaque_block_request(&request);
|
||||
|
||||
CustomMessageOutcome::BlockRequest { target: who, request, pending_response: tx }
|
||||
}
|
||||
@@ -1289,7 +1197,7 @@ fn prepare_block_request<B: BlockT>(
|
||||
fn prepare_state_request<B: BlockT>(
|
||||
peers: &mut HashMap<PeerId, Peer<B>>,
|
||||
who: PeerId,
|
||||
request: sc_network_sync::schema::v1::StateRequest,
|
||||
request: OpaqueStateRequest,
|
||||
) -> CustomMessageOutcome<B> {
|
||||
let (tx, rx) = oneshot::channel();
|
||||
|
||||
@@ -1302,7 +1210,7 @@ fn prepare_state_request<B: BlockT>(
|
||||
fn prepare_warp_sync_request<B: BlockT>(
|
||||
peers: &mut HashMap<PeerId, Peer<B>>,
|
||||
who: PeerId,
|
||||
request: crate::warp_request_handler::Request<B>,
|
||||
request: WarpProofRequest<B>,
|
||||
) -> CustomMessageOutcome<B> {
|
||||
let (tx, rx) = oneshot::channel();
|
||||
|
||||
@@ -1346,19 +1254,19 @@ pub enum CustomMessageOutcome<B: BlockT> {
|
||||
/// A new block request must be emitted.
|
||||
BlockRequest {
|
||||
target: PeerId,
|
||||
request: sc_network_sync::schema::v1::BlockRequest,
|
||||
request: OpaqueBlockRequest,
|
||||
pending_response: oneshot::Sender<Result<Vec<u8>, RequestFailure>>,
|
||||
},
|
||||
/// A new storage request must be emitted.
|
||||
StateRequest {
|
||||
target: PeerId,
|
||||
request: sc_network_sync::schema::v1::StateRequest,
|
||||
request: OpaqueStateRequest,
|
||||
pending_response: oneshot::Sender<Result<Vec<u8>, RequestFailure>>,
|
||||
},
|
||||
/// A new warp sync request must be emitted.
|
||||
WarpSyncRequest {
|
||||
target: PeerId,
|
||||
request: crate::warp_request_handler::Request<B>,
|
||||
request: WarpProofRequest<B>,
|
||||
pending_response: oneshot::Sender<Result<Vec<u8>, RequestFailure>>,
|
||||
},
|
||||
/// Peer has a reported a new head of chain.
|
||||
@@ -1455,10 +1363,8 @@ where
|
||||
let (req, _) = peer.request.take().unwrap();
|
||||
match req {
|
||||
PeerRequest::Block(req) => {
|
||||
let protobuf_response =
|
||||
match sc_network_sync::schema::v1::BlockResponse::decode(
|
||||
&resp[..],
|
||||
) {
|
||||
let response =
|
||||
match self.chain_sync.decode_block_response(&resp[..]) {
|
||||
Ok(proto) => proto,
|
||||
Err(e) => {
|
||||
debug!(
|
||||
@@ -1474,13 +1380,11 @@ where
|
||||
},
|
||||
};
|
||||
|
||||
finished_block_requests.push((*id, req, protobuf_response));
|
||||
finished_block_requests.push((*id, req, response));
|
||||
},
|
||||
PeerRequest::State => {
|
||||
let protobuf_response =
|
||||
match sc_network_sync::schema::v1::StateResponse::decode(
|
||||
&resp[..],
|
||||
) {
|
||||
let response =
|
||||
match self.chain_sync.decode_state_response(&resp[..]) {
|
||||
Ok(proto) => proto,
|
||||
Err(e) => {
|
||||
debug!(
|
||||
@@ -1496,7 +1400,7 @@ where
|
||||
},
|
||||
};
|
||||
|
||||
finished_state_requests.push((*id, protobuf_response));
|
||||
finished_state_requests.push((*id, response));
|
||||
},
|
||||
PeerRequest::WarpProof => {
|
||||
finished_warp_sync_requests.push((*id, resp));
|
||||
@@ -1555,12 +1459,12 @@ where
|
||||
}
|
||||
}
|
||||
}
|
||||
for (id, req, protobuf_response) in finished_block_requests {
|
||||
let ev = self.on_block_response(id, req, protobuf_response);
|
||||
for (id, req, response) in finished_block_requests {
|
||||
let ev = self.on_block_response(id, req, response);
|
||||
self.pending_messages.push_back(ev);
|
||||
}
|
||||
for (id, protobuf_response) in finished_state_requests {
|
||||
let ev = self.on_state_response(id, protobuf_response);
|
||||
for (id, response) in finished_state_requests {
|
||||
let ev = self.on_state_response(id, response);
|
||||
self.pending_messages.push_back(ev);
|
||||
}
|
||||
for (id, response) in finished_warp_sync_requests {
|
||||
@@ -1572,25 +1476,32 @@ where
|
||||
self.tick();
|
||||
}
|
||||
|
||||
for (id, request) in self.sync.block_requests() {
|
||||
let event = prepare_block_request(&mut self.peers, *id, request);
|
||||
for (id, request) in self
|
||||
.chain_sync
|
||||
.block_requests()
|
||||
.map(|(peer_id, request)| (*peer_id, request))
|
||||
.collect::<Vec<_>>()
|
||||
{
|
||||
let event =
|
||||
prepare_block_request(self.chain_sync.as_ref(), &mut self.peers, id, request);
|
||||
self.pending_messages.push_back(event);
|
||||
}
|
||||
if let Some((id, request)) = self.sync.state_request() {
|
||||
if let Some((id, request)) = self.chain_sync.state_request() {
|
||||
let event = prepare_state_request(&mut self.peers, id, request);
|
||||
self.pending_messages.push_back(event);
|
||||
}
|
||||
for (id, request) in self.sync.justification_requests() {
|
||||
let event = prepare_block_request(&mut self.peers, id, request);
|
||||
for (id, request) in self.chain_sync.justification_requests().collect::<Vec<_>>() {
|
||||
let event =
|
||||
prepare_block_request(self.chain_sync.as_ref(), &mut self.peers, id, request);
|
||||
self.pending_messages.push_back(event);
|
||||
}
|
||||
if let Some((id, request)) = self.sync.warp_sync_request() {
|
||||
if let Some((id, request)) = self.chain_sync.warp_sync_request() {
|
||||
let event = prepare_warp_sync_request(&mut self.peers, id, request);
|
||||
self.pending_messages.push_back(event);
|
||||
}
|
||||
|
||||
// Check if there is any block announcement validation finished.
|
||||
while let Poll::Ready(result) = self.sync.poll_block_announce_validation(cx) {
|
||||
while let Poll::Ready(result) = self.chain_sync.poll_block_announce_validation(cx) {
|
||||
match self.process_block_announce_validation_result(result) {
|
||||
CustomMessageOutcome::None => {},
|
||||
outcome => self.pending_messages.push_back(outcome),
|
||||
@@ -1771,7 +1682,8 @@ where
|
||||
|
||||
// Make sure that the newly added block announce validation future was
|
||||
// polled once to be registered in the task.
|
||||
if let Poll::Ready(res) = self.sync.poll_block_announce_validation(cx) {
|
||||
if let Poll::Ready(res) = self.chain_sync.poll_block_announce_validation(cx)
|
||||
{
|
||||
self.process_block_announce_validation_result(res)
|
||||
} else {
|
||||
CustomMessageOutcome::None
|
||||
|
||||
@@ -63,10 +63,12 @@ pub mod generic {
|
||||
use bitflags::bitflags;
|
||||
use codec::{Decode, Encode, Input, Output};
|
||||
use sc_client_api::StorageProof;
|
||||
use sc_network_common::message::RequestId;
|
||||
use sc_network_sync::message::{
|
||||
generic::{BlockRequest, BlockResponse},
|
||||
BlockAnnounce,
|
||||
use sc_network_common::{
|
||||
message::RequestId,
|
||||
sync::message::{
|
||||
generic::{BlockRequest, BlockResponse},
|
||||
BlockAnnounce,
|
||||
},
|
||||
};
|
||||
use sp_runtime::ConsensusEngineId;
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
use crate::{
|
||||
behaviour::{self, Behaviour, BehaviourOut},
|
||||
bitswap::Bitswap,
|
||||
config::{parse_str_addr, Params, TransportConfig},
|
||||
config::{self, parse_str_addr, Params, TransportConfig},
|
||||
discovery::DiscoveryConfig,
|
||||
error::Error,
|
||||
network_state::{
|
||||
@@ -60,7 +60,7 @@ use metrics::{Histogram, HistogramVec, MetricSources, Metrics};
|
||||
use parking_lot::Mutex;
|
||||
use sc_client_api::{BlockBackend, ProofProvider};
|
||||
use sc_consensus::{BlockImportError, BlockImportStatus, ImportQueue, Link};
|
||||
use sc_network_sync::{Status as SyncStatus, SyncState};
|
||||
use sc_network_common::sync::{SyncMode, SyncState, SyncStatus};
|
||||
use sc_peerset::PeersetHandle;
|
||||
use sc_utils::mpsc::{tracing_unbounded, TracingUnboundedReceiver, TracingUnboundedSender};
|
||||
use sp_blockchain::{HeaderBackend, HeaderMetadata};
|
||||
@@ -207,13 +207,23 @@ where
|
||||
None => (None, None),
|
||||
};
|
||||
|
||||
let (protocol, peerset_handle, mut known_addresses) = Protocol::new(
|
||||
protocol::ProtocolConfig {
|
||||
roles: From::from(¶ms.role),
|
||||
max_parallel_downloads: params.network_config.max_parallel_downloads,
|
||||
sync_mode: params.network_config.sync_mode.clone(),
|
||||
let chain_sync = (params.create_chain_sync)(
|
||||
if params.role.is_light() {
|
||||
SyncMode::Light
|
||||
} else {
|
||||
match params.network_config.sync_mode {
|
||||
config::SyncMode::Full => SyncMode::Full,
|
||||
config::SyncMode::Fast { skip_proofs, storage_chain_mode } =>
|
||||
SyncMode::LightState { skip_proofs, storage_chain_mode },
|
||||
config::SyncMode::Warp => SyncMode::Warp,
|
||||
}
|
||||
},
|
||||
params.chain.clone(),
|
||||
warp_sync_provider,
|
||||
)?;
|
||||
let (protocol, peerset_handle, mut known_addresses) = Protocol::new(
|
||||
From::from(¶ms.role),
|
||||
params.chain.clone(),
|
||||
params.protocol_id.clone(),
|
||||
¶ms.network_config,
|
||||
iter::once(Vec::new())
|
||||
@@ -222,9 +232,8 @@ where
|
||||
.map(|_| default_notif_handshake_message.clone()),
|
||||
)
|
||||
.collect(),
|
||||
params.block_announce_validator,
|
||||
params.metrics_registry.as_ref(),
|
||||
warp_sync_provider,
|
||||
chain_sync,
|
||||
)?;
|
||||
|
||||
// List of multiaddresses that we know in the network.
|
||||
|
||||
@@ -16,15 +16,17 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
use crate::{
|
||||
config, state_request_handler::StateRequestHandler, Event, NetworkService, NetworkWorker,
|
||||
};
|
||||
use crate::{config, Event, NetworkService, NetworkWorker};
|
||||
|
||||
use futures::prelude::*;
|
||||
use libp2p::PeerId;
|
||||
use sc_network_common::config::ProtocolId;
|
||||
use sc_network_light::light_client_requests::handler::LightClientRequestHandler;
|
||||
use sc_network_sync::block_request_handler::BlockRequestHandler;
|
||||
use sc_network_sync::{
|
||||
block_request_handler::BlockRequestHandler, state_request_handler::StateRequestHandler,
|
||||
ChainSync,
|
||||
};
|
||||
use sp_consensus::block_validation::DefaultBlockAnnounceValidator;
|
||||
use sp_runtime::traits::{Block as BlockT, Header as _};
|
||||
use std::{borrow::Cow, sync::Arc, time::Duration};
|
||||
use substrate_test_runtime_client::{TestClientBuilder, TestClientBuilderExt as _};
|
||||
@@ -109,6 +111,7 @@ fn build_test_full_node(
|
||||
protocol_config
|
||||
};
|
||||
|
||||
let max_parallel_downloads = config.max_parallel_downloads;
|
||||
let worker = NetworkWorker::new(config::Params {
|
||||
role: config::Role::Full,
|
||||
executor: None,
|
||||
@@ -120,8 +123,17 @@ fn build_test_full_node(
|
||||
transaction_pool: Arc::new(crate::config::EmptyTransactionPool),
|
||||
protocol_id,
|
||||
import_queue,
|
||||
block_announce_validator: Box::new(
|
||||
sp_consensus::block_validation::DefaultBlockAnnounceValidator,
|
||||
create_chain_sync: Box::new(
|
||||
move |sync_mode, chain, warp_sync_provider| match ChainSync::new(
|
||||
sync_mode,
|
||||
chain,
|
||||
Box::new(DefaultBlockAnnounceValidator),
|
||||
max_parallel_downloads,
|
||||
warp_sync_provider,
|
||||
) {
|
||||
Ok(chain_sync) => Ok(Box::new(chain_sync)),
|
||||
Err(error) => Err(Box::new(error).into()),
|
||||
},
|
||||
),
|
||||
metrics_registry: None,
|
||||
block_request_protocol_config,
|
||||
|
||||
@@ -17,11 +17,9 @@ targets = ["x86_64-unknown-linux-gnu"]
|
||||
prost-build = "0.10"
|
||||
|
||||
[dependencies]
|
||||
bitflags = "1.3.2"
|
||||
codec = { package = "parity-scale-codec", version = "3.0.0", features = [
|
||||
"derive",
|
||||
] }
|
||||
either = "1.5.3"
|
||||
futures = "0.3.21"
|
||||
libp2p = "0.46.1"
|
||||
log = "0.4.17"
|
||||
|
||||
@@ -17,10 +17,7 @@
|
||||
//! Helper for handling (i.e. answering) block requests from a remote peer via the
|
||||
//! `crate::request_responses::RequestResponsesBehaviour`.
|
||||
|
||||
use crate::{
|
||||
message::BlockAttributes,
|
||||
schema::v1::{block_request::FromBlock, BlockResponse, Direction},
|
||||
};
|
||||
use crate::schema::v1::{block_request::FromBlock, BlockResponse, Direction};
|
||||
use codec::{Decode, Encode};
|
||||
use futures::{
|
||||
channel::{mpsc, oneshot},
|
||||
@@ -34,6 +31,7 @@ use sc_client_api::BlockBackend;
|
||||
use sc_network_common::{
|
||||
config::ProtocolId,
|
||||
request_responses::{IncomingRequest, OutgoingResponse, ProtocolConfig},
|
||||
sync::message::BlockAttributes,
|
||||
};
|
||||
use sp_blockchain::HeaderBackend;
|
||||
use sp_runtime::{
|
||||
|
||||
@@ -16,9 +16,9 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
use crate::message;
|
||||
use libp2p::PeerId;
|
||||
use log::trace;
|
||||
use sc_network_common::sync::message;
|
||||
use sp_runtime::traits::{Block as BlockT, NumberFor, One};
|
||||
use std::{
|
||||
cmp,
|
||||
@@ -245,8 +245,8 @@ impl<B: BlockT> BlockCollection<B> {
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::{BlockCollection, BlockData, BlockRangeState};
|
||||
use crate::message;
|
||||
use libp2p::PeerId;
|
||||
use sc_network_common::sync::message;
|
||||
use sp_core::H256;
|
||||
use sp_runtime::testing::{Block as RawBlock, ExtrinsicWrapper};
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@ use crate::{PeerSync, PeerSyncState};
|
||||
use fork_tree::ForkTree;
|
||||
use libp2p::PeerId;
|
||||
use log::{debug, trace, warn};
|
||||
use sc_network_common::sync::metrics::Metrics;
|
||||
use sp_blockchain::Error as ClientError;
|
||||
use sp_runtime::traits::{Block as BlockT, NumberFor, Zero};
|
||||
use std::{
|
||||
@@ -56,15 +57,6 @@ pub(crate) struct ExtraRequests<B: BlockT> {
|
||||
request_type_name: &'static str,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Metrics {
|
||||
pub pending_requests: u32,
|
||||
pub active_requests: u32,
|
||||
pub importing_requests: u32,
|
||||
pub failed_requests: u32,
|
||||
_priv: (),
|
||||
}
|
||||
|
||||
impl<B: BlockT> ExtraRequests<B> {
|
||||
pub(crate) fn new(request_type_name: &'static str) -> Self {
|
||||
Self {
|
||||
@@ -258,7 +250,6 @@ impl<B: BlockT> ExtraRequests<B> {
|
||||
active_requests: self.active_requests.len().try_into().unwrap_or(std::u32::MAX),
|
||||
failed_requests: self.failed_requests.len().try_into().unwrap_or(std::u32::MAX),
|
||||
importing_requests: self.importing_requests.len().try_into().unwrap_or(std::u32::MAX),
|
||||
_priv: (),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -18,6 +18,6 @@
|
||||
|
||||
//! Include sources generated from protobuf definitions.
|
||||
|
||||
pub mod v1 {
|
||||
pub(crate) mod v1 {
|
||||
include!(concat!(env!("OUT_DIR"), "/api.v1.rs"));
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@ use codec::{Decode, Encode};
|
||||
use log::debug;
|
||||
use sc_client_api::{CompactProof, ProofProvider};
|
||||
use sc_consensus::ImportedState;
|
||||
use sc_network_common::sync::StateDownloadProgress;
|
||||
use smallvec::SmallVec;
|
||||
use sp_core::storage::well_known_keys;
|
||||
use sp_runtime::traits::{Block as BlockT, Header, NumberFor};
|
||||
@@ -42,15 +43,6 @@ pub struct StateSync<B: BlockT, Client> {
|
||||
skip_proof: bool,
|
||||
}
|
||||
|
||||
/// Reported state download progress.
|
||||
#[derive(Clone, Eq, PartialEq, Debug)]
|
||||
pub struct StateDownloadProgress {
|
||||
/// Estimated download percentage.
|
||||
pub percentage: u32,
|
||||
/// Total state size in bytes downloaded so far.
|
||||
pub size: u64,
|
||||
}
|
||||
|
||||
/// Import state chunk result.
|
||||
pub enum ImportResult<B: BlockT> {
|
||||
/// State is complete and ready for import.
|
||||
|
||||
@@ -18,60 +18,25 @@
|
||||
|
||||
//! Warp sync support.
|
||||
|
||||
pub use crate::warp_request_handler::{
|
||||
EncodedProof, Request as WarpProofRequest, VerificationResult, WarpSyncProvider,
|
||||
};
|
||||
use crate::{
|
||||
schema::v1::{StateRequest, StateResponse},
|
||||
state::{ImportResult, StateSync},
|
||||
};
|
||||
use sc_client_api::ProofProvider;
|
||||
use sc_network_common::sync::warp::{
|
||||
EncodedProof, VerificationResult, WarpProofRequest, WarpSyncPhase, WarpSyncProgress,
|
||||
WarpSyncProvider,
|
||||
};
|
||||
use sp_blockchain::HeaderBackend;
|
||||
use sp_finality_grandpa::{AuthorityList, SetId};
|
||||
use sp_runtime::traits::{Block as BlockT, NumberFor, Zero};
|
||||
use std::{fmt, sync::Arc};
|
||||
use std::sync::Arc;
|
||||
|
||||
enum Phase<B: BlockT, Client> {
|
||||
WarpProof { set_id: SetId, authorities: AuthorityList, last_hash: B::Hash },
|
||||
State(StateSync<B, Client>),
|
||||
}
|
||||
|
||||
/// Reported warp sync phase.
|
||||
#[derive(Clone, Eq, PartialEq, Debug)]
|
||||
pub enum WarpSyncPhase<B: BlockT> {
|
||||
/// Waiting for peers to connect.
|
||||
AwaitingPeers,
|
||||
/// Downloading and verifying grandpa warp proofs.
|
||||
DownloadingWarpProofs,
|
||||
/// Downloading state data.
|
||||
DownloadingState,
|
||||
/// Importing state.
|
||||
ImportingState,
|
||||
/// Downloading block history.
|
||||
DownloadingBlocks(NumberFor<B>),
|
||||
}
|
||||
|
||||
impl<B: BlockT> fmt::Display for WarpSyncPhase<B> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
Self::AwaitingPeers => write!(f, "Waiting for peers"),
|
||||
Self::DownloadingWarpProofs => write!(f, "Downloading finality proofs"),
|
||||
Self::DownloadingState => write!(f, "Downloading state"),
|
||||
Self::ImportingState => write!(f, "Importing state"),
|
||||
Self::DownloadingBlocks(n) => write!(f, "Downloading block history (#{})", n),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Reported warp sync progress.
|
||||
#[derive(Clone, Eq, PartialEq, Debug)]
|
||||
pub struct WarpSyncProgress<B: BlockT> {
|
||||
/// Estimated download percentage.
|
||||
pub phase: WarpSyncPhase<B>,
|
||||
/// Total bytes downloaded so far.
|
||||
pub total_bytes: u64,
|
||||
}
|
||||
|
||||
/// Import warp proof result.
|
||||
pub enum WarpProofImportResult {
|
||||
/// Import was successful.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2021 Parity Technologies (UK) Ltd.
|
||||
// Copyright 2022 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Substrate.
|
||||
|
||||
// Substrate is free software: you can redistribute it and/or modify
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
//! Helper for handling (i.e. answering) grandpa warp sync requests from a remote peer.
|
||||
|
||||
use codec::{Decode, Encode};
|
||||
use codec::Decode;
|
||||
use futures::{
|
||||
channel::{mpsc, oneshot},
|
||||
stream::StreamExt,
|
||||
@@ -27,52 +27,13 @@ use sc_network_common::{
|
||||
request_responses::{
|
||||
IncomingRequest, OutgoingResponse, ProtocolConfig as RequestResponseConfig,
|
||||
},
|
||||
sync::warp::{EncodedProof, WarpProofRequest, WarpSyncProvider},
|
||||
};
|
||||
use sp_runtime::traits::Block as BlockT;
|
||||
use std::{sync::Arc, time::Duration};
|
||||
|
||||
pub use sp_finality_grandpa::{AuthorityList, SetId};
|
||||
|
||||
/// Scale-encoded warp sync proof response.
|
||||
pub struct EncodedProof(pub Vec<u8>);
|
||||
|
||||
/// Warp sync request
|
||||
#[derive(Encode, Decode, Debug)]
|
||||
pub struct Request<B: BlockT> {
|
||||
/// Start collecting proofs from this block.
|
||||
pub begin: B::Hash,
|
||||
}
|
||||
|
||||
const MAX_RESPONSE_SIZE: u64 = 16 * 1024 * 1024;
|
||||
|
||||
/// Proof verification result.
|
||||
pub enum VerificationResult<Block: BlockT> {
|
||||
/// Proof is valid, but the target was not reached.
|
||||
Partial(SetId, AuthorityList, Block::Hash),
|
||||
/// Target finality is proved.
|
||||
Complete(SetId, AuthorityList, Block::Header),
|
||||
}
|
||||
|
||||
/// Warp sync backend. Handles retrieveing and verifying warp sync proofs.
|
||||
pub trait WarpSyncProvider<B: BlockT>: Send + Sync {
|
||||
/// Generate proof starting at given block hash. The proof is accumulated until maximum proof
|
||||
/// size is reached.
|
||||
fn generate(
|
||||
&self,
|
||||
start: B::Hash,
|
||||
) -> Result<EncodedProof, Box<dyn std::error::Error + Send + Sync>>;
|
||||
/// Verify warp proof against current set of authorities.
|
||||
fn verify(
|
||||
&self,
|
||||
proof: &EncodedProof,
|
||||
set_id: SetId,
|
||||
authorities: AuthorityList,
|
||||
) -> Result<VerificationResult<B>, Box<dyn std::error::Error + Send + Sync>>;
|
||||
/// Get current list of authorities. This is supposed to be genesis authorities when starting
|
||||
/// sync.
|
||||
fn current_authorities(&self) -> AuthorityList;
|
||||
}
|
||||
|
||||
/// Generates a [`RequestResponseConfig`] for the grandpa warp sync request protocol, refusing
|
||||
/// incoming requests.
|
||||
pub fn generate_request_response_config(protocol_id: ProtocolId) -> RequestResponseConfig {
|
||||
@@ -115,7 +76,7 @@ impl<TBlock: BlockT> RequestHandler<TBlock> {
|
||||
payload: Vec<u8>,
|
||||
pending_response: oneshot::Sender<OutgoingResponse>,
|
||||
) -> Result<(), HandleRequestError> {
|
||||
let request = Request::<TBlock>::decode(&mut &payload[..])?;
|
||||
let request = WarpProofRequest::<TBlock>::decode(&mut &payload[..])?;
|
||||
|
||||
let EncodedProof(proof) = self
|
||||
.backend
|
||||
|
||||
@@ -26,6 +26,8 @@ sc-client-api = { version = "4.0.0-dev", path = "../../api" }
|
||||
sc-consensus = { version = "0.10.0-dev", path = "../../consensus/common" }
|
||||
sc-network = { version = "0.10.0-dev", path = "../" }
|
||||
sc-network-common = { version = "0.10.0-dev", path = "../common" }
|
||||
sc-network-light = { version = "0.10.0-dev", path = "../light" }
|
||||
sc-network-sync = { version = "0.10.0-dev", path = "../sync" }
|
||||
sc-service = { version = "0.10.0-dev", default-features = false, features = ["test-helpers"], path = "../../service" }
|
||||
sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" }
|
||||
sp-consensus = { version = "0.10.0-dev", path = "../../../primitives/consensus/common" }
|
||||
|
||||
@@ -48,16 +48,21 @@ use sc_consensus::{
|
||||
};
|
||||
pub use sc_network::config::EmptyTransactionPool;
|
||||
use sc_network::{
|
||||
block_request_handler::BlockRequestHandler,
|
||||
config::{
|
||||
MultiaddrWithPeerId, NetworkConfiguration, NonDefaultSetConfig, NonReservedPeerMode,
|
||||
ProtocolConfig, Role, SyncMode, TransportConfig,
|
||||
MultiaddrWithPeerId, NetworkConfiguration, NonDefaultSetConfig, NonReservedPeerMode, Role,
|
||||
SyncMode, TransportConfig,
|
||||
},
|
||||
light_client_requests::handler::LightClientRequestHandler,
|
||||
state_request_handler::StateRequestHandler,
|
||||
warp_request_handler, Multiaddr, NetworkService, NetworkWorker,
|
||||
Multiaddr, NetworkService, NetworkWorker,
|
||||
};
|
||||
pub use sc_network_common::config::ProtocolId;
|
||||
use sc_network_common::sync::warp::{
|
||||
AuthorityList, EncodedProof, SetId, VerificationResult, WarpSyncProvider,
|
||||
};
|
||||
use sc_network_light::light_client_requests::handler::LightClientRequestHandler;
|
||||
use sc_network_sync::{
|
||||
block_request_handler::BlockRequestHandler, state_request_handler::StateRequestHandler,
|
||||
warp_request_handler, ChainSync,
|
||||
};
|
||||
use sc_service::client::Client;
|
||||
use sp_blockchain::{
|
||||
well_known_cache_keys::{self, Id as CacheKeyId},
|
||||
@@ -638,27 +643,26 @@ impl<B: BlockT> VerifierAdapter<B> {
|
||||
|
||||
struct TestWarpSyncProvider<B: BlockT>(Arc<dyn HeaderBackend<B>>);
|
||||
|
||||
impl<B: BlockT> warp_request_handler::WarpSyncProvider<B> for TestWarpSyncProvider<B> {
|
||||
impl<B: BlockT> WarpSyncProvider<B> for TestWarpSyncProvider<B> {
|
||||
fn generate(
|
||||
&self,
|
||||
_start: B::Hash,
|
||||
) -> Result<warp_request_handler::EncodedProof, Box<dyn std::error::Error + Send + Sync>> {
|
||||
) -> Result<EncodedProof, Box<dyn std::error::Error + Send + Sync>> {
|
||||
let info = self.0.info();
|
||||
let best_header = self.0.header(BlockId::hash(info.best_hash)).unwrap().unwrap();
|
||||
Ok(warp_request_handler::EncodedProof(best_header.encode()))
|
||||
Ok(EncodedProof(best_header.encode()))
|
||||
}
|
||||
fn verify(
|
||||
&self,
|
||||
proof: &warp_request_handler::EncodedProof,
|
||||
_set_id: warp_request_handler::SetId,
|
||||
_authorities: warp_request_handler::AuthorityList,
|
||||
) -> Result<warp_request_handler::VerificationResult<B>, Box<dyn std::error::Error + Send + Sync>>
|
||||
{
|
||||
let warp_request_handler::EncodedProof(encoded) = proof;
|
||||
proof: &EncodedProof,
|
||||
_set_id: SetId,
|
||||
_authorities: AuthorityList,
|
||||
) -> Result<VerificationResult<B>, Box<dyn std::error::Error + Send + Sync>> {
|
||||
let EncodedProof(encoded) = proof;
|
||||
let header = B::Header::decode(&mut encoded.as_slice()).unwrap();
|
||||
Ok(warp_request_handler::VerificationResult::Complete(0, Default::default(), header))
|
||||
Ok(VerificationResult::Complete(0, Default::default(), header))
|
||||
}
|
||||
fn current_authorities(&self) -> warp_request_handler::AuthorityList {
|
||||
fn current_authorities(&self) -> AuthorityList {
|
||||
Default::default()
|
||||
}
|
||||
}
|
||||
@@ -688,7 +692,7 @@ pub struct FullPeerConfig {
|
||||
pub storage_chain: bool,
|
||||
}
|
||||
|
||||
pub trait TestNetFactory: Sized
|
||||
pub trait TestNetFactory: Default + Sized
|
||||
where
|
||||
<Self::BlockImport as BlockImport<Block>>::Transaction: Send,
|
||||
{
|
||||
@@ -696,14 +700,8 @@ where
|
||||
type BlockImport: BlockImport<Block, Error = ConsensusError> + Clone + Send + Sync + 'static;
|
||||
type PeerData: Default;
|
||||
|
||||
/// These two need to be implemented!
|
||||
fn from_config(config: &ProtocolConfig) -> Self;
|
||||
fn make_verifier(
|
||||
&self,
|
||||
client: PeersClient,
|
||||
config: &ProtocolConfig,
|
||||
peer_data: &Self::PeerData,
|
||||
) -> Self::Verifier;
|
||||
/// This one needs to be implemented!
|
||||
fn make_verifier(&self, client: PeersClient, peer_data: &Self::PeerData) -> Self::Verifier;
|
||||
|
||||
/// Get reference to peer.
|
||||
fn peer(&mut self, i: usize) -> &mut Peer<Self::PeerData, Self::BlockImport>;
|
||||
@@ -723,15 +721,10 @@ where
|
||||
Self::PeerData,
|
||||
);
|
||||
|
||||
fn default_config() -> ProtocolConfig {
|
||||
ProtocolConfig::default()
|
||||
}
|
||||
|
||||
/// Create new test network with this many peers.
|
||||
fn new(n: usize) -> Self {
|
||||
trace!(target: "test_network", "Creating test network");
|
||||
let config = Self::default_config();
|
||||
let mut net = Self::from_config(&config);
|
||||
let mut net = Self::default();
|
||||
|
||||
for i in 0..n {
|
||||
trace!(target: "test_network", "Adding peer {}", i);
|
||||
@@ -767,11 +760,8 @@ where
|
||||
let (block_import, justification_import, data) = self
|
||||
.make_block_import(PeersClient { client: client.clone(), backend: backend.clone() });
|
||||
|
||||
let verifier = self.make_verifier(
|
||||
PeersClient { client: client.clone(), backend: backend.clone() },
|
||||
&Default::default(),
|
||||
&data,
|
||||
);
|
||||
let verifier = self
|
||||
.make_verifier(PeersClient { client: client.clone(), backend: backend.clone() }, &data);
|
||||
let verifier = VerifierAdapter::new(verifier);
|
||||
|
||||
let import_queue = Box::new(BasicQueue::new(
|
||||
@@ -845,6 +835,10 @@ where
|
||||
protocol_config
|
||||
};
|
||||
|
||||
let max_parallel_downloads = network_config.max_parallel_downloads;
|
||||
let block_announce_validator = config
|
||||
.block_announce_validator
|
||||
.unwrap_or_else(|| Box::new(DefaultBlockAnnounceValidator));
|
||||
let network = NetworkWorker::new(sc_network::config::Params {
|
||||
role: if config.is_authority { Role::Authority } else { Role::Full },
|
||||
executor: None,
|
||||
@@ -856,9 +850,18 @@ where
|
||||
transaction_pool: Arc::new(EmptyTransactionPool),
|
||||
protocol_id,
|
||||
import_queue,
|
||||
block_announce_validator: config
|
||||
.block_announce_validator
|
||||
.unwrap_or_else(|| Box::new(DefaultBlockAnnounceValidator)),
|
||||
create_chain_sync: Box::new(move |sync_mode, chain, warp_sync_provider| {
|
||||
match ChainSync::new(
|
||||
sync_mode,
|
||||
chain,
|
||||
block_announce_validator,
|
||||
max_parallel_downloads,
|
||||
warp_sync_provider,
|
||||
) {
|
||||
Ok(chain_sync) => Ok(Box::new(chain_sync)),
|
||||
Err(error) => Err(Box::new(error).into()),
|
||||
}
|
||||
}),
|
||||
metrics_registry: None,
|
||||
block_request_protocol_config,
|
||||
state_request_protocol_config,
|
||||
@@ -1012,6 +1015,7 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct TestNet {
|
||||
peers: Vec<Peer<(), PeersClient>>,
|
||||
}
|
||||
@@ -1021,17 +1025,7 @@ impl TestNetFactory for TestNet {
|
||||
type PeerData = ();
|
||||
type BlockImport = PeersClient;
|
||||
|
||||
/// Create new test network with peers and given config.
|
||||
fn from_config(_config: &ProtocolConfig) -> Self {
|
||||
TestNet { peers: Vec::new() }
|
||||
}
|
||||
|
||||
fn make_verifier(
|
||||
&self,
|
||||
_client: PeersClient,
|
||||
_config: &ProtocolConfig,
|
||||
_peer_data: &(),
|
||||
) -> Self::Verifier {
|
||||
fn make_verifier(&self, _client: PeersClient, _peer_data: &()) -> Self::Verifier {
|
||||
PassThroughVerifier::new(false)
|
||||
}
|
||||
|
||||
@@ -1081,6 +1075,7 @@ impl JustificationImport<Block> for ForceFinalized {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct JustificationTestNet(TestNet);
|
||||
|
||||
impl TestNetFactory for JustificationTestNet {
|
||||
@@ -1088,17 +1083,8 @@ impl TestNetFactory for JustificationTestNet {
|
||||
type PeerData = ();
|
||||
type BlockImport = PeersClient;
|
||||
|
||||
fn from_config(config: &ProtocolConfig) -> Self {
|
||||
JustificationTestNet(TestNet::from_config(config))
|
||||
}
|
||||
|
||||
fn make_verifier(
|
||||
&self,
|
||||
client: PeersClient,
|
||||
config: &ProtocolConfig,
|
||||
peer_data: &(),
|
||||
) -> Self::Verifier {
|
||||
self.0.make_verifier(client, config, peer_data)
|
||||
fn make_verifier(&self, client: PeersClient, peer_data: &()) -> Self::Verifier {
|
||||
self.0.make_verifier(client, peer_data)
|
||||
}
|
||||
|
||||
fn peer(&mut self, i: usize) -> &mut Peer<Self::PeerData, Self::BlockImport> {
|
||||
|
||||
@@ -50,8 +50,10 @@ sp-consensus = { version = "0.10.0-dev", path = "../../primitives/consensus/comm
|
||||
sc-consensus = { version = "0.10.0-dev", path = "../../client/consensus/common" }
|
||||
sp-inherents = { version = "4.0.0-dev", path = "../../primitives/inherents" }
|
||||
sp-storage = { version = "6.0.0", path = "../../primitives/storage" }
|
||||
sc-network-common = { version = "0.10.0-dev", path = "../network/common" }
|
||||
sc-network = { version = "0.10.0-dev", path = "../network" }
|
||||
sc-network-common = { version = "0.10.0-dev", path = "../network/common" }
|
||||
sc-network-light = { version = "0.10.0-dev", path = "../network/light" }
|
||||
sc-network-sync = { version = "0.10.0-dev", path = "../network/sync" }
|
||||
sc-chain-spec = { version = "4.0.0-dev", path = "../chain-spec" }
|
||||
sc-client-api = { version = "4.0.0-dev", path = "../api" }
|
||||
sp-api = { version = "4.0.0-dev", path = "../../primitives/api" }
|
||||
|
||||
@@ -38,13 +38,17 @@ use sc_consensus::import_queue::ImportQueue;
|
||||
use sc_executor::RuntimeVersionOf;
|
||||
use sc_keystore::LocalKeystore;
|
||||
use sc_network::{
|
||||
block_request_handler::{self, BlockRequestHandler},
|
||||
config::{Role, SyncMode},
|
||||
light_client_requests::{self, handler::LightClientRequestHandler},
|
||||
state_request_handler::{self, StateRequestHandler},
|
||||
warp_request_handler::{self, RequestHandler as WarpSyncRequestHandler, WarpSyncProvider},
|
||||
NetworkService,
|
||||
};
|
||||
use sc_network_common::sync::warp::WarpSyncProvider;
|
||||
use sc_network_light::light_client_requests::{self, handler::LightClientRequestHandler};
|
||||
use sc_network_sync::{
|
||||
block_request_handler::{self, BlockRequestHandler},
|
||||
state_request_handler::{self, StateRequestHandler},
|
||||
warp_request_handler::{self, RequestHandler as WarpSyncRequestHandler},
|
||||
ChainSync,
|
||||
};
|
||||
use sc_rpc::{
|
||||
author::AuthorApiServer,
|
||||
chain::ChainApiServer,
|
||||
@@ -801,6 +805,7 @@ where
|
||||
}
|
||||
};
|
||||
|
||||
let max_parallel_downloads = config.network.max_parallel_downloads;
|
||||
let network_params = sc_network::config::Params {
|
||||
role: config.role.clone(),
|
||||
executor: {
|
||||
@@ -818,9 +823,20 @@ where
|
||||
network_config: config.network.clone(),
|
||||
chain: client.clone(),
|
||||
transaction_pool: transaction_pool_adapter as _,
|
||||
import_queue: Box::new(import_queue),
|
||||
protocol_id,
|
||||
block_announce_validator,
|
||||
import_queue: Box::new(import_queue),
|
||||
create_chain_sync: Box::new(
|
||||
move |sync_mode, chain, warp_sync_provider| match ChainSync::new(
|
||||
sync_mode,
|
||||
chain,
|
||||
block_announce_validator,
|
||||
max_parallel_downloads,
|
||||
warp_sync_provider,
|
||||
) {
|
||||
Ok(chain_sync) => Ok(Box::new(chain_sync)),
|
||||
Err(error) => Err(Box::new(error).into()),
|
||||
},
|
||||
),
|
||||
metrics_registry: config.prometheus_config.as_ref().map(|config| config.registry.clone()),
|
||||
block_request_protocol_config,
|
||||
state_request_protocol_config,
|
||||
|
||||
Reference in New Issue
Block a user