Skip to content
This repository was archived by the owner on Nov 15, 2023. It is now read-only.

Commit 0b2606e

Browse files
expensesbkchr
authored andcommitted
Add error types to BABE and PoW (#3827)
* Add an error type to Babe * Add an error type to PoW * Simplify error enum variant names * Update core/consensus/babe/src/lib.rs Co-Authored-By: Bastian Köcher <bkchr@users.noreply.github.com> * Add missing newline * Split up DataProvider into CreateInherents and CheckInherents
1 parent 0cd7260 commit 0b2606e

File tree

7 files changed

+191
-106
lines changed

7 files changed

+191
-106
lines changed

Cargo.lock

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

core/consensus/babe/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ schnorrkel = { version = "0.8.5", features = ["preaudit_deprecated"] }
3636
rand = "0.7.2"
3737
merlin = "1.2.1"
3838
pdqselect = "0.1.0"
39+
derive_more = "0.15.0"
3940

4041
[dev-dependencies]
4142
keyring = { package = "substrate-keyring", path = "../../keyring" }

core/consensus/babe/src/lib.rs

Lines changed: 100 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ use consensus_common::ImportResult;
6666
use consensus_common::import_queue::{
6767
BoxJustificationImport, BoxFinalityProofImport,
6868
};
69-
use sr_primitives::{generic::{BlockId, OpaqueDigestItemId}, Justification};
69+
use sr_primitives::{generic::{BlockId, OpaqueDigestItemId}, Justification, RuntimeString};
7070
use sr_primitives::traits::{
7171
Block as BlockT, Header, DigestItemFor, ProvideRuntimeApi,
7272
Zero,
@@ -102,6 +102,7 @@ use log::{warn, debug, info, trace};
102102
use slots::{SlotWorker, SlotData, SlotInfo, SlotCompatible};
103103
use epoch_changes::descendent_query;
104104
use header_metadata::HeaderMetadata;
105+
use schnorrkel::SignatureError;
105106

106107
mod aux_schema;
107108
mod verification;
@@ -114,13 +115,71 @@ pub use babe_primitives::{
114115
};
115116
pub use epoch_changes::{EpochChanges, EpochChangesFor, SharedEpochChanges};
116117

117-
macro_rules! babe_err {
118-
($($i: expr),+) => {
119-
{
120-
debug!(target: "babe", $($i),+);
121-
format!($($i),+)
122-
}
123-
};
118+
119+
#[derive(derive_more::Display, Debug)]
120+
enum Error<B: BlockT> {
121+
#[display(fmt = "Multiple BABE pre-runtime digests, rejecting!")]
122+
MultiplePreRuntimeDigests,
123+
#[display(fmt = "No BABE pre-runtime digest found")]
124+
NoPreRuntimeDigest,
125+
#[display(fmt = "Multiple BABE epoch change digests, rejecting!")]
126+
MultipleEpochChangeDigests,
127+
#[display(fmt = "Could not extract timestamp and slot: {:?}", _0)]
128+
Extraction(consensus_common::Error),
129+
#[display(fmt = "Could not fetch epoch at {:?}", _0)]
130+
FetchEpoch(B::Hash),
131+
#[display(fmt = "Header {:?} rejected: too far in the future", _0)]
132+
TooFarInFuture(B::Hash),
133+
#[display(fmt = "Parent ({}) of {} unavailable. Cannot import", _0, _1)]
134+
ParentUnavailable(B::Hash, B::Hash),
135+
#[display(fmt = "Slot number must increase: parent slot: {}, this slot: {}", _0, _1)]
136+
SlotNumberMustIncrease(u64, u64),
137+
#[display(fmt = "Header {:?} has a bad seal", _0)]
138+
HeaderBadSeal(B::Hash),
139+
#[display(fmt = "Header {:?} is unsealed", _0)]
140+
HeaderUnsealed(B::Hash),
141+
#[display(fmt = "Slot author not found")]
142+
SlotAuthorNotFound,
143+
#[display(fmt = "Secondary slot assignments are disabled for the current epoch.")]
144+
SecondarySlotAssignmentsDisabled,
145+
#[display(fmt = "Bad signature on {:?}", _0)]
146+
BadSignature(B::Hash),
147+
#[display(fmt = "Invalid author: Expected secondary author: {:?}, got: {:?}.", _0, _1)]
148+
InvalidAuthor(AuthorityId, AuthorityId),
149+
#[display(fmt = "No secondary author expected.")]
150+
NoSecondaryAuthorExpected,
151+
#[display(fmt = "VRF verification of block by author {:?} failed: threshold {} exceeded", _0, _1)]
152+
VRFVerificationOfBlockFailed(AuthorityId, u128),
153+
#[display(fmt = "VRF verification failed: {:?}", _0)]
154+
VRFVerificationFailed(SignatureError),
155+
#[display(fmt = "Could not fetch parent header: {:?}", _0)]
156+
FetchParentHeader(client::error::Error),
157+
#[display(fmt = "Expected epoch change to happen at {:?}, s{}", _0, _1)]
158+
ExpectedEpochChange(B::Hash, u64),
159+
#[display(fmt = "Could not look up epoch: {:?}", _0)]
160+
CouldNotLookUpEpoch(Box<fork_tree::Error<client::error::Error>>),
161+
#[display(fmt = "Block {} is not valid under any epoch.", _0)]
162+
BlockNotValid(B::Hash),
163+
#[display(fmt = "Unexpected epoch change")]
164+
UnexpectedEpochChange,
165+
#[display(fmt = "Parent block of {} has no associated weight", _0)]
166+
ParentBlockNoAssociatedWeight(B::Hash),
167+
#[display(fmt = "Checking inherents failed: {}", _0)]
168+
CheckInherents(String),
169+
Client(client::error::Error),
170+
Runtime(RuntimeString),
171+
ForkTree(Box<fork_tree::Error<client::error::Error>>),
172+
}
173+
174+
impl<B: BlockT> std::convert::From<Error<B>> for String {
175+
fn from(error: Error<B>) -> String {
176+
error.to_string()
177+
}
178+
}
179+
180+
fn babe_err<B: BlockT>(error: Error<B>) -> Error<B> {
181+
debug!(target: "babe", "{}", error);
182+
error
124183
}
125184

126185
macro_rules! babe_info {
@@ -385,7 +444,7 @@ impl<B, C, E, I, Error, SO> slots::SimpleSlotWorker<B> for BabeWorker<B, C, E, I
385444

386445
fn proposer(&mut self, block: &B::Header) -> Result<Self::Proposer, consensus_common::Error> {
387446
self.env.init(block).map_err(|e| {
388-
consensus_common::Error::ClientImport(format!("{:?}", e)).into()
447+
consensus_common::Error::ClientImport(format!("{:?}", e))
389448
})
390449
}
391450
}
@@ -410,7 +469,7 @@ impl<B, C, E, I, Error, SO> SlotWorker<B> for BabeWorker<B, C, E, I, SO> where
410469

411470
/// Extract the BABE pre digest from the given header. Pre-runtime digests are
412471
/// mandatory, the function will return `Err` if none is found.
413-
fn find_pre_digest<H: Header>(header: &H) -> Result<BabePreDigest, String>
472+
fn find_pre_digest<B: BlockT>(header: &B::Header) -> Result<BabePreDigest, Error<B>>
414473
{
415474
// genesis block doesn't contain a pre digest so let's generate a
416475
// dummy one to not break any invariants in the rest of the code
@@ -425,25 +484,25 @@ fn find_pre_digest<H: Header>(header: &H) -> Result<BabePreDigest, String>
425484
for log in header.digest().logs() {
426485
trace!(target: "babe", "Checking log {:?}, looking for pre runtime digest", log);
427486
match (log.as_babe_pre_digest(), pre_digest.is_some()) {
428-
(Some(_), true) => Err(babe_err!("Multiple BABE pre-runtime digests, rejecting!"))?,
487+
(Some(_), true) => return Err(babe_err(Error::MultiplePreRuntimeDigests)),
429488
(None, _) => trace!(target: "babe", "Ignoring digest not meant for us"),
430489
(s, false) => pre_digest = s,
431490
}
432491
}
433-
pre_digest.ok_or_else(|| babe_err!("No BABE pre-runtime digest found"))
492+
pre_digest.ok_or_else(|| babe_err(Error::NoPreRuntimeDigest))
434493
}
435494

436495
/// Extract the BABE epoch change digest from the given header, if it exists.
437496
fn find_next_epoch_digest<B: BlockT>(header: &B::Header)
438-
-> Result<Option<NextEpochDescriptor>, String>
497+
-> Result<Option<NextEpochDescriptor>, Error<B>>
439498
where DigestItemFor<B>: CompatibleDigestItem,
440499
{
441500
let mut epoch_digest: Option<_> = None;
442501
for log in header.digest().logs() {
443502
trace!(target: "babe", "Checking log {:?}, looking for epoch change digest.", log);
444503
let log = log.try_to::<ConsensusLog>(OpaqueDigestItemId::Consensus(&BABE_ENGINE_ID));
445504
match (log, epoch_digest.is_some()) {
446-
(Some(ConsensusLog::NextEpochData(_)), true) => Err(babe_err!("Multiple BABE epoch change digests, rejecting!"))?,
505+
(Some(ConsensusLog::NextEpochData(_)), true) => return Err(babe_err(Error::MultipleEpochChangeDigests)),
447506
(Some(ConsensusLog::NextEpochData(epoch)), false) => epoch_digest = Some(epoch),
448507
_ => trace!(target: "babe", "Ignoring digest not meant for us"),
449508
}
@@ -493,20 +552,20 @@ impl<B, E, Block: BlockT, RA, PRA> BabeVerifier<B, E, Block, RA, PRA> {
493552
block: Block,
494553
block_id: BlockId<Block>,
495554
inherent_data: InherentData,
496-
) -> Result<(), String>
555+
) -> Result<(), Error<Block>>
497556
where PRA: ProvideRuntimeApi, PRA::Api: BlockBuilderApi<Block>
498557
{
499558
let inherent_res = self.api.runtime_api().check_inherents(
500559
&block_id,
501560
block,
502561
inherent_data,
503-
).map_err(|e| format!("{:?}", e))?;
562+
).map_err(Error::Client)?;
504563

505564
if !inherent_res.ok() {
506565
inherent_res
507566
.into_errors()
508567
.try_for_each(|(i, e)| {
509-
Err(self.inherent_data_providers.error_to_string(&i, &e))
568+
Err(Error::CheckInherents(self.inherent_data_providers.error_to_string(&i, &e)))
510569
})
511570
} else {
512571
Ok(())
@@ -585,18 +644,18 @@ impl<B, E, Block, RA, PRA> Verifier<Block> for BabeVerifier<B, E, Block, RA, PRA
585644
let mut inherent_data = self
586645
.inherent_data_providers
587646
.create_inherent_data()
588-
.map_err(String::from)?;
647+
.map_err( Error::<Block>::Runtime)?;
589648

590649
let (_, slot_now, _) = self.time_source.extract_timestamp_and_slot(&inherent_data)
591-
.map_err(|e| format!("Could not extract timestamp and slot: {:?}", e))?;
650+
.map_err(Error::<Block>::Extraction)?;
592651

593652
let hash = header.hash();
594653
let parent_hash = *header.parent_hash();
595654

596655
let parent_header_metadata = self.client.header_metadata(parent_hash)
597-
.map_err(|e| format!("Could not fetch parent header: {:?}", e))?;
656+
.map_err(Error::<Block>::FetchParentHeader)?;
598657

599-
let pre_digest = find_pre_digest::<Block::Header>(&header)?;
658+
let pre_digest = find_pre_digest::<Block>(&header)?;
600659
let epoch = {
601660
let epoch_changes = self.epoch_changes.lock();
602661
epoch_changes.epoch_for_child_of(
@@ -606,8 +665,8 @@ impl<B, E, Block, RA, PRA> Verifier<Block> for BabeVerifier<B, E, Block, RA, PRA
606665
pre_digest.slot_number(),
607666
|slot| self.config.genesis_epoch(slot),
608667
)
609-
.map_err(|e| format!("{:?}", e))?
610-
.ok_or_else(|| format!("Could not fetch epoch at {:?}", parent_hash))?
668+
.map_err(|e| Error::<Block>::ForkTree(Box::new(e)))?
669+
.ok_or_else(|| Error::<Block>::FetchEpoch(parent_hash))?
611670
};
612671

613672
// We add one to the current slot to allow for some small drift.
@@ -691,7 +750,7 @@ impl<B, E, Block, RA, PRA> Verifier<Block> for BabeVerifier<B, E, Block, RA, PRA
691750
telemetry!(CONSENSUS_DEBUG; "babe.header_too_far_in_future";
692751
"hash" => ?hash, "a" => ?a, "b" => ?b
693752
);
694-
Err(format!("Header {:?} rejected: too far in the future", hash))
753+
Err(Error::<Block>::TooFarInFuture(hash).into())
695754
}
696755
}
697756
}
@@ -787,36 +846,32 @@ impl<B, E, Block, I, RA, PRA> BlockImport<Block> for BabeBlockImport<B, E, Block
787846
match self.client.status(BlockId::Hash(hash)) {
788847
Ok(blockchain::BlockStatus::InChain) => return Ok(ImportResult::AlreadyInChain),
789848
Ok(blockchain::BlockStatus::Unknown) => {},
790-
Err(e) => return Err(ConsensusError::ClientImport(e.to_string()).into()),
849+
Err(e) => return Err(ConsensusError::ClientImport(e.to_string())),
791850
}
792851

793-
let pre_digest = find_pre_digest::<Block::Header>(&block.header)
852+
let pre_digest = find_pre_digest::<Block>(&block.header)
794853
.expect("valid babe headers must contain a predigest; \
795854
header has been already verified; qed");
796855
let slot_number = pre_digest.slot_number();
797856

798857
let parent_hash = *block.header.parent_hash();
799858
let parent_header = self.client.header(&BlockId::Hash(parent_hash))
800859
.map_err(|e| ConsensusError::ChainLookup(e.to_string()))?
801-
.ok_or_else(|| ConsensusError::ChainLookup(babe_err!(
802-
"Parent ({}) of {} unavailable. Cannot import",
803-
parent_hash,
804-
hash
805-
)))?;
860+
.ok_or_else(|| ConsensusError::ChainLookup(babe_err(
861+
Error::<Block>::ParentUnavailable(parent_hash, hash)
862+
).into()))?;
806863

807-
let parent_slot = find_pre_digest::<Block::Header>(&parent_header)
864+
let parent_slot = find_pre_digest::<Block>(&parent_header)
808865
.map(|d| d.slot_number())
809866
.expect("parent is non-genesis; valid BABE headers contain a pre-digest; \
810867
header has already been verified; qed");
811868

812869
// make sure that slot number is strictly increasing
813870
if slot_number <= parent_slot {
814871
return Err(
815-
ConsensusError::ClientImport(babe_err!(
816-
"Slot number must increase: parent slot: {}, this slot: {}",
817-
parent_slot,
818-
slot_number
819-
))
872+
ConsensusError::ClientImport(babe_err(
873+
Error::<Block>::SlotNumberMustIncrease(parent_slot, slot_number)
874+
).into())
820875
);
821876
}
822877

@@ -834,7 +889,7 @@ impl<B, E, Block, I, RA, PRA> BlockImport<Block> for BabeBlockImport<B, E, Block
834889
aux_schema::load_block_weight(&*self.client, parent_hash)
835890
.map_err(|e| ConsensusError::ClientImport(e.to_string()))?
836891
.ok_or_else(|| ConsensusError::ClientImport(
837-
babe_err!("Parent block of {} has no associated weight", hash)
892+
babe_err(Error::<Block>::ParentBlockNoAssociatedWeight(hash)).into()
838893
))?
839894
};
840895

@@ -846,10 +901,10 @@ impl<B, E, Block, I, RA, PRA> BlockImport<Block> for BabeBlockImport<B, E, Block
846901
|slot| self.config.genesis_epoch(slot),
847902
)
848903
.map_err(|e: fork_tree::Error<client::error::Error>| ConsensusError::ChainLookup(
849-
babe_err!("Could not look up epoch: {:?}", e)
904+
babe_err(Error::<Block>::CouldNotLookUpEpoch(Box::new(e))).into()
850905
))?
851906
.ok_or_else(|| ConsensusError::ClientImport(
852-
babe_err!("Block {} is not valid under any epoch.", hash)
907+
babe_err(Error::<Block>::BlockNotValid(hash)).into()
853908
))?;
854909

855910
let first_in_epoch = parent_slot < epoch.as_ref().start_slot;
@@ -860,20 +915,20 @@ impl<B, E, Block, I, RA, PRA> BlockImport<Block> for BabeBlockImport<B, E, Block
860915

861916
// search for this all the time so we can reject unexpected announcements.
862917
let next_epoch_digest = find_next_epoch_digest::<Block>(&block.header)
863-
.map_err(|e| ConsensusError::from(ConsensusError::ClientImport(e.to_string())))?;
918+
.map_err(|e| ConsensusError::ClientImport(e.to_string()))?;
864919

865920
match (first_in_epoch, next_epoch_digest.is_some()) {
866921
(true, true) => {},
867922
(false, false) => {},
868923
(true, false) => {
869924
return Err(
870925
ConsensusError::ClientImport(
871-
babe_err!("Expected epoch change to happen at {:?}, s{}", hash, slot_number),
926+
babe_err(Error::<Block>::ExpectedEpochChange(hash, slot_number)).into(),
872927
)
873928
);
874929
},
875930
(false, true) => {
876-
return Err(ConsensusError::ClientImport("Unexpected epoch change".into()));
931+
return Err(ConsensusError::ClientImport(Error::<Block>::UnexpectedEpochChange.into()));
877932
},
878933
}
879934

@@ -917,7 +972,7 @@ impl<B, E, Block, I, RA, PRA> BlockImport<Block> for BabeBlockImport<B, E, Block
917972
};
918973

919974
if let Err(e) = prune_and_import() {
920-
babe_err!("Failed to launch next epoch: {:?}", e);
975+
debug!(target: "babe", "Failed to launch next epoch: {:?}", e);
921976
*epoch_changes = old_epoch_changes.expect("set `Some` above and not taken; qed");
922977
return Err(e);
923978
}
@@ -1004,7 +1059,7 @@ fn prune_finalized<B, E, Block, RA>(
10041059
.expect("best finalized hash was given by client; \
10051060
finalized headers must exist in db; qed");
10061061

1007-
find_pre_digest::<Block::Header>(&finalized_header)
1062+
find_pre_digest::<Block>(&finalized_header)
10081063
.expect("finalized header must be valid; \
10091064
valid blocks have a pre-digest; qed")
10101065
.slot_number()

core/consensus/babe/src/tests.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ impl Environment<TestBlock> for DummyFactory {
8181
-> Result<DummyProposer, Error>
8282
{
8383

84-
let parent_slot = crate::find_pre_digest(parent_header)
84+
let parent_slot = crate::find_pre_digest::<TestBlock>(parent_header)
8585
.expect("parent header has a pre-digest")
8686
.slot_number();
8787

@@ -109,7 +109,7 @@ impl DummyProposer {
109109
Err(e) => return future::ready(Err(e)),
110110
};
111111

112-
let this_slot = crate::find_pre_digest(block.header())
112+
let this_slot = crate::find_pre_digest::<TestBlock>(block.header())
113113
.expect("baked block has valid pre-digest")
114114
.slot_number();
115115

@@ -535,7 +535,7 @@ fn propose_and_import_block(
535535
let mut proposer = proposer_factory.init(parent).unwrap();
536536

537537
let slot_number = slot_number.unwrap_or_else(|| {
538-
let parent_pre_digest = find_pre_digest(parent).unwrap();
538+
let parent_pre_digest = find_pre_digest::<TestBlock>(parent).unwrap();
539539
parent_pre_digest.slot_number() + 1
540540
});
541541

0 commit comments

Comments
 (0)