diff --git a/Cargo.lock b/Cargo.lock index d12db0d72559a..192a8abbdb50e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -20612,7 +20612,6 @@ dependencies = [ "sp-arithmetic", "sp-blockchain", "sp-consensus", - "sp-consensus-grandpa", "sp-core 28.0.0", "sp-runtime", "sp-test-primitives", diff --git a/prdoc/pr_10223.prdoc b/prdoc/pr_10223.prdoc new file mode 100644 index 0000000000000..87a41abccb88b --- /dev/null +++ b/prdoc/pr_10223.prdoc @@ -0,0 +1,14 @@ +title: Removed dependency to `sp-consensus-grandpa` from `sc-network-sync` +doc: +- audience: Node Dev + description: |- + Refactored warp sync to remove the dependency on GRANDPA consensus primitives from the network sync module. + Instead of directly verifying proofs with GRANDPA-specific parameters, warp sync now uses a more generic + verifier pattern. This makes the warp sync implementation independent of any specific consensus mechanism, + allowing it to work with different consensus algorithms in the future. + +crates: +- name: sc-consensus-grandpa + bump: major +- name: sc-network-sync + bump: major diff --git a/substrate/client/consensus/grandpa/src/warp_proof.rs b/substrate/client/consensus/grandpa/src/warp_proof.rs index 42701a9cb3edd..8934206097845 100644 --- a/substrate/client/consensus/grandpa/src/warp_proof.rs +++ b/substrate/client/consensus/grandpa/src/warp_proof.rs @@ -24,7 +24,9 @@ use crate::{ BlockNumberOps, GrandpaJustification, SharedAuthoritySet, }; use sc_client_api::Backend as ClientBackend; -use sc_network_sync::strategy::warp::{EncodedProof, VerificationResult, WarpSyncProvider}; +use sc_network_sync::strategy::warp::{ + EncodedProof, VerificationResult, Verifier, WarpSyncProvider, +}; use sp_blockchain::{Backend as BlockchainBackend, HeaderBackend}; use sp_consensus_grandpa::{AuthorityList, SetId, GRANDPA_ENGINE_ID}; use sp_runtime::{ @@ -278,29 +280,26 @@ where } } -impl> WarpSyncProvider - for NetworkProvider +/// Verifier state for GRANDPA warp sync. +struct VerifierState { + set_id: SetId, + authorities: AuthorityList, + next_proof_context: Block::Hash, +} + +/// Verifier implementation for GRANDPA warp sync. +struct GrandpaVerifier { + state: VerifierState, + hard_forks: HashMap<(Block::Hash, NumberFor), (SetId, AuthorityList)>, +} + +impl Verifier for GrandpaVerifier where NumberFor: BlockNumberOps, { - fn generate( - &self, - start: Block::Hash, - ) -> Result> { - let proof = WarpSyncProof::::generate( - &*self.backend, - start, - &self.authority_set.authority_set_changes(), - ) - .map_err(Box::new)?; - Ok(EncodedProof(proof.encode())) - } - fn verify( - &self, + &mut self, proof: &EncodedProof, - set_id: SetId, - authorities: AuthorityList, ) -> Result, Box> { let EncodedProof(proof) = proof; let proof = WarpSyncProof::::decode_all(&mut proof.as_slice()) @@ -310,8 +309,20 @@ where .last() .map(|p| p.header.clone()) .ok_or_else(|| "Empty proof".to_string())?; - let (next_set_id, next_authorities) = - proof.verify(set_id, authorities, &self.hard_forks).map_err(Box::new)?; + + let (current_set_id, current_authorities) = + (self.state.set_id, self.state.authorities.clone()); + + let (next_set_id, next_authorities) = proof + .verify(current_set_id, current_authorities, &self.hard_forks) + .map_err(Box::new)?; + + self.state = VerifierState { + set_id: next_set_id, + authorities: next_authorities, + next_proof_context: last_header.hash(), + }; + let justifications = proof .proofs .into_iter() @@ -321,25 +332,48 @@ where (p.header, justifications) }) .collect::>(); + if proof.is_finished { - Ok(VerificationResult::::Complete( - next_set_id, - next_authorities, - last_header, - justifications, - )) + Ok(VerificationResult::Complete(last_header, justifications)) } else { - Ok(VerificationResult::::Partial( - next_set_id, - next_authorities, - last_header.hash(), - justifications, - )) + Ok(VerificationResult::Partial(justifications)) } } - fn current_authorities(&self) -> AuthorityList { - self.authority_set.inner().current_authorities.clone() + fn next_proof_context(&self) -> Block::Hash { + self.state.next_proof_context + } +} + +impl> WarpSyncProvider + for NetworkProvider +where + NumberFor: BlockNumberOps, +{ + fn generate( + &self, + start: Block::Hash, + ) -> Result> { + let proof = WarpSyncProof::::generate( + &*self.backend, + start, + &self.authority_set.authority_set_changes(), + ) + .map_err(Box::new)?; + Ok(EncodedProof(proof.encode())) + } + + fn create_verifier(&self) -> Box> { + let authority_set = self.authority_set.inner(); + let genesis_hash = self.backend.blockchain().info().genesis_hash; + Box::new(GrandpaVerifier { + state: VerifierState { + set_id: authority_set.set_id, + authorities: authority_set.current_authorities.clone(), + next_proof_context: genesis_hash, + }, + hard_forks: self.hard_forks.clone(), + }) } } diff --git a/substrate/client/network/sync/Cargo.toml b/substrate/client/network/sync/Cargo.toml index c92362dabf703..5478b9044995b 100644 --- a/substrate/client/network/sync/Cargo.toml +++ b/substrate/client/network/sync/Cargo.toml @@ -37,7 +37,6 @@ smallvec = { workspace = true, default-features = true } sp-arithmetic = { workspace = true, default-features = true } sp-blockchain = { workspace = true, default-features = true } sp-consensus = { workspace = true, default-features = true } -sp-consensus-grandpa = { workspace = true, default-features = true } sp-core = { workspace = true, default-features = true } sp-runtime = { workspace = true, default-features = true } thiserror = { workspace = true } diff --git a/substrate/client/network/sync/src/strategy/polkadot.rs b/substrate/client/network/sync/src/strategy/polkadot.rs index 03de11de7e9e9..25551c6b54497 100644 --- a/substrate/client/network/sync/src/strategy/polkadot.rs +++ b/substrate/client/network/sync/src/strategy/polkadot.rs @@ -82,7 +82,7 @@ pub struct PolkadotSyncingStrategy { /// Client used by syncing strategies. client: Arc, /// Warp strategy. - warp: Option>, + warp: Option>, /// State strategy. state: Option>, /// `ChainSync` strategy.` @@ -207,7 +207,7 @@ where ); debug_assert!(false); }, - WarpSync::::STRATEGY_KEY => + WarpSync::::STRATEGY_KEY => if let Some(warp) = &mut self.warp { warp.on_generic_response(peer_id, protocol_name, response); } else { diff --git a/substrate/client/network/sync/src/strategy/warp.rs b/substrate/client/network/sync/src/strategy/warp.rs index c815ca1b86d6a..8458a5c3944f8 100644 --- a/substrate/client/network/sync/src/strategy/warp.rs +++ b/substrate/client/network/sync/src/strategy/warp.rs @@ -20,7 +20,6 @@ use sc_consensus::IncomingBlock; use sp_consensus::BlockOrigin; -pub use sp_consensus_grandpa::{AuthorityList, SetId}; use crate::{ block_relay_protocol::{BlockDownloader, BlockResponseError}, @@ -60,12 +59,23 @@ pub struct WarpProofRequest { pub begin: B::Hash, } +/// Verifier for warp sync proofs. Each verifier operates in a specific context. +pub trait Verifier: Send + Sync { + /// Verify a warp sync proof. + fn verify( + &mut self, + proof: &EncodedProof, + ) -> Result, Box>; + /// Hash to be used as the starting point for the next proof request. + fn next_proof_context(&self) -> Block::Hash; +} + /// Proof verification result. pub enum VerificationResult { /// Proof is valid, but the target was not reached. - Partial(SetId, AuthorityList, Block::Hash, Vec<(Block::Header, Justifications)>), + Partial(Vec<(Block::Header, Justifications)>), /// Target finality is proved. - Complete(SetId, AuthorityList, Block::Header, Vec<(Block::Header, Justifications)>), + Complete(Block::Header, Vec<(Block::Header, Justifications)>), } /// Warp sync backend. Handles retrieving and verifying warp sync proofs. @@ -76,16 +86,8 @@ pub trait WarpSyncProvider: Send + Sync { &self, start: Block::Hash, ) -> Result>; - /// Verify warp proof against current set of authorities. - fn verify( - &self, - proof: &EncodedProof, - set_id: SetId, - authorities: AuthorityList, - ) -> Result, Box>; - /// Get current list of authorities. This is supposed to be genesis authorities when starting - /// sync. - fn current_authorities(&self) -> AuthorityList; + /// Create a verifier for warp sync proofs. + fn create_verifier(&self) -> Box>; } mod rep { @@ -115,7 +117,7 @@ mod rep { pub enum WarpSyncPhase { /// Waiting for peers to connect. AwaitingPeers { required_peers: usize }, - /// Downloading and verifying grandpa warp proofs. + /// Downloading and verifying warp proofs. DownloadingWarpProofs, /// Downloading target block. DownloadingTargetBlock, @@ -168,12 +170,7 @@ enum Phase { /// Waiting for enough peers to connect. WaitingForPeers { warp_sync_provider: Arc> }, /// Downloading warp proofs. - WarpProof { - set_id: SetId, - authorities: AuthorityList, - last_hash: B::Hash, - warp_sync_provider: Arc>, - }, + WarpProof { verifier: Box> }, /// Downloading target block. TargetBlock(B::Header), /// Warp sync is complete. @@ -204,9 +201,8 @@ pub struct WarpSyncResult { } /// Warp sync state machine. Accumulates warp proofs and state. -pub struct WarpSync { +pub struct WarpSync { phase: Phase, - client: Arc, total_proof_bytes: u64, total_state_bytes: u64, peers: HashMap>, @@ -219,10 +215,9 @@ pub struct WarpSync { min_peers_to_start_warp_sync: usize, } -impl WarpSync +impl WarpSync where B: BlockT, - Client: HeaderBackend + 'static, { /// Strategy key used by warp sync. pub const STRATEGY_KEY: StrategyKey = StrategyKey::new("Warp"); @@ -230,13 +225,16 @@ where /// Create a new instance. When passing a warp sync provider we will be checking for proof and /// authorities. Alternatively we can pass a target block when we want to skip downloading /// proofs, in this case we will continue polling until the target block is known. - pub fn new( + pub fn new( client: Arc, warp_sync_config: WarpSyncConfig, protocol_name: Option, block_downloader: Arc>, min_peers_to_start_warp_sync: Option, - ) -> Self { + ) -> Self + where + Client: HeaderBackend + 'static, + { let min_peers_to_start_warp_sync = min_peers_to_start_warp_sync.unwrap_or(MIN_PEERS_TO_START_WARP_SYNC); if client.info().finalized_state.is_some() { @@ -245,7 +243,6 @@ where "Can't use warp sync mode with a partially synced database. Reverting to full sync mode." ); return Self { - client, phase: Phase::Complete, total_proof_bytes: 0, total_state_bytes: 0, @@ -266,7 +263,6 @@ where }; Self { - client, phase, total_proof_bytes: 0, total_state_bytes: 0, @@ -329,12 +325,8 @@ where return } - self.phase = Phase::WarpProof { - set_id: 0, - authorities: warp_sync_provider.current_authorities(), - last_hash: self.client.info().genesis_hash, - warp_sync_provider: Arc::clone(warp_sync_provider), - }; + let verifier = warp_sync_provider.create_verifier(); + self.phase = Phase::WarpProof { verifier }; trace!(target: LOG_TARGET, "Started warp sync with {} peers.", self.peers.len()); } @@ -396,9 +388,7 @@ where peer.state = PeerState::Available; } - let Phase::WarpProof { set_id, authorities, last_hash, warp_sync_provider } = - &mut self.phase - else { + let Phase::WarpProof { verifier } = &mut self.phase else { debug!(target: LOG_TARGET, "Unexpected warp proof response"); self.actions .push(SyncingAction::DropPeer(BadPeer(*peer_id, rep::UNEXPECTED_RESPONSE))); @@ -424,28 +414,24 @@ where } }; - match warp_sync_provider.verify(&response, *set_id, authorities.clone()) { + match verifier.verify(&response) { Err(e) => { debug!(target: LOG_TARGET, "Bad warp proof response: {}", e); self.actions .push(SyncingAction::DropPeer(BadPeer(*peer_id, rep::BAD_WARP_PROOF))) }, - Ok(VerificationResult::Partial(new_set_id, new_authorities, new_last_hash, proofs)) => { - log::debug!(target: LOG_TARGET, "Verified partial proof, set_id={:?}", new_set_id); - *set_id = new_set_id; - *authorities = new_authorities; - *last_hash = new_last_hash; + Ok(VerificationResult::Partial(proofs)) => { + debug!(target: LOG_TARGET, "Verified partial proof"); self.total_proof_bytes += response.0.len() as u64; self.actions.push(SyncingAction::ImportBlocks { origin: BlockOrigin::NetworkInitialSync, blocks: proofs.into_iter().map(proof_to_incoming_block).collect(), }); }, - Ok(VerificationResult::Complete(new_set_id, _, header, proofs)) => { - log::debug!( + Ok(VerificationResult::Complete(header, proofs)) => { + debug!( target: LOG_TARGET, - "Verified complete proof, set_id={:?}. Continuing with target block download: {} ({}).", - new_set_id, + "Verified complete proof. Continuing with target block download: {} ({}).", header.hash(), header.number(), ); @@ -570,10 +556,10 @@ where /// Produce warp proof request. fn warp_proof_request(&mut self) -> Option<(PeerId, ProtocolName, WarpProofRequest)> { - let Phase::WarpProof { last_hash, .. } = &self.phase else { return None }; + let Phase::WarpProof { verifier } = &self.phase else { return None }; - // Copy `last_hash` early to cut the borrowing tie. - let begin = *last_hash; + // Copy verifier context early to cut the borrowing tie. + let begin = verifier.next_proof_context(); if self .peers @@ -773,15 +759,19 @@ mod test { use crate::{mock::MockBlockDownloader, service::network::NetworkServiceProvider}; use sc_block_builder::BlockBuilderBuilder; use sp_blockchain::{BlockStatus, Error as BlockchainError, HeaderBackend, Info}; - use sp_consensus_grandpa::{AuthorityList, SetId, GRANDPA_ENGINE_ID}; use sp_core::H256; - use sp_runtime::traits::{Block as BlockT, Header as HeaderT, NumberFor}; + use sp_runtime::{ + traits::{Block as BlockT, Header as HeaderT, NumberFor}, + ConsensusEngineId, + }; use std::{io::ErrorKind, sync::Arc}; use substrate_test_runtime_client::{ runtime::{Block, Hash}, BlockBuilderExt, DefaultTestClientBuilderExt, TestClientBuilder, TestClientBuilderExt, }; + pub const TEST_ENGINE_ID: ConsensusEngineId = *b"TEST"; + mockall::mock! { pub Client {} @@ -805,13 +795,19 @@ mod test { &self, start: B::Hash, ) -> Result>; + fn create_verifier(&self) -> Box>; + } + } + + mockall::mock! { + pub Verifier {} + + impl super::Verifier for Verifier { fn verify( - &self, + &mut self, proof: &EncodedProof, - set_id: SetId, - authorities: AuthorityList, ) -> Result, Box>; - fn current_authorities(&self) -> AuthorityList; + fn next_proof_context(&self) -> B::Hash; } } @@ -954,10 +950,12 @@ mod test { fn warp_sync_is_started_only_when_there_is_enough_peers() { let client = mock_client_without_state(); let mut provider = MockWarpSyncProvider::::new(); - provider - .expect_current_authorities() - .once() - .return_const(AuthorityList::default()); + let mut verifier = MockVerifier::::new(); + verifier.expect_next_proof_context().returning(|| Hash::random()); + verifier + .expect_verify() + .returning(|_| unreachable!("verify should not be called in this test")); + provider.expect_create_verifier().return_once(move || Box::new(verifier)); let config = WarpSyncConfig::WithProvider(Arc::new(provider)); let mut warp_sync = WarpSync::new( Arc::new(client), @@ -1008,10 +1006,12 @@ mod test { for _ in 0..100 { let client = mock_client_without_state(); let mut provider = MockWarpSyncProvider::::new(); - provider - .expect_current_authorities() - .once() - .return_const(AuthorityList::default()); + let mut verifier = MockVerifier::::new(); + verifier.expect_next_proof_context().returning(|| Hash::random()); + verifier + .expect_verify() + .returning(|_| unreachable!("verify should not be called in this test")); + provider.expect_create_verifier().return_once(move || Box::new(verifier)); let config = WarpSyncConfig::WithProvider(Arc::new(provider)); let mut warp_sync = WarpSync::new( Arc::new(client), @@ -1035,10 +1035,12 @@ mod test { for _ in 0..10 { let client = mock_client_without_state(); let mut provider = MockWarpSyncProvider::::new(); - provider - .expect_current_authorities() - .once() - .return_const(AuthorityList::default()); + let mut verifier = MockVerifier::::new(); + verifier.expect_next_proof_context().returning(|| Hash::random()); + verifier + .expect_verify() + .returning(|_| unreachable!("verify should not be called in this test")); + provider.expect_create_verifier().return_once(move || Box::new(verifier)); let config = WarpSyncConfig::WithProvider(Arc::new(provider)); let mut warp_sync = WarpSync::new( Arc::new(client), @@ -1061,10 +1063,12 @@ mod test { fn backedoff_number_peer_is_not_scheduled() { let client = mock_client_without_state(); let mut provider = MockWarpSyncProvider::::new(); - provider - .expect_current_authorities() - .once() - .return_const(AuthorityList::default()); + let mut verifier = MockVerifier::::new(); + verifier.expect_next_proof_context().returning(|| Hash::random()); + verifier + .expect_verify() + .returning(|_| unreachable!("verify should not be called in this test")); + provider.expect_create_verifier().return_once(move || Box::new(verifier)); let config = WarpSyncConfig::WithProvider(Arc::new(provider)); let mut warp_sync = WarpSync::new( Arc::new(client), @@ -1111,10 +1115,12 @@ mod test { fn no_warp_proof_request_in_another_phase() { let client = mock_client_without_state(); let mut provider = MockWarpSyncProvider::::new(); - provider - .expect_current_authorities() - .once() - .return_const(AuthorityList::default()); + let mut verifier = MockVerifier::::new(); + verifier.expect_next_proof_context().returning(|| Hash::random()); + verifier + .expect_verify() + .returning(|_| unreachable!("verify should not be called in this test")); + provider.expect_create_verifier().return_once(move || Box::new(verifier)); let config = WarpSyncConfig::WithProvider(Arc::new(provider)); let mut warp_sync = WarpSync::new( Arc::new(client), @@ -1146,10 +1152,13 @@ mod test { fn warp_proof_request_starts_at_last_hash() { let client = mock_client_without_state(); let mut provider = MockWarpSyncProvider::::new(); - provider - .expect_current_authorities() - .once() - .return_const(AuthorityList::default()); + let mut verifier = MockVerifier::::new(); + let known_last_hash = Hash::random(); + verifier.expect_next_proof_context().returning(move || known_last_hash); + verifier + .expect_verify() + .returning(|_| unreachable!("verify should not be called in this test")); + provider.expect_create_verifier().return_once(move || Box::new(verifier)); let config = WarpSyncConfig::WithProvider(Arc::new(provider)); let mut warp_sync = WarpSync::new( Arc::new(client), @@ -1165,16 +1174,6 @@ mod test { } assert!(matches!(warp_sync.phase, Phase::WarpProof { .. })); - let known_last_hash = Hash::random(); - - // Manually set last hash to known value. - match &mut warp_sync.phase { - Phase::WarpProof { last_hash, .. } => { - *last_hash = known_last_hash; - }, - _ => panic!("Invalid phase."), - } - let (_peer_id, _protocol_name, request) = warp_sync.warp_proof_request().unwrap(); assert_eq!(request.begin, known_last_hash); } @@ -1183,10 +1182,12 @@ mod test { fn no_parallel_warp_proof_requests() { let client = mock_client_without_state(); let mut provider = MockWarpSyncProvider::::new(); - provider - .expect_current_authorities() - .once() - .return_const(AuthorityList::default()); + let mut verifier = MockVerifier::::new(); + verifier.expect_next_proof_context().returning(|| Hash::random()); + verifier + .expect_verify() + .returning(|_| unreachable!("verify should not be called in this test")); + provider.expect_create_verifier().return_once(move || Box::new(verifier)); let config = WarpSyncConfig::WithProvider(Arc::new(provider)); let mut warp_sync = WarpSync::new( Arc::new(client), @@ -1212,14 +1213,13 @@ mod test { fn bad_warp_proof_response_drops_peer() { let client = mock_client_without_state(); let mut provider = MockWarpSyncProvider::::new(); - provider - .expect_current_authorities() - .once() - .return_const(AuthorityList::default()); + let mut verifier = MockVerifier::::new(); + verifier.expect_next_proof_context().returning(|| Hash::random()); // Warp proof verification fails. - provider.expect_verify().return_once(|_proof, _set_id, _authorities| { + verifier.expect_verify().return_once(|_proof| { Err(Box::new(std::io::Error::new(ErrorKind::Other, "test-verification-failure"))) }); + provider.expect_create_verifier().return_once(move || Box::new(verifier)); let config = WarpSyncConfig::WithProvider(Arc::new(provider)); let mut warp_sync = WarpSync::new( Arc::new(client), @@ -1261,10 +1261,6 @@ mod test { fn partial_warp_proof_doesnt_advance_phase() { let client = Arc::new(TestClientBuilder::new().set_no_genesis().build()); let mut provider = MockWarpSyncProvider::::new(); - provider - .expect_current_authorities() - .once() - .return_const(AuthorityList::default()); let target_block = BlockBuilderBuilder::new(&*client) .on_parent_block(client.chain_info().best_hash) .with_parent_block_number(client.chain_info().best_number) @@ -1274,20 +1270,20 @@ mod test { .unwrap() .block; let target_header = target_block.header().clone(); - let justifications = Justifications::new(vec![(GRANDPA_ENGINE_ID, vec![1, 2, 3, 4, 5])]); + let justifications = Justifications::new(vec![(TEST_ENGINE_ID, vec![1, 2, 3, 4, 5])]); // Warp proof is partial. - { - let target_header = target_header.clone(); - let justifications = justifications.clone(); - provider.expect_verify().return_once(move |_proof, set_id, authorities| { - Ok(VerificationResult::Partial( - set_id, - authorities, - target_header.hash(), - vec![(target_header, justifications)], - )) - }); - } + let mut verifier = MockVerifier::::new(); + let context = client.info().genesis_hash; + verifier.expect_next_proof_context().returning(move || context); + let header_for_verify = target_header.clone(); + let just_for_verify = justifications.clone(); + verifier.expect_verify().return_once(move |_proof| { + Ok(VerificationResult::Partial(vec![( + header_for_verify.clone(), + just_for_verify.clone(), + )])) + }); + provider.expect_create_verifier().return_once(move || Box::new(verifier)); let config = WarpSyncConfig::WithProvider(Arc::new(provider)); let mut warp_sync = WarpSync::new( client, @@ -1345,10 +1341,6 @@ mod test { fn complete_warp_proof_advances_phase() { let client = Arc::new(TestClientBuilder::new().set_no_genesis().build()); let mut provider = MockWarpSyncProvider::::new(); - provider - .expect_current_authorities() - .once() - .return_const(AuthorityList::default()); let target_block = BlockBuilderBuilder::new(&*client) .on_parent_block(client.chain_info().best_hash) .with_parent_block_number(client.chain_info().best_number) @@ -1358,20 +1350,20 @@ mod test { .unwrap() .block; let target_header = target_block.header().clone(); - let justifications = Justifications::new(vec![(GRANDPA_ENGINE_ID, vec![1, 2, 3, 4, 5])]); + let justifications = Justifications::new(vec![(TEST_ENGINE_ID, vec![1, 2, 3, 4, 5])]); // Warp proof is complete. - { - let target_header = target_header.clone(); - let justifications = justifications.clone(); - provider.expect_verify().return_once(move |_proof, set_id, authorities| { - Ok(VerificationResult::Complete( - set_id, - authorities, - target_header.clone(), - vec![(target_header, justifications)], - )) - }); - } + let mut verifier = MockVerifier::::new(); + let context = client.info().genesis_hash; + verifier.expect_next_proof_context().returning(move || context); + let header_for_verify = target_header.clone(); + let just_for_verify = justifications.clone(); + verifier.expect_verify().return_once(move |_proof| { + Ok(VerificationResult::Complete( + header_for_verify.clone(), + vec![(header_for_verify.clone(), just_for_verify.clone())], + )) + }); + provider.expect_create_verifier().return_once(move || Box::new(verifier)); let config = WarpSyncConfig::WithProvider(Arc::new(provider)); let mut warp_sync = WarpSync::new( client, @@ -1431,10 +1423,12 @@ mod test { fn no_target_block_requests_in_another_phase() { let client = mock_client_without_state(); let mut provider = MockWarpSyncProvider::::new(); - provider - .expect_current_authorities() - .once() - .return_const(AuthorityList::default()); + let mut verifier = MockVerifier::::new(); + verifier.expect_next_proof_context().returning(|| Hash::random()); + verifier + .expect_verify() + .returning(|_| unreachable!("verify should not be called in this test")); + provider.expect_create_verifier().return_once(move || Box::new(verifier)); let config = WarpSyncConfig::WithProvider(Arc::new(provider)); let mut warp_sync = WarpSync::new( Arc::new(client), @@ -1459,10 +1453,9 @@ mod test { fn target_block_request_is_correct() { let client = Arc::new(TestClientBuilder::new().set_no_genesis().build()); let mut provider = MockWarpSyncProvider::::new(); - provider - .expect_current_authorities() - .once() - .return_const(AuthorityList::default()); + let mut verifier = MockVerifier::::new(); + let header_for_ctx = client.info().genesis_hash; + verifier.expect_next_proof_context().returning(move || header_for_ctx); let target_block = BlockBuilderBuilder::new(&*client) .on_parent_block(client.chain_info().best_hash) .with_parent_block_number(client.chain_info().best_number) @@ -1473,9 +1466,11 @@ mod test { .block; let target_header = target_block.header().clone(); // Warp proof is complete. - provider.expect_verify().return_once(move |_proof, set_id, authorities| { - Ok(VerificationResult::Complete(set_id, authorities, target_header, Default::default())) + let header_for_verify = target_header.clone(); + verifier.expect_verify().return_once(move |_proof| { + Ok(VerificationResult::Complete(header_for_verify, Default::default())) }); + provider.expect_create_verifier().return_once(move || Box::new(verifier)); let config = WarpSyncConfig::WithProvider(Arc::new(provider)); let mut warp_sync = WarpSync::new(client, config, None, Arc::new(MockBlockDownloader::new()), None); @@ -1533,10 +1528,9 @@ mod test { fn no_parallel_target_block_requests() { let client = Arc::new(TestClientBuilder::new().set_no_genesis().build()); let mut provider = MockWarpSyncProvider::::new(); - provider - .expect_current_authorities() - .once() - .return_const(AuthorityList::default()); + let mut verifier = MockVerifier::::new(); + let header_for_ctx = client.info().genesis_hash; + verifier.expect_next_proof_context().returning(move || header_for_ctx); let target_block = BlockBuilderBuilder::new(&*client) .on_parent_block(client.chain_info().best_hash) .with_parent_block_number(client.chain_info().best_number) @@ -1547,9 +1541,11 @@ mod test { .block; let target_header = target_block.header().clone(); // Warp proof is complete. - provider.expect_verify().return_once(move |_proof, set_id, authorities| { - Ok(VerificationResult::Complete(set_id, authorities, target_header, Default::default())) + let header_for_verify = target_header.clone(); + verifier.expect_verify().return_once(move |_proof| { + Ok(VerificationResult::Complete(header_for_verify, Default::default())) }); + provider.expect_create_verifier().return_once(move || Box::new(verifier)); let config = WarpSyncConfig::WithProvider(Arc::new(provider)); let mut warp_sync = WarpSync::new(client, config, None, Arc::new(MockBlockDownloader::new()), None); @@ -1572,10 +1568,9 @@ mod test { fn target_block_response_with_no_blocks_drops_peer() { let client = Arc::new(TestClientBuilder::new().set_no_genesis().build()); let mut provider = MockWarpSyncProvider::::new(); - provider - .expect_current_authorities() - .once() - .return_const(AuthorityList::default()); + let mut verifier = MockVerifier::::new(); + let header_for_ctx = client.info().genesis_hash; + verifier.expect_next_proof_context().returning(move || header_for_ctx); let target_block = BlockBuilderBuilder::new(&*client) .on_parent_block(client.chain_info().best_hash) .with_parent_block_number(client.chain_info().best_number) @@ -1586,9 +1581,11 @@ mod test { .block; let target_header = target_block.header().clone(); // Warp proof is complete. - provider.expect_verify().return_once(move |_proof, set_id, authorities| { - Ok(VerificationResult::Complete(set_id, authorities, target_header, Default::default())) + let header_for_verify = target_header.clone(); + verifier.expect_verify().return_once(move |_proof| { + Ok(VerificationResult::Complete(header_for_verify, Default::default())) }); + provider.expect_create_verifier().return_once(move || Box::new(verifier)); let config = WarpSyncConfig::WithProvider(Arc::new(provider)); let mut warp_sync = WarpSync::new(client, config, None, Arc::new(MockBlockDownloader::new()), None); @@ -1616,10 +1613,9 @@ mod test { fn target_block_response_with_extra_blocks_drops_peer() { let client = Arc::new(TestClientBuilder::new().set_no_genesis().build()); let mut provider = MockWarpSyncProvider::::new(); - provider - .expect_current_authorities() - .once() - .return_const(AuthorityList::default()); + let mut verifier = MockVerifier::::new(); + let header_for_ctx = client.info().genesis_hash; + verifier.expect_next_proof_context().returning(move || header_for_ctx); let target_block = BlockBuilderBuilder::new(&*client) .on_parent_block(client.chain_info().best_hash) .with_parent_block_number(client.chain_info().best_number) @@ -1641,9 +1637,11 @@ mod test { let target_header = target_block.header().clone(); // Warp proof is complete. - provider.expect_verify().return_once(move |_proof, set_id, authorities| { - Ok(VerificationResult::Complete(set_id, authorities, target_header, Default::default())) + let header_for_verify = target_header.clone(); + verifier.expect_verify().return_once(move |_proof| { + Ok(VerificationResult::Complete(header_for_verify, Default::default())) }); + provider.expect_create_verifier().return_once(move || Box::new(verifier)); let config = WarpSyncConfig::WithProvider(Arc::new(provider)); let mut warp_sync = WarpSync::new(client, config, None, Arc::new(MockBlockDownloader::new()), None); @@ -1694,10 +1692,9 @@ mod test { let client = Arc::new(TestClientBuilder::new().set_no_genesis().build()); let mut provider = MockWarpSyncProvider::::new(); - provider - .expect_current_authorities() - .once() - .return_const(AuthorityList::default()); + let mut verifier = MockVerifier::::new(); + let header_for_ctx = client.info().genesis_hash; + verifier.expect_next_proof_context().returning(move || header_for_ctx); let target_block = BlockBuilderBuilder::new(&*client) .on_parent_block(client.chain_info().best_hash) .with_parent_block_number(client.chain_info().best_number) @@ -1719,9 +1716,11 @@ mod test { let target_header = target_block.header().clone(); // Warp proof is complete. - provider.expect_verify().return_once(move |_proof, set_id, authorities| { - Ok(VerificationResult::Complete(set_id, authorities, target_header, Default::default())) + let header_for_verify = target_header.clone(); + verifier.expect_verify().return_once(move |_proof| { + Ok(VerificationResult::Complete(header_for_verify, Default::default())) }); + provider.expect_create_verifier().return_once(move || Box::new(verifier)); let config = WarpSyncConfig::WithProvider(Arc::new(provider)); let mut warp_sync = WarpSync::new(client, config, None, Arc::new(MockBlockDownloader::new()), None); @@ -1758,10 +1757,9 @@ mod test { fn correct_target_block_response_sets_strategy_result() { let client = Arc::new(TestClientBuilder::new().set_no_genesis().build()); let mut provider = MockWarpSyncProvider::::new(); - provider - .expect_current_authorities() - .once() - .return_const(AuthorityList::default()); + let mut verifier = MockVerifier::::new(); + let header_for_ctx = client.info().genesis_hash; + verifier.expect_next_proof_context().returning(move || header_for_ctx); let mut target_block_builder = BlockBuilderBuilder::new(&*client) .on_parent_block(client.chain_info().best_hash) .with_parent_block_number(client.chain_info().best_number) @@ -1773,9 +1771,11 @@ mod test { let target_block = target_block_builder.build().unwrap().block; let target_header = target_block.header().clone(); // Warp proof is complete. - provider.expect_verify().return_once(move |_proof, set_id, authorities| { - Ok(VerificationResult::Complete(set_id, authorities, target_header, Default::default())) + let header_for_verify = target_header.clone(); + verifier.expect_verify().return_once(move |_proof| { + Ok(VerificationResult::Complete(header_for_verify, Default::default())) }); + provider.expect_create_verifier().return_once(move || Box::new(verifier)); let config = WarpSyncConfig::WithProvider(Arc::new(provider)); let mut warp_sync = WarpSync::new(client, config, None, Arc::new(MockBlockDownloader::new()), None); diff --git a/substrate/client/network/test/src/lib.rs b/substrate/client/network/test/src/lib.rs index 79a0a42138bf7..92bb62ad58a24 100644 --- a/substrate/client/network/test/src/lib.rs +++ b/substrate/client/network/test/src/lib.rs @@ -71,7 +71,7 @@ use sc_network_sync::{ strategy::{ polkadot::{PolkadotSyncingStrategy, PolkadotSyncingStrategyConfig}, warp::{ - AuthorityList, EncodedProof, SetId, VerificationResult, WarpSyncConfig, + EncodedProof, VerificationResult, Verifier as WarpVerifier, WarpSyncConfig, WarpSyncProvider, }, }, @@ -656,6 +656,25 @@ impl VerifierAdapter { struct TestWarpSyncProvider(Arc>); +struct TestVerifier { + genesis_hash: B::Hash, +} + +impl WarpVerifier for TestVerifier { + fn verify( + &mut self, + proof: &EncodedProof, + ) -> Result, Box> { + let EncodedProof(encoded) = proof; + let header = B::Header::decode(&mut encoded.as_slice()).unwrap(); + Ok(VerificationResult::Complete(header, Default::default())) + } + + fn next_proof_context(&self) -> B::Hash { + self.genesis_hash + } +} + impl WarpSyncProvider for TestWarpSyncProvider { fn generate( &self, @@ -665,18 +684,10 @@ impl WarpSyncProvider for TestWarpSyncProvider { let best_header = self.0.header(info.best_hash).unwrap().unwrap(); Ok(EncodedProof(best_header.encode())) } - fn verify( - &self, - proof: &EncodedProof, - _set_id: SetId, - _authorities: AuthorityList, - ) -> Result, Box> { - let EncodedProof(encoded) = proof; - let header = B::Header::decode(&mut encoded.as_slice()).unwrap(); - Ok(VerificationResult::Complete(0, Default::default(), header, Default::default())) - } - fn current_authorities(&self) -> AuthorityList { - Default::default() + + fn create_verifier(&self) -> Box> { + let genesis_hash = self.0.info().genesis_hash; + Box::new(TestVerifier { genesis_hash }) } }