diff --git a/substrate/Cargo.lock b/substrate/Cargo.lock index b42da79f88..1fd3c18534 100644 --- a/substrate/Cargo.lock +++ b/substrate/Cargo.lock @@ -4869,6 +4869,7 @@ dependencies = [ name = "substrate-consensus-babe" version = "2.0.0" dependencies = [ + "derive_more 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "fork-tree 2.0.0", "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", @@ -4945,6 +4946,7 @@ dependencies = [ name = "substrate-consensus-pow" version = "2.0.0" dependencies = [ + "derive_more 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)", "futures-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "parity-scale-codec 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/substrate/core/consensus/babe/Cargo.toml b/substrate/core/consensus/babe/Cargo.toml index b1c2c31f7d..30b7c1f8d6 100644 --- a/substrate/core/consensus/babe/Cargo.toml +++ b/substrate/core/consensus/babe/Cargo.toml @@ -36,6 +36,7 @@ schnorrkel = { version = "0.8.5", features = ["preaudit_deprecated"] } rand = "0.7.2" merlin = "1.2.1" pdqselect = "0.1.0" +derive_more = "0.15.0" [dev-dependencies] keyring = { package = "substrate-keyring", path = "../../keyring" } diff --git a/substrate/core/consensus/babe/src/lib.rs b/substrate/core/consensus/babe/src/lib.rs index 0eacf1407e..287b26a300 100644 --- a/substrate/core/consensus/babe/src/lib.rs +++ b/substrate/core/consensus/babe/src/lib.rs @@ -66,7 +66,7 @@ use consensus_common::ImportResult; use consensus_common::import_queue::{ BoxJustificationImport, BoxFinalityProofImport, }; -use sr_primitives::{generic::{BlockId, OpaqueDigestItemId}, Justification}; +use sr_primitives::{generic::{BlockId, OpaqueDigestItemId}, Justification, RuntimeString}; use sr_primitives::traits::{ Block as BlockT, Header, DigestItemFor, ProvideRuntimeApi, Zero, @@ -102,6 +102,7 @@ use log::{warn, debug, info, trace}; use slots::{SlotWorker, SlotData, SlotInfo, SlotCompatible}; use epoch_changes::descendent_query; use header_metadata::HeaderMetadata; +use schnorrkel::SignatureError; mod aux_schema; mod verification; @@ -114,13 +115,71 @@ pub use babe_primitives::{ }; pub use epoch_changes::{EpochChanges, EpochChangesFor, SharedEpochChanges}; -macro_rules! babe_err { - ($($i: expr),+) => { - { - debug!(target: "babe", $($i),+); - format!($($i),+) - } - }; + +#[derive(derive_more::Display, Debug)] +enum Error { + #[display(fmt = "Multiple BABE pre-runtime digests, rejecting!")] + MultiplePreRuntimeDigests, + #[display(fmt = "No BABE pre-runtime digest found")] + NoPreRuntimeDigest, + #[display(fmt = "Multiple BABE epoch change digests, rejecting!")] + MultipleEpochChangeDigests, + #[display(fmt = "Could not extract timestamp and slot: {:?}", _0)] + Extraction(consensus_common::Error), + #[display(fmt = "Could not fetch epoch at {:?}", _0)] + FetchEpoch(B::Hash), + #[display(fmt = "Header {:?} rejected: too far in the future", _0)] + TooFarInFuture(B::Hash), + #[display(fmt = "Parent ({}) of {} unavailable. Cannot import", _0, _1)] + ParentUnavailable(B::Hash, B::Hash), + #[display(fmt = "Slot number must increase: parent slot: {}, this slot: {}", _0, _1)] + SlotNumberMustIncrease(u64, u64), + #[display(fmt = "Header {:?} has a bad seal", _0)] + HeaderBadSeal(B::Hash), + #[display(fmt = "Header {:?} is unsealed", _0)] + HeaderUnsealed(B::Hash), + #[display(fmt = "Slot author not found")] + SlotAuthorNotFound, + #[display(fmt = "Secondary slot assignments are disabled for the current epoch.")] + SecondarySlotAssignmentsDisabled, + #[display(fmt = "Bad signature on {:?}", _0)] + BadSignature(B::Hash), + #[display(fmt = "Invalid author: Expected secondary author: {:?}, got: {:?}.", _0, _1)] + InvalidAuthor(AuthorityId, AuthorityId), + #[display(fmt = "No secondary author expected.")] + NoSecondaryAuthorExpected, + #[display(fmt = "VRF verification of block by author {:?} failed: threshold {} exceeded", _0, _1)] + VRFVerificationOfBlockFailed(AuthorityId, u128), + #[display(fmt = "VRF verification failed: {:?}", _0)] + VRFVerificationFailed(SignatureError), + #[display(fmt = "Could not fetch parent header: {:?}", _0)] + FetchParentHeader(client::error::Error), + #[display(fmt = "Expected epoch change to happen at {:?}, s{}", _0, _1)] + ExpectedEpochChange(B::Hash, u64), + #[display(fmt = "Could not look up epoch: {:?}", _0)] + CouldNotLookUpEpoch(Box>), + #[display(fmt = "Block {} is not valid under any epoch.", _0)] + BlockNotValid(B::Hash), + #[display(fmt = "Unexpected epoch change")] + UnexpectedEpochChange, + #[display(fmt = "Parent block of {} has no associated weight", _0)] + ParentBlockNoAssociatedWeight(B::Hash), + #[display(fmt = "Checking inherents failed: {}", _0)] + CheckInherents(String), + Client(client::error::Error), + Runtime(RuntimeString), + ForkTree(Box>), +} + +impl std::convert::From> for String { + fn from(error: Error) -> String { + error.to_string() + } +} + +fn babe_err(error: Error) -> Error { + debug!(target: "babe", "{}", error); + error } macro_rules! babe_info { @@ -385,7 +444,7 @@ impl slots::SimpleSlotWorker for BabeWorker Result { self.env.init(block).map_err(|e| { - consensus_common::Error::ClientImport(format!("{:?}", e)).into() + consensus_common::Error::ClientImport(format!("{:?}", e)) }) } } @@ -410,7 +469,7 @@ impl SlotWorker for BabeWorker where /// Extract the BABE pre digest from the given header. Pre-runtime digests are /// mandatory, the function will return `Err` if none is found. -fn find_pre_digest(header: &H) -> Result +fn find_pre_digest(header: &B::Header) -> Result> { // genesis block doesn't contain a pre digest so let's generate a // dummy one to not break any invariants in the rest of the code @@ -425,17 +484,17 @@ fn find_pre_digest(header: &H) -> Result for log in header.digest().logs() { trace!(target: "babe", "Checking log {:?}, looking for pre runtime digest", log); match (log.as_babe_pre_digest(), pre_digest.is_some()) { - (Some(_), true) => Err(babe_err!("Multiple BABE pre-runtime digests, rejecting!"))?, + (Some(_), true) => return Err(babe_err(Error::MultiplePreRuntimeDigests)), (None, _) => trace!(target: "babe", "Ignoring digest not meant for us"), (s, false) => pre_digest = s, } } - pre_digest.ok_or_else(|| babe_err!("No BABE pre-runtime digest found")) + pre_digest.ok_or_else(|| babe_err(Error::NoPreRuntimeDigest)) } /// Extract the BABE epoch change digest from the given header, if it exists. fn find_next_epoch_digest(header: &B::Header) - -> Result, String> + -> Result, Error> where DigestItemFor: CompatibleDigestItem, { let mut epoch_digest: Option<_> = None; @@ -443,7 +502,7 @@ fn find_next_epoch_digest(header: &B::Header) trace!(target: "babe", "Checking log {:?}, looking for epoch change digest.", log); let log = log.try_to::(OpaqueDigestItemId::Consensus(&BABE_ENGINE_ID)); match (log, epoch_digest.is_some()) { - (Some(ConsensusLog::NextEpochData(_)), true) => Err(babe_err!("Multiple BABE epoch change digests, rejecting!"))?, + (Some(ConsensusLog::NextEpochData(_)), true) => return Err(babe_err(Error::MultipleEpochChangeDigests)), (Some(ConsensusLog::NextEpochData(epoch)), false) => epoch_digest = Some(epoch), _ => trace!(target: "babe", "Ignoring digest not meant for us"), } @@ -493,20 +552,20 @@ impl BabeVerifier { block: Block, block_id: BlockId, inherent_data: InherentData, - ) -> Result<(), String> + ) -> Result<(), Error> where PRA: ProvideRuntimeApi, PRA::Api: BlockBuilderApi { let inherent_res = self.api.runtime_api().check_inherents( &block_id, block, inherent_data, - ).map_err(|e| format!("{:?}", e))?; + ).map_err(Error::Client)?; if !inherent_res.ok() { inherent_res .into_errors() .try_for_each(|(i, e)| { - Err(self.inherent_data_providers.error_to_string(&i, &e)) + Err(Error::CheckInherents(self.inherent_data_providers.error_to_string(&i, &e))) }) } else { Ok(()) @@ -585,18 +644,18 @@ impl Verifier for BabeVerifier::Runtime)?; let (_, slot_now, _) = self.time_source.extract_timestamp_and_slot(&inherent_data) - .map_err(|e| format!("Could not extract timestamp and slot: {:?}", e))?; + .map_err(Error::::Extraction)?; let hash = header.hash(); let parent_hash = *header.parent_hash(); let parent_header_metadata = self.client.header_metadata(parent_hash) - .map_err(|e| format!("Could not fetch parent header: {:?}", e))?; + .map_err(Error::::FetchParentHeader)?; - let pre_digest = find_pre_digest::(&header)?; + let pre_digest = find_pre_digest::(&header)?; let epoch = { let epoch_changes = self.epoch_changes.lock(); epoch_changes.epoch_for_child_of( @@ -606,8 +665,8 @@ impl Verifier for BabeVerifier::ForkTree(Box::new(e)))? + .ok_or_else(|| Error::::FetchEpoch(parent_hash))? }; // We add one to the current slot to allow for some small drift. @@ -691,7 +750,7 @@ impl Verifier for BabeVerifier ?hash, "a" => ?a, "b" => ?b ); - Err(format!("Header {:?} rejected: too far in the future", hash)) + Err(Error::::TooFarInFuture(hash).into()) } } } @@ -787,10 +846,10 @@ impl BlockImport for BabeBlockImport return Ok(ImportResult::AlreadyInChain), Ok(blockchain::BlockStatus::Unknown) => {}, - Err(e) => return Err(ConsensusError::ClientImport(e.to_string()).into()), + Err(e) => return Err(ConsensusError::ClientImport(e.to_string())), } - let pre_digest = find_pre_digest::(&block.header) + let pre_digest = find_pre_digest::(&block.header) .expect("valid babe headers must contain a predigest; \ header has been already verified; qed"); let slot_number = pre_digest.slot_number(); @@ -798,13 +857,11 @@ impl BlockImport for BabeBlockImport::ParentUnavailable(parent_hash, hash) + ).into()))?; - let parent_slot = find_pre_digest::(&parent_header) + let parent_slot = find_pre_digest::(&parent_header) .map(|d| d.slot_number()) .expect("parent is non-genesis; valid BABE headers contain a pre-digest; \ header has already been verified; qed"); @@ -812,11 +869,9 @@ impl BlockImport for BabeBlockImport::SlotNumberMustIncrease(parent_slot, slot_number) + ).into()) ); } @@ -834,7 +889,7 @@ impl BlockImport for BabeBlockImport::ParentBlockNoAssociatedWeight(hash)).into() ))? }; @@ -846,10 +901,10 @@ impl BlockImport for BabeBlockImport| ConsensusError::ChainLookup( - babe_err!("Could not look up epoch: {:?}", e) + babe_err(Error::::CouldNotLookUpEpoch(Box::new(e))).into() ))? .ok_or_else(|| ConsensusError::ClientImport( - babe_err!("Block {} is not valid under any epoch.", hash) + babe_err(Error::::BlockNotValid(hash)).into() ))?; let first_in_epoch = parent_slot < epoch.as_ref().start_slot; @@ -860,7 +915,7 @@ impl BlockImport for BabeBlockImport(&block.header) - .map_err(|e| ConsensusError::from(ConsensusError::ClientImport(e.to_string())))?; + .map_err(|e| ConsensusError::ClientImport(e.to_string()))?; match (first_in_epoch, next_epoch_digest.is_some()) { (true, true) => {}, @@ -868,12 +923,12 @@ impl BlockImport for BabeBlockImport { return Err( ConsensusError::ClientImport( - babe_err!("Expected epoch change to happen at {:?}, s{}", hash, slot_number), + babe_err(Error::::ExpectedEpochChange(hash, slot_number)).into(), ) ); }, (false, true) => { - return Err(ConsensusError::ClientImport("Unexpected epoch change".into())); + return Err(ConsensusError::ClientImport(Error::::UnexpectedEpochChange.into())); }, } @@ -917,7 +972,7 @@ impl BlockImport for BabeBlockImport( .expect("best finalized hash was given by client; \ finalized headers must exist in db; qed"); - find_pre_digest::(&finalized_header) + find_pre_digest::(&finalized_header) .expect("finalized header must be valid; \ valid blocks have a pre-digest; qed") .slot_number() diff --git a/substrate/core/consensus/babe/src/tests.rs b/substrate/core/consensus/babe/src/tests.rs index e6883977a0..2e236f190b 100644 --- a/substrate/core/consensus/babe/src/tests.rs +++ b/substrate/core/consensus/babe/src/tests.rs @@ -81,7 +81,7 @@ impl Environment for DummyFactory { -> Result { - let parent_slot = crate::find_pre_digest(parent_header) + let parent_slot = crate::find_pre_digest::(parent_header) .expect("parent header has a pre-digest") .slot_number(); @@ -109,7 +109,7 @@ impl DummyProposer { Err(e) => return future::ready(Err(e)), }; - let this_slot = crate::find_pre_digest(block.header()) + let this_slot = crate::find_pre_digest::(block.header()) .expect("baked block has valid pre-digest") .slot_number(); @@ -535,7 +535,7 @@ fn propose_and_import_block( let mut proposer = proposer_factory.init(parent).unwrap(); let slot_number = slot_number.unwrap_or_else(|| { - let parent_pre_digest = find_pre_digest(parent).unwrap(); + let parent_pre_digest = find_pre_digest::(parent).unwrap(); parent_pre_digest.slot_number() + 1 }); diff --git a/substrate/core/consensus/babe/src/verification.rs b/substrate/core/consensus/babe/src/verification.rs index 05d6102450..36e34dfb95 100644 --- a/substrate/core/consensus/babe/src/verification.rs +++ b/substrate/core/consensus/babe/src/verification.rs @@ -22,7 +22,7 @@ use babe_primitives::{Epoch, BabePreDigest, CompatibleDigestItem, AuthorityId}; use babe_primitives::{AuthoritySignature, SlotNumber, AuthorityIndex, AuthorityPair}; use slots::CheckedHeader; use log::{debug, trace}; -use super::{find_pre_digest, BlockT}; +use super::{find_pre_digest, babe_err, BlockT, Error}; use super::authorship::{make_transcript, calculate_primary_threshold, check_primary_threshold, secondary_slot_author}; /// BABE verification parameters @@ -41,15 +41,6 @@ pub(super) struct VerificationParams<'a, B: 'a + BlockT> { pub(super) config: &'a super::Config, } -macro_rules! babe_err { - ($($i: expr),+) => { - { - debug!(target: "babe", $($i),+); - format!($($i),+) - } - }; -} - /// Check a header has been signed by the right key. If the slot is too far in /// the future, an error will be returned. If successful, returns the pre-header /// and the digest item containing the seal. @@ -63,7 +54,7 @@ macro_rules! babe_err { /// with each having different validation logic. pub(super) fn check_header( params: VerificationParams, -) -> Result>, String> where +) -> Result>, Error> where DigestItemFor: CompatibleDigestItem, { let VerificationParams { @@ -75,16 +66,16 @@ pub(super) fn check_header( } = params; let authorities = &epoch.authorities; - let pre_digest = pre_digest.map(Ok).unwrap_or_else(|| find_pre_digest::(&header))?; + let pre_digest = pre_digest.map(Ok).unwrap_or_else(|| find_pre_digest::(&header))?; trace!(target: "babe", "Checking header"); let seal = match header.digest_mut().pop() { Some(x) => x, - None => return Err(babe_err!("Header {:?} is unsealed", header.hash())), + None => return Err(babe_err(Error::HeaderUnsealed(header.hash()))), }; let sig = seal.as_babe_seal().ok_or_else(|| { - babe_err!("Header {:?} has a bad seal", header.hash()) + babe_err(Error::HeaderBadSeal(header.hash())) })?; // the pre-hash of the header doesn't include the seal @@ -98,7 +89,7 @@ pub(super) fn check_header( let author = match authorities.get(pre_digest.authority_index() as usize) { Some(author) => author.0.clone(), - None => return Err(babe_err!("Slot author not found")), + None => return Err(babe_err(Error::SlotAuthorNotFound)), }; match &pre_digest { @@ -128,7 +119,7 @@ pub(super) fn check_header( )?; }, _ => { - return Err(babe_err!("Secondary slot assignments are disabled for the current epoch.")); + return Err(babe_err(Error::SecondarySlotAssignmentsDisabled)); } } @@ -156,7 +147,7 @@ fn check_primary_header( signature: AuthoritySignature, epoch: &Epoch, c: (u64, u64), -) -> Result<(), String> { +) -> Result<(), Error> { let (vrf_output, vrf_proof, authority_index, slot_number) = pre_digest; let author = &epoch.authorities[authority_index as usize].0; @@ -172,7 +163,7 @@ fn check_primary_header( schnorrkel::PublicKey::from_bytes(author.as_slice()).and_then(|p| { p.vrf_verify(transcript, vrf_output, vrf_proof) }).map_err(|s| { - babe_err!("VRF verification failed: {:?}", s) + babe_err(Error::VRFVerificationFailed(s)) })? }; @@ -183,13 +174,12 @@ fn check_primary_header( ); if !check_primary_threshold(&inout, threshold) { - return Err(babe_err!("VRF verification of block by author {:?} failed: \ - threshold {} exceeded", author, threshold)); + return Err(babe_err(Error::VRFVerificationOfBlockFailed(author.clone(), threshold))); } Ok(()) } else { - Err(babe_err!("Bad signature on {:?}", pre_hash)) + Err(babe_err(Error::BadSignature(pre_hash))) } } @@ -202,7 +192,7 @@ fn check_secondary_header( pre_digest: (AuthorityIndex, SlotNumber), signature: AuthoritySignature, epoch: &Epoch, -) -> Result<(), String> { +) -> Result<(), Error> { let (authority_index, slot_number) = pre_digest; // check the signature is valid under the expected authority and @@ -211,22 +201,17 @@ fn check_secondary_header( slot_number, &epoch.authorities, epoch.randomness, - ).ok_or_else(|| "No secondary author expected.".to_string())?; + ).ok_or_else(|| Error::NoSecondaryAuthorExpected)?; let author = &epoch.authorities[authority_index as usize].0; if expected_author != author { - let msg = format!("Invalid author: Expected secondary author: {:?}, got: {:?}.", - expected_author, - author, - ); - - return Err(msg); + return Err(Error::InvalidAuthor(expected_author.clone(), author.clone())); } if AuthorityPair::verify(&signature, pre_hash.as_ref(), author) { Ok(()) } else { - Err(format!("Bad signature on {:?}", pre_hash)) + Err(Error::BadSignature(pre_hash)) } } diff --git a/substrate/core/consensus/pow/Cargo.toml b/substrate/core/consensus/pow/Cargo.toml index 54dd58c467..86efcbb95d 100644 --- a/substrate/core/consensus/pow/Cargo.toml +++ b/substrate/core/consensus/pow/Cargo.toml @@ -16,3 +16,4 @@ pow-primitives = { package = "substrate-consensus-pow-primitives", path = "primi consensus-common = { package = "substrate-consensus-common", path = "../common" } log = "0.4.8" futures-preview = { version = "0.3.0-alpha.19", features = ["compat"] } +derive_more = "0.15.0" diff --git a/substrate/core/consensus/pow/src/lib.rs b/substrate/core/consensus/pow/src/lib.rs index 766c1c63e0..040eb01d9c 100644 --- a/substrate/core/consensus/pow/src/lib.rs +++ b/substrate/core/consensus/pow/src/lib.rs @@ -37,7 +37,7 @@ use client::{ block_builder::api::BlockBuilder as BlockBuilderApi, backend::AuxStore, well_known_cache_keys::Id as CacheKeyId, }; -use sr_primitives::Justification; +use sr_primitives::{Justification, RuntimeString}; use sr_primitives::generic::{BlockId, Digest, DigestItem}; use sr_primitives::traits::{Block as BlockT, Header as HeaderT, ProvideRuntimeApi}; use srml_timestamp::{TimestampInherentData, InherentError as TIError}; @@ -46,12 +46,50 @@ use primitives::H256; use inherents::{InherentDataProviders, InherentData}; use consensus_common::{ BlockImportParams, BlockOrigin, ForkChoiceStrategy, SyncOracle, Environment, Proposer, - SelectChain, + SelectChain, Error as ConsensusError }; use consensus_common::import_queue::{BoxBlockImport, BasicQueue, Verifier}; use codec::{Encode, Decode}; use log::*; +#[derive(derive_more::Display, Debug)] +pub enum Error { + #[display(fmt = "Header uses the wrong engine {:?}", _0)] + WrongEngine([u8; 4]), + #[display(fmt = "Header {:?} is unsealed", _0)] + HeaderUnsealed(B::Hash), + #[display(fmt = "PoW validation error: invalid seal")] + InvalidSeal, + #[display(fmt = "Rejecting block too far in future")] + TooFarInFuture, + #[display(fmt = "Fetching best header failed using select chain: {:?}", _0)] + BestHeaderSelectChain(ConsensusError), + #[display(fmt = "Fetching best header failed: {:?}", _0)] + BestHeader(client::error::Error), + #[display(fmt = "Best header does not exist")] + NoBestHeader, + #[display(fmt = "Block proposing error: {:?}", _0)] + BlockProposingError(String), + #[display(fmt = "Fetch best hash failed via select chain: {:?}", _0)] + BestHashSelectChain(ConsensusError), + #[display(fmt = "Error with block built on {:?}: {:?}", _0, _1)] + BlockBuiltError(B::Hash, ConsensusError), + #[display(fmt = "Creating inherents failed: {}", _0)] + CreateInherents(RuntimeString), + #[display(fmt = "Checking inherents failed: {}", _0)] + CheckInherents(String), + Client(client::error::Error), + Codec(codec::Error), + Environment(String), + Runtime(RuntimeString) +} + +impl std::convert::From> for String { + fn from(error: Error) -> String { + error.to_string() + } +} + /// Auxiliary storage prefix for PoW engine. pub const POW_AUX_PREFIX: [u8; 4] = *b"PoW:"; @@ -74,12 +112,12 @@ impl PowAux where Difficulty: Decode + Default, { /// Read the auxiliary from client. - pub fn read(client: &C, hash: &H256) -> Result { + pub fn read(client: &C, hash: &H256) -> Result> { let key = aux_key(hash); - match client.get_aux(&key).map_err(|e| format!("{:?}", e))? { + match client.get_aux(&key).map_err(Error::Client)? { Some(bytes) => Self::decode(&mut &bytes[..]) - .map_err(|e| format!("{:?}", e)), + .map_err(Error::Codec), None => Ok(Self::default()), } } @@ -91,7 +129,7 @@ pub trait PowAlgorithm { type Difficulty: TotalDifficulty + Default + Encode + Decode + Ord + Clone + Copy; /// Get the next block's difficulty. - fn difficulty(&self, parent: &BlockId) -> Result; + fn difficulty(&self, parent: &BlockId) -> Result>; /// Verify proof of work against the given difficulty. fn verify( &self, @@ -99,7 +137,7 @@ pub trait PowAlgorithm { pre_hash: &H256, seal: &Seal, difficulty: Self::Difficulty, - ) -> Result; + ) -> Result>; /// Mine a seal that satisfies the given difficulty. fn mine( &self, @@ -107,7 +145,7 @@ pub trait PowAlgorithm { pre_hash: &H256, difficulty: Self::Difficulty, round: u32, - ) -> Result, String>; + ) -> Result, Error>; } /// A verifier for PoW blocks. @@ -134,7 +172,7 @@ impl, C, S, Algorithm> PowVerifier { &self, mut header: B::Header, parent_block_id: BlockId, - ) -> Result<(B::Header, Algorithm::Difficulty, DigestItem), String> where + ) -> Result<(B::Header, Algorithm::Difficulty, DigestItem), Error> where Algorithm: PowAlgorithm, { let hash = header.hash(); @@ -144,10 +182,10 @@ impl, C, S, Algorithm> PowVerifier { if id == POW_ENGINE_ID { (DigestItem::Seal(id, seal.clone()), seal) } else { - return Err(format!("Header uses the wrong engine {:?}", id)) + return Err(Error::WrongEngine(id)) } }, - _ => return Err(format!("Header {:?} is unsealed", hash)), + _ => return Err(Error::HeaderUnsealed(hash)), }; let pre_hash = header.hash(); @@ -159,7 +197,7 @@ impl, C, S, Algorithm> PowVerifier { &inner_seal, difficulty, )? { - return Err("PoW validation error: invalid seal".into()); + return Err(Error::InvalidSeal); } Ok((header, difficulty, seal)) @@ -171,7 +209,7 @@ impl, C, S, Algorithm> PowVerifier { block_id: BlockId, inherent_data: InherentData, timestamp_now: u64, - ) -> Result<(), String> where + ) -> Result<(), Error> where C: ProvideRuntimeApi, C::Api: BlockBuilderApi { const MAX_TIMESTAMP_DRIFT_SECS: u64 = 60; @@ -184,7 +222,7 @@ impl, C, S, Algorithm> PowVerifier { &block_id, block, inherent_data, - ).map_err(|e| format!("{:?}", e))?; + ).map_err(Error::Client)?; if !inherent_res.ok() { inherent_res @@ -192,13 +230,15 @@ impl, C, S, Algorithm> PowVerifier { .try_for_each(|(i, e)| match TIError::try_from(&i, &e) { Some(TIError::ValidAtTimestamp(timestamp)) => { if timestamp > timestamp_now + MAX_TIMESTAMP_DRIFT_SECS { - return Err("Rejecting block too far in future".into()); + return Err(Error::TooFarInFuture); } Ok(()) }, - Some(TIError::Other(e)) => Err(e.into()), - None => Err(self.inherent_data_providers.error_to_string(&i, &e)), + Some(TIError::Other(e)) => Err(Error::Runtime(e)), + None => Err(Error::CheckInherents( + self.inherent_data_providers.error_to_string(&i, &e) + )), }) } else { Ok(()) @@ -231,8 +271,8 @@ impl, C, S, Algorithm> Verifier for PowVerifier(self.client.as_ref(), &best_hash)?; + let mut aux = PowAux::read::<_, B>(self.client.as_ref(), &parent_hash)?; let (checked_header, difficulty, seal) = self.check_header( header, @@ -390,7 +430,7 @@ fn mine_loop, C, Algorithm, E, SO, S>( build_time: std::time::Duration, select_chain: Option<&S>, inherent_data_providers: &inherents::InherentDataProviders, -) -> Result<(), String> where +) -> Result<(), Error> where C: HeaderBackend + AuxStore, Algorithm: PowAlgorithm, E: Environment, @@ -408,23 +448,24 @@ fn mine_loop, C, Algorithm, E, SO, S>( let (best_hash, best_header) = match select_chain { Some(select_chain) => { let header = select_chain.best_chain() - .map_err(|e| format!("Fetching best header failed using select chain: {:?}", e))?; + .map_err(Error::BestHeaderSelectChain)?; let hash = header.hash(); (hash, header) }, None => { let hash = client.info().best_hash; let header = client.header(BlockId::Hash(hash)) - .map_err(|e| format!("Fetching best header failed: {:?}", e))? - .ok_or("Best header does not exist")?; + .map_err(Error::BestHeader)? + .ok_or(Error::NoBestHeader)?; (hash, header) }, }; let mut aux = PowAux::read(client, &best_hash)?; - let mut proposer = env.init(&best_header).map_err(|e| format!("{:?}", e))?; + let mut proposer = env.init(&best_header) + .map_err(|e| Error::Environment(format!("{:?}", e)))?; let inherent_data = inherent_data_providers - .create_inherent_data().map_err(String::from)?; + .create_inherent_data().map_err(Error::CreateInherents)?; let mut inherent_digest = Digest::default(); if let Some(preruntime) = &preruntime { inherent_digest.push(DigestItem::PreRuntime(POW_ENGINE_ID, preruntime.to_vec())); @@ -433,7 +474,7 @@ fn mine_loop, C, Algorithm, E, SO, S>( inherent_data, inherent_digest, build_time.clone(), - )).map_err(|e| format!("Block proposing error: {:?}", e))?; + )).map_err(|e| Error::BlockProposingError(format!("{:?}", e)))?; let (header, body) = block.deconstruct(); let (difficulty, seal) = { @@ -470,7 +511,7 @@ fn mine_loop, C, Algorithm, E, SO, S>( let key = aux_key(&hash); let best_hash = match select_chain { Some(select_chain) => select_chain.best_chain() - .map_err(|e| format!("Fetch best hash failed via select chain: {:?}", e))? + .map_err(Error::BestHashSelectChain)? .hash(), None => client.info().best_hash, }; @@ -493,6 +534,6 @@ fn mine_loop, C, Algorithm, E, SO, S>( }; block_import.import_block(import_block, HashMap::default()) - .map_err(|e| format!("Error with block built on {:?}: {:?}", best_hash, e))?; + .map_err(|e| Error::BlockBuiltError(best_hash, e))?; } }