diff --git a/substrate/client/consensus/pow/src/lib.rs b/substrate/client/consensus/pow/src/lib.rs index ca7285b7fe..87f51be216 100644 --- a/substrate/client/consensus/pow/src/lib.rs +++ b/substrate/client/consensus/pow/src/lib.rs @@ -30,6 +30,8 @@ //! clients. use std::sync::Arc; +use std::any::Any; +use std::borrow::Cow; use std::thread; use std::collections::HashMap; use std::marker::PhantomData; @@ -63,8 +65,6 @@ pub enum Error { InvalidSeal, #[display(fmt = "PoW validation error: invalid difficulty")] InvalidDifficulty, - #[display(fmt = "PoW block import expects an intermediate, but not found one")] - NoIntermediate, #[display(fmt = "Rejecting block too far in future")] TooFarInFuture, #[display(fmt = "Fetching best header failed using select chain: {:?}", _0)] @@ -257,6 +257,7 @@ impl BlockImport for PowBlockImport + Send + Sync + HeaderBackend + AuxStore + ProvideCache + BlockOf, C::Api: BlockBuilderApi, Algorithm: PowAlgorithm, + Algorithm::Difficulty: 'static, { type Error = ConsensusError; type Transaction = sp_api::TransactionFor; @@ -312,10 +313,9 @@ impl BlockImport for PowBlockImport return Err(Error::::HeaderUnsealed(block.header.hash()).into()), }; - let intermediate = PowIntermediate::::decode( - &mut &block.intermediates.remove(INTERMEDIATE_KEY) - .ok_or(Error::::NoIntermediate)?[..] - ).map_err(|_| Error::::NoIntermediate)?; + let intermediate = block.take_intermediate::>( + INTERMEDIATE_KEY + )?; let difficulty = match intermediate.difficulty { Some(difficulty) => difficulty, @@ -392,6 +392,7 @@ impl PowVerifier { impl Verifier for PowVerifier where Algorithm: PowAlgorithm + Send + Sync, + Algorithm::Difficulty: 'static, { fn verify( &mut self, @@ -418,7 +419,7 @@ impl Verifier for PowVerifier where justification, intermediates: { let mut ret = HashMap::new(); - ret.insert(INTERMEDIATE_KEY.to_vec(), intermediate.encode()); + ret.insert(Cow::from(INTERMEDIATE_KEY), Box::new(intermediate) as Box); ret }, auxiliary: vec![], @@ -553,6 +554,7 @@ fn mine_loop( ) -> Result<(), Error> where C: HeaderBackend + AuxStore + ProvideRuntimeApi, Algorithm: PowAlgorithm, + Algorithm::Difficulty: 'static, E: Environment, E::Proposer: Proposer>, E::Error: std::fmt::Debug, @@ -659,7 +661,7 @@ fn mine_loop( storage_changes: Some(proposal.storage_changes), intermediates: { let mut ret = HashMap::new(); - ret.insert(INTERMEDIATE_KEY.to_vec(), intermediate.encode()); + ret.insert(Cow::from(INTERMEDIATE_KEY), Box::new(intermediate) as Box); ret }, finalized: false, diff --git a/substrate/primitives/consensus/common/src/block_import.rs b/substrate/primitives/consensus/common/src/block_import.rs index af1b61a9fe..952a044e9b 100644 --- a/substrate/primitives/consensus/common/src/block_import.rs +++ b/substrate/primitives/consensus/common/src/block_import.rs @@ -22,7 +22,9 @@ use serde::{Serialize, Deserialize}; use std::borrow::Cow; use std::collections::HashMap; use std::sync::Arc; +use std::any::Any; +use crate::Error; use crate::import_queue::{Verifier, CacheKeyId}; /// Block import result. @@ -144,7 +146,7 @@ pub struct BlockImportParams { /// Intermediate values that are interpreted by block importers. Each block importer, /// upon handling a value, removes it from the intermediate list. The final block importer /// rejects block import if there are still intermediate values that remain unhandled. - pub intermediates: HashMap, Vec>, + pub intermediates: HashMap, Box>, /// Auxiliary consensus data produced by the block. /// Contains a list of key-value pairs. If values are `None`, the keys /// will be deleted. @@ -223,6 +225,36 @@ impl BlockImportParams { import_existing: self.import_existing, } } + + /// Take interemdiate by given key, and remove it from the processing list. + pub fn take_intermediate(&mut self, key: &[u8]) -> Result, Error> { + if self.intermediates.contains_key(key) { + self.intermediates.remove(key) + .ok_or(Error::NoIntermediate) + .and_then(|value| { + value.downcast::() + .map_err(|_| Error::InvalidIntermediate) + }) + } else { + Err(Error::NoIntermediate) + } + } + + /// Get a reference to a given intermediate. + pub fn intermediate(&self, key: &[u8]) -> Result<&T, Error> { + self.intermediates.get(key) + .ok_or(Error::NoIntermediate)? + .downcast_ref::() + .ok_or(Error::InvalidIntermediate) + } + + /// Get a mutable reference to a given intermediate. + pub fn intermediate_mut(&mut self, key: &[u8]) -> Result<&mut T, Error> { + self.intermediates.get_mut(key) + .ok_or(Error::NoIntermediate)? + .downcast_mut::() + .ok_or(Error::InvalidIntermediate) + } } /// Block import trait. diff --git a/substrate/primitives/consensus/common/src/error.rs b/substrate/primitives/consensus/common/src/error.rs index 972e4a2d48..c802831d65 100644 --- a/substrate/primitives/consensus/common/src/error.rs +++ b/substrate/primitives/consensus/common/src/error.rs @@ -31,6 +31,12 @@ pub enum Error { /// I/O terminated unexpectedly #[display(fmt="I/O terminated unexpectedly.")] IoTerminated, + /// Intermediate missing. + #[display(fmt="Missing intermediate.")] + NoIntermediate, + /// Intermediate is of wrong type. + #[display(fmt="Invalid intermediate.")] + InvalidIntermediate, /// Unable to schedule wakeup. #[display(fmt="Timer error: {}", _0)] FaultyTimer(std::io::Error),