mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-04-28 00:28:01 +00:00
Light GRANDPA import handler (#1669)
* GrandpaLightBlockImport * extract authorities in AuraVerifier * post-merge fix * restore authorities cache * license * new finality proof draft * generalized PendingJustifications * finality proof messages * fixed compilation * pass verifier to import_finality_proof * do not fetch remote proof from light import directly * FinalityProofProvider * fixed authorities cache test * restored finality proof tests * finality_proof docs * use DB backend in test client * justification_is_fetched_by_light_client_when_consensus_data_changes * restore justification_is_fetched_by_light_client_when_consensus_data_changes * some more tests * added authorities-related TODO * removed unneeded clear_finality_proof_requests field * truncated some long lines * more granular light import tests * only provide finality proof if it is generated by the requested set * post-merge fix * finality_proof_is_none_if_first_justification_is_generated_by_unknown_set * make light+grandpa test rely on finality proofs (instead of simple justifications) * empty_finality_proof_is_returned_to_light_client_when_authority_set_is_different * missing trait method impl * fixed proof-of-finality docs * one more doc fix * fix docs * initialize authorities cache (post-merge fix) * fixed cache initialization (post-merge fix) * post-fix merge: fix light + GRANDPA tests (bad way) * proper fix of empty_finality_proof_is_returned_to_light_client_when_authority_set_is_different * fixed easy grumbles * import finality proofs in BlockImportWorker thread * allow import of finality proofs for non-requested blocks * limit number of fragments in finality proof * GRANDPA post-merge fix * BABE: pos-merge fix
This commit is contained in:
committed by
Gavin Wood
parent
258f0835e4
commit
22586113ea
@@ -22,6 +22,8 @@ use std::borrow::Cow;
|
||||
use std::collections::HashMap;
|
||||
use crate::well_known_cache_keys;
|
||||
|
||||
use crate::import_queue::Verifier;
|
||||
|
||||
/// Block import result.
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub enum ImportResult {
|
||||
@@ -44,6 +46,8 @@ pub struct ImportedAux {
|
||||
pub needs_justification: bool,
|
||||
/// Received a bad justification.
|
||||
pub bad_justification: bool,
|
||||
/// Request a finality proof for the given block.
|
||||
pub needs_finality_proof: bool,
|
||||
}
|
||||
|
||||
impl Default for ImportedAux {
|
||||
@@ -52,6 +56,7 @@ impl Default for ImportedAux {
|
||||
clear_justification_requests: false,
|
||||
needs_justification: false,
|
||||
bad_justification: false,
|
||||
needs_finality_proof: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -202,3 +207,26 @@ pub trait JustificationImport<B: BlockT> {
|
||||
justification: Justification,
|
||||
) -> Result<(), Self::Error>;
|
||||
}
|
||||
|
||||
/// Finality proof import trait.
|
||||
pub trait FinalityProofImport<B: BlockT> {
|
||||
type Error: ::std::error::Error + Send + 'static;
|
||||
|
||||
/// Called by the import queue when it is started.
|
||||
fn on_start(&self, _link: &crate::import_queue::Link<B>) { }
|
||||
|
||||
/// Import a Block justification and finalize the given block. Returns finalized block or error.
|
||||
fn import_finality_proof(
|
||||
&self,
|
||||
hash: B::Hash,
|
||||
number: NumberFor<B>,
|
||||
finality_proof: Vec<u8>,
|
||||
verifier: &Verifier<B>,
|
||||
) -> Result<(B::Hash, NumberFor<B>), Self::Error>;
|
||||
}
|
||||
|
||||
/// Finality proof request builder.
|
||||
pub trait FinalityProofRequestBuilder<B: BlockT>: Send {
|
||||
/// Build data blob, associated with the request.
|
||||
fn build_request_data(&self, hash: &B::Hash) -> Vec<u8>;
|
||||
}
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
|
||||
use crate::block_import::{
|
||||
BlockImport, BlockOrigin, ImportBlock, ImportedAux, ImportResult, JustificationImport,
|
||||
FinalityProofImport, FinalityProofRequestBuilder,
|
||||
};
|
||||
use crossbeam_channel::{self as channel, Receiver, Sender};
|
||||
use parity_codec::Encode;
|
||||
@@ -57,6 +58,12 @@ pub type SharedBlockImport<B> = Arc<dyn BlockImport<B, Error = ConsensusError> +
|
||||
/// Shared justification import struct used by the queue.
|
||||
pub type SharedJustificationImport<B> = Arc<dyn JustificationImport<B, Error=ConsensusError> + Send + Sync>;
|
||||
|
||||
/// Shared finality proof import struct used by the queue.
|
||||
pub type SharedFinalityProofImport<B> = Arc<dyn FinalityProofImport<B, Error=ConsensusError> + Send + Sync>;
|
||||
|
||||
/// Shared finality proof request builder struct used by the queue.
|
||||
pub type SharedFinalityProofRequestBuilder<B> = Arc<dyn FinalityProofRequestBuilder<B> + Send + Sync>;
|
||||
|
||||
/// Maps to the Origin used by the network.
|
||||
pub type Origin = libp2p::PeerId;
|
||||
|
||||
@@ -76,7 +83,7 @@ pub struct IncomingBlock<B: BlockT> {
|
||||
}
|
||||
|
||||
/// Verify a justification of a block
|
||||
pub trait Verifier<B: BlockT>: Send + Sync + Sized {
|
||||
pub trait Verifier<B: BlockT>: Send + Sync {
|
||||
/// Verify the given data and return the ImportBlock and an optional
|
||||
/// new set of validators to import. If not, err with an Error-Message
|
||||
/// presented to the User in the logs.
|
||||
@@ -104,6 +111,8 @@ pub trait ImportQueue<B: BlockT>: Send + Sync + ImportQueueClone<B> {
|
||||
fn import_blocks(&self, origin: BlockOrigin, blocks: Vec<IncomingBlock<B>>);
|
||||
/// Import a block justification.
|
||||
fn import_justification(&self, who: Origin, hash: B::Hash, number: NumberFor<B>, justification: Justification);
|
||||
/// Import block finality proof.
|
||||
fn import_finality_proof(&self, who: Origin, hash: B::Hash, number: NumberFor<B>, finality_proof: Vec<u8>);
|
||||
}
|
||||
|
||||
pub trait ImportQueueClone<B: BlockT> {
|
||||
@@ -129,6 +138,7 @@ impl<B: BlockT> ImportQueueClone<B> for BasicQueue<B> {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// "BasicQueue" is a wrapper around a channel sender to the "BlockImporter".
|
||||
/// "BasicQueue" itself does not keep any state or do any importing work, and
|
||||
/// can therefore be send to other threads.
|
||||
@@ -153,11 +163,25 @@ impl<B: BlockT> BasicQueue<B> {
|
||||
pub fn new<V: 'static + Verifier<B>>(
|
||||
verifier: Arc<V>,
|
||||
block_import: SharedBlockImport<B>,
|
||||
justification_import: Option<SharedJustificationImport<B>>
|
||||
justification_import: Option<SharedJustificationImport<B>>,
|
||||
finality_proof_import: Option<SharedFinalityProofImport<B>>,
|
||||
finality_proof_request_builder: Option<SharedFinalityProofRequestBuilder<B>>,
|
||||
) -> Self {
|
||||
let (result_sender, result_port) = channel::unbounded();
|
||||
let worker_sender = BlockImportWorker::new(result_sender, verifier, block_import);
|
||||
let importer_sender = BlockImporter::new(result_port, worker_sender, justification_import);
|
||||
let worker_sender = BlockImportWorker::new(
|
||||
result_sender,
|
||||
verifier.clone(),
|
||||
block_import,
|
||||
finality_proof_import.clone(),
|
||||
);
|
||||
let importer_sender = BlockImporter::new(
|
||||
result_port,
|
||||
worker_sender,
|
||||
verifier,
|
||||
justification_import,
|
||||
finality_proof_import,
|
||||
finality_proof_request_builder,
|
||||
);
|
||||
|
||||
Self {
|
||||
sender: importer_sender,
|
||||
@@ -210,25 +234,36 @@ impl<B: BlockT> ImportQueue<B> for BasicQueue<B> {
|
||||
.send(BlockImportMsg::ImportJustification(who.clone(), hash, number, justification))
|
||||
.expect("1. self is holding a sender to the Importer, 2. Importer should handle messages while there are senders around; qed");
|
||||
}
|
||||
|
||||
fn import_finality_proof(&self, who: Origin, hash: B::Hash, number: NumberFor<B>, finality_proof: Vec<u8>) {
|
||||
let _ = self
|
||||
.sender
|
||||
.send(BlockImportMsg::ImportFinalityProof(who, hash, number, finality_proof))
|
||||
.expect("1. self is holding a sender to the Importer, 2. Importer should handle messages while there are senders around; qed");
|
||||
}
|
||||
}
|
||||
|
||||
pub enum BlockImportMsg<B: BlockT> {
|
||||
ImportBlocks(BlockOrigin, Vec<IncomingBlock<B>>),
|
||||
ImportJustification(Origin, B::Hash, NumberFor<B>, Justification),
|
||||
ImportFinalityProof(Origin, B::Hash, NumberFor<B>, Vec<u8>),
|
||||
Start(Box<Link<B>>, Sender<Result<(), std::io::Error>>),
|
||||
Stop,
|
||||
#[cfg(any(test, feature = "test-helpers"))]
|
||||
Synchronize,
|
||||
}
|
||||
|
||||
#[cfg_attr(test, derive(Debug, PartialEq))]
|
||||
pub enum BlockImportWorkerMsg<B: BlockT> {
|
||||
ImportBlocks(BlockOrigin, Vec<IncomingBlock<B>>),
|
||||
Imported(
|
||||
ImportedBlocks(
|
||||
Vec<(
|
||||
Result<BlockImportResult<NumberFor<B>>, BlockImportError>,
|
||||
B::Hash,
|
||||
)>,
|
||||
),
|
||||
ImportFinalityProof(Origin, B::Hash, NumberFor<B>, Vec<u8>),
|
||||
ImportedFinalityProof(Origin, (B::Hash, NumberFor<B>), Result<(B::Hash, NumberFor<B>), ()>),
|
||||
#[cfg(any(test, feature = "test-helpers"))]
|
||||
Synchronize,
|
||||
}
|
||||
@@ -243,14 +278,20 @@ struct BlockImporter<B: BlockT> {
|
||||
result_port: Receiver<BlockImportWorkerMsg<B>>,
|
||||
worker_sender: Sender<BlockImportWorkerMsg<B>>,
|
||||
link: Option<Box<dyn Link<B>>>,
|
||||
verifier: Arc<Verifier<B>>,
|
||||
justification_import: Option<SharedJustificationImport<B>>,
|
||||
finality_proof_import: Option<SharedFinalityProofImport<B>>,
|
||||
finality_proof_request_builder: Option<SharedFinalityProofRequestBuilder<B>>,
|
||||
}
|
||||
|
||||
impl<B: BlockT> BlockImporter<B> {
|
||||
fn new(
|
||||
result_port: Receiver<BlockImportWorkerMsg<B>>,
|
||||
worker_sender: Sender<BlockImportWorkerMsg<B>>,
|
||||
verifier: Arc<Verifier<B>>,
|
||||
justification_import: Option<SharedJustificationImport<B>>,
|
||||
finality_proof_import: Option<SharedFinalityProofImport<B>>,
|
||||
finality_proof_request_builder: Option<SharedFinalityProofRequestBuilder<B>>,
|
||||
) -> Sender<BlockImportMsg<B>> {
|
||||
trace!(target: "block_import", "Creating new Block Importer!");
|
||||
let (sender, port) = channel::bounded(4);
|
||||
@@ -262,7 +303,10 @@ impl<B: BlockT> BlockImporter<B> {
|
||||
result_port,
|
||||
worker_sender,
|
||||
link: None,
|
||||
verifier,
|
||||
justification_import,
|
||||
finality_proof_import,
|
||||
finality_proof_request_builder,
|
||||
};
|
||||
while importer.run() {
|
||||
// Importing until all senders have been dropped...
|
||||
@@ -303,10 +347,19 @@ impl<B: BlockT> BlockImporter<B> {
|
||||
BlockImportMsg::ImportJustification(who, hash, number, justification) => {
|
||||
self.handle_import_justification(who, hash, number, justification)
|
||||
},
|
||||
BlockImportMsg::ImportFinalityProof(who, hash, number, finality_proof) => {
|
||||
self.handle_import_finality_proof(who, hash, number, finality_proof)
|
||||
},
|
||||
BlockImportMsg::Start(link, sender) => {
|
||||
if let Some(finality_proof_request_builder) = self.finality_proof_request_builder.take() {
|
||||
link.set_finality_proof_request_builder(finality_proof_request_builder);
|
||||
}
|
||||
if let Some(justification_import) = self.justification_import.as_ref() {
|
||||
justification_import.on_start(&*link);
|
||||
}
|
||||
if let Some(finality_proof_import) = self.finality_proof_import.as_ref() {
|
||||
finality_proof_import.on_start(&*link);
|
||||
}
|
||||
self.link = Some(link);
|
||||
let _ = sender.send(Ok(()));
|
||||
},
|
||||
@@ -332,14 +385,20 @@ impl<B: BlockT> BlockImporter<B> {
|
||||
};
|
||||
|
||||
let results = match msg {
|
||||
BlockImportWorkerMsg::Imported(results) => (results),
|
||||
BlockImportWorkerMsg::ImportedBlocks(results) => (results),
|
||||
BlockImportWorkerMsg::ImportedFinalityProof(who, request_block, finalization_result) => {
|
||||
link.finality_proof_imported(who, request_block, finalization_result);
|
||||
return true;
|
||||
},
|
||||
#[cfg(any(test, feature = "test-helpers"))]
|
||||
BlockImportWorkerMsg::Synchronize => {
|
||||
trace!(target: "sync", "Synchronizing link");
|
||||
link.synchronized();
|
||||
return true;
|
||||
},
|
||||
_ => unreachable!("Import Worker does not send ImportBlocks message; qed"),
|
||||
BlockImportWorkerMsg::ImportBlocks(_, _)
|
||||
| BlockImportWorkerMsg::ImportFinalityProof(_, _, _, _)
|
||||
=> unreachable!("Import Worker does not send Import* message; qed"),
|
||||
};
|
||||
let mut has_error = false;
|
||||
let mut hashes = vec![];
|
||||
@@ -375,6 +434,11 @@ impl<B: BlockT> BlockImporter<B> {
|
||||
link.report_peer(peer, BAD_JUSTIFICATION_REPUTATION_CHANGE);
|
||||
}
|
||||
}
|
||||
|
||||
if aux.needs_finality_proof {
|
||||
trace!(target: "sync", "Block imported but requires finality proof {}: {:?}", number, hash);
|
||||
link.request_finality_proof(&hash, number);
|
||||
}
|
||||
},
|
||||
Err(BlockImportError::IncompleteHeader(who)) => {
|
||||
if let Some(peer) = who {
|
||||
@@ -422,6 +486,13 @@ impl<B: BlockT> BlockImporter<B> {
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_import_finality_proof(&self, who: Origin, hash: B::Hash, number: NumberFor<B>, finality_proof: Vec<u8>) {
|
||||
trace!(target: "sync", "Scheduling finality proof of {}/{} for import", number, hash);
|
||||
self.worker_sender
|
||||
.send(BlockImportWorkerMsg::ImportFinalityProof(who, hash, number, finality_proof))
|
||||
.expect("1. This is holding a sender to the worker, 2. the worker should not quit while a sender is still held; qed");
|
||||
}
|
||||
|
||||
fn handle_import_blocks(&mut self, origin: BlockOrigin, blocks: Vec<IncomingBlock<B>>) {
|
||||
trace!(target: "sync", "Scheduling {} blocks for import", blocks.len());
|
||||
self.worker_sender
|
||||
@@ -433,6 +504,7 @@ impl<B: BlockT> BlockImporter<B> {
|
||||
struct BlockImportWorker<B: BlockT, V: Verifier<B>> {
|
||||
result_sender: Sender<BlockImportWorkerMsg<B>>,
|
||||
block_import: SharedBlockImport<B>,
|
||||
finality_proof_import: Option<SharedFinalityProofImport<B>>,
|
||||
verifier: Arc<V>,
|
||||
}
|
||||
|
||||
@@ -441,6 +513,7 @@ impl<B: BlockT, V: 'static + Verifier<B>> BlockImportWorker<B, V> {
|
||||
result_sender: Sender<BlockImportWorkerMsg<B>>,
|
||||
verifier: Arc<V>,
|
||||
block_import: SharedBlockImport<B>,
|
||||
finality_proof_import: Option<SharedFinalityProofImport<B>>,
|
||||
) -> Sender<BlockImportWorkerMsg<B>> {
|
||||
let (sender, port) = channel::bounded(4);
|
||||
let _ = thread::Builder::new()
|
||||
@@ -450,6 +523,7 @@ impl<B: BlockT, V: 'static + Verifier<B>> BlockImportWorker<B, V> {
|
||||
result_sender,
|
||||
verifier,
|
||||
block_import,
|
||||
finality_proof_import,
|
||||
};
|
||||
for msg in port.iter() {
|
||||
// Working until all senders have been dropped...
|
||||
@@ -457,12 +531,17 @@ impl<B: BlockT, V: 'static + Verifier<B>> BlockImportWorker<B, V> {
|
||||
BlockImportWorkerMsg::ImportBlocks(origin, blocks) => {
|
||||
worker.import_a_batch_of_blocks(origin, blocks);
|
||||
},
|
||||
BlockImportWorkerMsg::ImportFinalityProof(who, hash, number, proof) => {
|
||||
worker.import_finality_proof(who, hash, number, proof);
|
||||
},
|
||||
#[cfg(any(test, feature = "test-helpers"))]
|
||||
BlockImportWorkerMsg::Synchronize => {
|
||||
trace!(target: "sync", "Sending sync message");
|
||||
let _ = worker.result_sender.send(BlockImportWorkerMsg::Synchronize);
|
||||
},
|
||||
_ => unreachable!("Import Worker does not receive the Imported message; qed"),
|
||||
BlockImportWorkerMsg::ImportedBlocks(_)
|
||||
| BlockImportWorkerMsg::ImportedFinalityProof(_, _, _)
|
||||
=> unreachable!("Import Worker does not receive the Imported* messages; qed"),
|
||||
}
|
||||
}
|
||||
})
|
||||
@@ -512,10 +591,31 @@ impl<B: BlockT, V: 'static + Verifier<B>> BlockImportWorker<B, V> {
|
||||
|
||||
let _ = self
|
||||
.result_sender
|
||||
.send(BlockImportWorkerMsg::Imported(results));
|
||||
.send(BlockImportWorkerMsg::ImportedBlocks(results));
|
||||
|
||||
trace!(target: "sync", "Imported {} of {}", imported, count);
|
||||
}
|
||||
|
||||
fn import_finality_proof(&self, who: Origin, hash: B::Hash, number: NumberFor<B>, finality_proof: Vec<u8>) {
|
||||
let result = self.finality_proof_import.as_ref().map(|finality_proof_import| {
|
||||
finality_proof_import.import_finality_proof(hash, number, finality_proof, &*self.verifier)
|
||||
.map_err(|e| {
|
||||
debug!(
|
||||
"Finality proof import failed with {:?} for hash: {:?} number: {:?} coming from node: {:?}",
|
||||
e,
|
||||
hash,
|
||||
number,
|
||||
who,
|
||||
);
|
||||
})
|
||||
}).unwrap_or(Err(()));
|
||||
|
||||
let _ = self
|
||||
.result_sender
|
||||
.send(BlockImportWorkerMsg::ImportedFinalityProof(who, (hash, number), result));
|
||||
|
||||
trace!(target: "sync", "Imported finality proof for {}/{}", number, hash);
|
||||
}
|
||||
}
|
||||
|
||||
/// Hooks that the verification queue can use to influence the synchronization
|
||||
@@ -531,6 +631,21 @@ pub trait Link<B: BlockT>: Send {
|
||||
fn clear_justification_requests(&self) {}
|
||||
/// Request a justification for the given block.
|
||||
fn request_justification(&self, _hash: &B::Hash, _number: NumberFor<B>) {}
|
||||
/// Finality proof import result.
|
||||
///
|
||||
/// Even though we have asked for finality proof of block A, provider could return proof of
|
||||
/// some earlier block B, if the proof for A was too large. The sync module should continue
|
||||
/// asking for proof of A in this case.
|
||||
fn finality_proof_imported(
|
||||
&self,
|
||||
_who: Origin,
|
||||
_request_block: (B::Hash, NumberFor<B>),
|
||||
_finalization_result: Result<(B::Hash, NumberFor<B>), ()>,
|
||||
) {}
|
||||
/// Request a finality proof for the given block.
|
||||
fn request_finality_proof(&self, _hash: &B::Hash, _number: NumberFor<B>) {}
|
||||
/// Remember finality proof request builder on start.
|
||||
fn set_finality_proof_request_builder(&self, _request_builder: SharedFinalityProofRequestBuilder<B>) {}
|
||||
/// Adjusts the reputation of the given peer.
|
||||
fn report_peer(&self, _who: Origin, _reputation_change: i32) {}
|
||||
/// Restart sync.
|
||||
@@ -637,12 +752,14 @@ pub fn import_single_block<B: BlockT, V: Verifier<B>>(
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::block_import::ForkChoiceStrategy;
|
||||
use libp2p::PeerId;
|
||||
use test_client::runtime::{Block, Hash};
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
enum LinkMsg {
|
||||
BlockImported,
|
||||
FinalityProofImported,
|
||||
Disconnected,
|
||||
Restarted,
|
||||
}
|
||||
@@ -664,6 +781,14 @@ mod tests {
|
||||
fn block_imported(&self, _hash: &Hash, _number: NumberFor<Block>) {
|
||||
let _ = self.sender.send(LinkMsg::BlockImported);
|
||||
}
|
||||
fn finality_proof_imported(
|
||||
&self,
|
||||
_: Origin,
|
||||
_: (Hash, NumberFor<Block>),
|
||||
_: Result<(Hash, NumberFor<Block>), ()>,
|
||||
) {
|
||||
let _ = self.sender.send(LinkMsg::FinalityProofImported);
|
||||
}
|
||||
fn report_peer(&self, _: Origin, _: i32) {
|
||||
let _ = self.sender.send(LinkMsg::Disconnected);
|
||||
}
|
||||
@@ -672,12 +797,33 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
impl<B: BlockT> Verifier<B> for () {
|
||||
fn verify(
|
||||
&self,
|
||||
origin: BlockOrigin,
|
||||
header: B::Header,
|
||||
justification: Option<Justification>,
|
||||
body: Option<Vec<B::Extrinsic>>,
|
||||
) -> Result<(ImportBlock<B>, Option<Vec<AuthorityIdFor<B>>>), String> {
|
||||
Ok((ImportBlock {
|
||||
origin,
|
||||
header,
|
||||
body,
|
||||
finalized: false,
|
||||
justification,
|
||||
post_digests: vec![],
|
||||
auxiliary: Vec::new(),
|
||||
fork_choice: ForkChoiceStrategy::LongestChain,
|
||||
}, None))
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn process_import_result_works() {
|
||||
let (result_sender, result_port) = channel::unbounded();
|
||||
let (worker_sender, _) = channel::unbounded();
|
||||
let (link_sender, link_port) = channel::unbounded();
|
||||
let importer_sender = BlockImporter::<Block>::new(result_port, worker_sender, None);
|
||||
let importer_sender = BlockImporter::<Block>::new(result_port, worker_sender, Arc::new(()), None, None, None);
|
||||
let link = TestLink::new(link_sender);
|
||||
let (ack_sender, start_ack_port) = channel::bounded(4);
|
||||
let _ = importer_sender.send(BlockImportMsg::Start(Box::new(link.clone()), ack_sender));
|
||||
@@ -687,52 +833,101 @@ mod tests {
|
||||
|
||||
// Send a known
|
||||
let results = vec![(Ok(BlockImportResult::ImportedKnown(Default::default())), Default::default())];
|
||||
let _ = result_sender.send(BlockImportWorkerMsg::Imported(results)).ok().unwrap();
|
||||
let _ = result_sender.send(BlockImportWorkerMsg::ImportedBlocks(results)).ok().unwrap();
|
||||
assert_eq!(link_port.recv(), Ok(LinkMsg::BlockImported));
|
||||
|
||||
// Send a second known
|
||||
let results = vec![(Ok(BlockImportResult::ImportedKnown(Default::default())), Default::default())];
|
||||
let _ = result_sender.send(BlockImportWorkerMsg::Imported(results)).ok().unwrap();
|
||||
let _ = result_sender.send(BlockImportWorkerMsg::ImportedBlocks(results)).ok().unwrap();
|
||||
assert_eq!(link_port.recv(), Ok(LinkMsg::BlockImported));
|
||||
|
||||
// Send an unknown
|
||||
let results = vec![(Ok(BlockImportResult::ImportedUnknown(Default::default(), Default::default(), None)), Default::default())];
|
||||
let _ = result_sender.send(BlockImportWorkerMsg::Imported(results)).ok().unwrap();
|
||||
let _ = result_sender.send(BlockImportWorkerMsg::ImportedBlocks(results)).ok().unwrap();
|
||||
assert_eq!(link_port.recv(), Ok(LinkMsg::BlockImported));
|
||||
|
||||
// Send an unknown with peer and bad justification
|
||||
let peer_id = PeerId::random();
|
||||
let results = vec![(Ok(BlockImportResult::ImportedUnknown(Default::default(),
|
||||
ImportedAux { needs_justification: true, clear_justification_requests: false, bad_justification: true },
|
||||
ImportedAux {
|
||||
needs_justification: true,
|
||||
clear_justification_requests: false,
|
||||
bad_justification: true,
|
||||
needs_finality_proof: false,
|
||||
},
|
||||
Some(peer_id.clone()))), Default::default())];
|
||||
let _ = result_sender.send(BlockImportWorkerMsg::Imported(results)).ok().unwrap();
|
||||
let _ = result_sender.send(BlockImportWorkerMsg::ImportedBlocks(results)).ok().unwrap();
|
||||
assert_eq!(link_port.recv(), Ok(LinkMsg::BlockImported));
|
||||
assert_eq!(link_port.recv(), Ok(LinkMsg::Disconnected));
|
||||
|
||||
// Send an incomplete header
|
||||
let results = vec![(Err(BlockImportError::IncompleteHeader(Some(peer_id.clone()))), Default::default())];
|
||||
let _ = result_sender.send(BlockImportWorkerMsg::Imported(results)).ok().unwrap();
|
||||
let _ = result_sender.send(BlockImportWorkerMsg::ImportedBlocks(results)).ok().unwrap();
|
||||
assert_eq!(link_port.recv(), Ok(LinkMsg::Disconnected));
|
||||
assert_eq!(link_port.recv(), Ok(LinkMsg::Restarted));
|
||||
|
||||
// Send an unknown parent
|
||||
let results = vec![(Err(BlockImportError::UnknownParent), Default::default())];
|
||||
let _ = result_sender.send(BlockImportWorkerMsg::Imported(results)).ok().unwrap();
|
||||
let _ = result_sender.send(BlockImportWorkerMsg::ImportedBlocks(results)).ok().unwrap();
|
||||
assert_eq!(link_port.recv(), Ok(LinkMsg::Restarted));
|
||||
|
||||
// Send a verification failed
|
||||
let results = vec![(Err(BlockImportError::VerificationFailed(Some(peer_id.clone()), String::new())), Default::default())];
|
||||
let _ = result_sender.send(BlockImportWorkerMsg::Imported(results)).ok().unwrap();
|
||||
let _ = result_sender.send(BlockImportWorkerMsg::ImportedBlocks(results)).ok().unwrap();
|
||||
assert_eq!(link_port.recv(), Ok(LinkMsg::Disconnected));
|
||||
assert_eq!(link_port.recv(), Ok(LinkMsg::Restarted));
|
||||
|
||||
// Send an error
|
||||
let results = vec![(Err(BlockImportError::Error), Default::default())];
|
||||
let _ = result_sender.send(BlockImportWorkerMsg::Imported(results)).ok().unwrap();
|
||||
let _ = result_sender.send(BlockImportWorkerMsg::ImportedBlocks(results)).ok().unwrap();
|
||||
assert_eq!(link_port.recv(), Ok(LinkMsg::Restarted));
|
||||
|
||||
// Drop the importer sender first, ensuring graceful shutdown.
|
||||
drop(importer_sender);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn process_finality_proof_import_result_works() {
|
||||
let (result_sender, result_port) = channel::unbounded();
|
||||
let (worker_sender, worker_receiver) = channel::unbounded();
|
||||
let (link_sender, link_port) = channel::unbounded();
|
||||
let importer_sender = BlockImporter::<Block>::new(result_port, worker_sender, Arc::new(()), None, None, None);
|
||||
let link = TestLink::new(link_sender);
|
||||
let (ack_sender, start_ack_port) = channel::bounded(4);
|
||||
let _ = importer_sender.send(BlockImportMsg::Start(Box::new(link.clone()), ack_sender));
|
||||
let who = Origin::random();
|
||||
|
||||
// Ensure the importer handles Start before any result messages.
|
||||
start_ack_port.recv().unwrap().unwrap();
|
||||
|
||||
// Send finality proof import request to BlockImporter
|
||||
importer_sender.send(BlockImportMsg::ImportFinalityProof(
|
||||
who.clone(),
|
||||
Default::default(),
|
||||
1,
|
||||
vec![42],
|
||||
)).unwrap();
|
||||
|
||||
// Wait until this request is redirected to the BlockImportWorker
|
||||
assert_eq!(worker_receiver.recv(), Ok(BlockImportWorkerMsg::ImportFinalityProof(
|
||||
who.clone(),
|
||||
Default::default(),
|
||||
1,
|
||||
vec![42],
|
||||
)));
|
||||
|
||||
// Send ack of proof import from BlockImportWorker to BlockImporter
|
||||
result_sender.send(BlockImportWorkerMsg::ImportedFinalityProof(
|
||||
who.clone(),
|
||||
(Default::default(), 0),
|
||||
Ok((Default::default(), 0)),
|
||||
)).unwrap();
|
||||
|
||||
// Wait for finality proof import result
|
||||
assert_eq!(link_port.recv(), Ok(LinkMsg::FinalityProofImported));
|
||||
|
||||
// Drop the importer sender first, ensuring graceful shutdown.
|
||||
drop(importer_sender);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -49,7 +49,8 @@ const MAX_BLOCK_SIZE: usize = 4 * 1024 * 1024 + 512;
|
||||
|
||||
pub use self::error::{Error, ErrorKind};
|
||||
pub use block_import::{
|
||||
BlockImport, BlockOrigin, ForkChoiceStrategy, ImportedAux, ImportBlock, ImportResult, JustificationImport,
|
||||
BlockImport, BlockOrigin, ForkChoiceStrategy, ImportedAux, ImportBlock, ImportResult,
|
||||
JustificationImport, FinalityProofImport, FinalityProofRequestBuilder,
|
||||
};
|
||||
pub use select_chain::SelectChain;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user