Add a new host function for reporting fatal errors; make WASM backtraces readable when printing out errors (#10741)

* Add a new host function for reporting fatal errors

* Fix one of the wasmtime executor tests

* Have `#[runtime_interface(wasm_only)]` actually mean WASM-only, and not no_std-only

* Print out errors through `Display` instead of `Debug`

* Switch one more trait to require `Error` for its error instead of only `Debug`

* Align to review comments
This commit is contained in:
Koute
2022-02-09 18:12:55 +09:00
committed by GitHub
parent bd261d57c4
commit 9a31b2c341
68 changed files with 554 additions and 249 deletions
@@ -205,7 +205,7 @@ where
let hash = block.header.hash();
let parent_hash = *block.header.parent_hash();
let authorities = authorities(self.client.as_ref(), &BlockId::Hash(parent_hash))
.map_err(|e| format!("Could not fetch authorities at {:?}: {:?}", parent_hash, e))?;
.map_err(|e| format!("Could not fetch authorities at {:?}: {}", parent_hash, e))?;
let create_inherent_data_providers = self
.create_inherent_data_providers
@@ -249,7 +249,7 @@ where
&BlockId::Hash(parent_hash),
|v| v >= 2,
)
.map_err(|e| format!("{:?}", e))?
.map_err(|e| e.to_string())?
{
self.check_inherents(
new_block.clone(),
@@ -104,7 +104,7 @@ where
let epoch_start = client
.runtime_api()
.current_epoch_start(&BlockId::Hash(header.hash()))
.map_err(|err| Error::StringError(format!("{:?}", err)))?;
.map_err(|err| Error::StringError(err.to_string()))?;
let epoch =
epoch_data(&shared_epoch, &client, &babe_config, *epoch_start, &select_chain)
.await?;
@@ -209,7 +209,7 @@ where
slot.into(),
|slot| Epoch::genesis(&babe_config, slot),
)
.map_err(|e| Error::Consensus(ConsensusError::ChainLookup(format!("{:?}", e))))?
.map_err(|e| Error::Consensus(ConsensusError::ChainLookup(e.to_string())))?
.ok_or(Error::Consensus(ConsensusError::InvalidAuthoritiesSet))
}
+9 -9
View File
@@ -232,7 +232,7 @@ pub enum Error<B: BlockT> {
#[error("Multiple BABE config change digests, rejecting!")]
MultipleConfigChangeDigests,
/// Could not extract timestamp and slot
#[error("Could not extract timestamp and slot: {0:?}")]
#[error("Could not extract timestamp and slot: {0}")]
Extraction(sp_consensus::Error),
/// Could not fetch epoch
#[error("Could not fetch epoch at {0:?}")]
@@ -274,7 +274,7 @@ pub enum Error<B: BlockT> {
#[error("VRF verification failed: {0:?}")]
VRFVerificationFailed(SignatureError),
/// Could not fetch parent header
#[error("Could not fetch parent header: {0:?}")]
#[error("Could not fetch parent header: {0}")]
FetchParentHeader(sp_blockchain::Error),
/// Expected epoch change to happen.
#[error("Expected epoch change to happen at {0:?}, s{1}")]
@@ -713,7 +713,7 @@ where
parent.number().clone(),
slot,
)
.map_err(|e| ConsensusError::ChainLookup(format!("{:?}", e)))?
.map_err(|e| ConsensusError::ChainLookup(e.to_string()))?
.ok_or(sp_consensus::Error::InvalidAuthoritiesSet)
}
@@ -1201,7 +1201,7 @@ where
)
.await
{
warn!(target: "babe", "Error checking/reporting BABE equivocation: {:?}", err);
warn!(target: "babe", "Error checking/reporting BABE equivocation: {}", err);
}
// if the body is passed through, we need to use the runtime
@@ -1551,7 +1551,7 @@ where
)
.map_err(|e| {
ConsensusError::ClientImport(format!(
"Error importing epoch changes: {:?}",
"Error importing epoch changes: {}",
e
))
})?;
@@ -1559,7 +1559,7 @@ where
};
if let Err(e) = prune_and_import() {
debug!(target: "babe", "Failed to launch next epoch: {:?}", e);
debug!(target: "babe", "Failed to launch next epoch: {}", e);
*epoch_changes =
old_epoch_changes.expect("set `Some` above and not taken; qed");
return Err(e)
@@ -1590,7 +1590,7 @@ where
parent_weight
} else {
aux_schema::load_block_weight(&*self.client, last_best)
.map_err(|e| ConsensusError::ChainLookup(format!("{:?}", e)))?
.map_err(|e| ConsensusError::ChainLookup(e.to_string()))?
.ok_or_else(|| {
ConsensusError::ChainLookup(
"No block weight for parent header.".to_string(),
@@ -1649,7 +1649,7 @@ where
let finalized_slot = {
let finalized_header = client
.header(BlockId::Hash(info.finalized_hash))
.map_err(|e| ConsensusError::ClientImport(format!("{:?}", e)))?
.map_err(|e| ConsensusError::ClientImport(e.to_string()))?
.expect(
"best finalized hash was given by client; finalized headers must exist in db; qed",
);
@@ -1666,7 +1666,7 @@ where
info.finalized_number,
finalized_slot,
)
.map_err(|e| ConsensusError::ClientImport(format!("{:?}", e)))?;
.map_err(|e| ConsensusError::ClientImport(e.to_string()))?;
Ok(())
}
@@ -161,21 +161,34 @@ pub enum BlockImportStatus<N: std::fmt::Debug + PartialEq> {
}
/// Block import error.
#[derive(Debug)]
#[derive(Debug, thiserror::Error)]
pub enum BlockImportError {
/// Block missed header, can't be imported
#[error("block is missing a header (origin = {0:?})")]
IncompleteHeader(Option<Origin>),
/// Block verification failed, can't be imported
#[error("block verification failed (origin = {0:?}): {1}")]
VerificationFailed(Option<Origin>, String),
/// Block is known to be Bad
#[error("bad block (origin = {0:?})")]
BadBlock(Option<Origin>),
/// Parent state is missing.
#[error("block is missing parent state")]
MissingState,
/// Block has an unknown parent
#[error("block has an unknown parent")]
UnknownParent,
/// Block import has been cancelled. This can happen if the parent block fails to be imported.
#[error("import has been cancelled")]
Cancelled,
/// Other error.
#[error("consensus error: {0}")]
Other(ConsensusError),
}
@@ -245,7 +258,7 @@ pub(crate) async fn import_single_block_metered<
Err(BlockImportError::BadBlock(peer.clone()))
},
Err(e) => {
debug!(target: "sync", "Error importing block {}: {:?}: {:?}", number, hash, e);
debug!(target: "sync", "Error importing block {}: {:?}: {}", number, hash, e);
Err(BlockImportError::Other(e))
},
};
@@ -303,11 +303,11 @@ impl<B: BlockT> BlockImportWorker<B> {
.map_err(|e| {
debug!(
target: "sync",
"Justification import failed with {:?} for hash: {:?} number: {:?} coming from node: {:?}",
e,
"Justification import failed for hash = {:?} with number = {:?} coming from node = {:?} with error: {}",
hash,
number,
who,
e,
);
e
})
@@ -118,7 +118,7 @@ where
pre_digest.slot(),
)
.map_err(|e| format!("failed to fetch epoch_descriptor: {}", e))?
.ok_or_else(|| format!("{:?}", sp_consensus::Error::InvalidAuthoritiesSet))?;
.ok_or_else(|| format!("{}", sp_consensus::Error::InvalidAuthoritiesSet))?;
// drop the lock
drop(epoch_changes);
@@ -48,7 +48,7 @@ where
match finalizer.finalize_block(BlockId::Hash(hash), justification, true) {
Err(e) => {
log::warn!("Failed to finalize block {:?}", e);
log::warn!("Failed to finalize block {}", e);
rpc::send_result(&mut sender, Err(e.into()))
},
Ok(()) => {
@@ -155,7 +155,10 @@ pub fn send_result<T: std::fmt::Debug>(
) {
if let Some(sender) = sender.take() {
if let Err(err) = sender.send(result) {
log::warn!("Server is shutting down: {:?}", err)
match err {
Ok(value) => log::warn!("Server is shutting down: {:?}", value),
Err(error) => log::warn!("Server is shutting down with error: {}", error),
}
}
} else {
// instant seal doesn't report errors over rpc, simply log them.
@@ -114,10 +114,7 @@ pub async fn seal_block<B, BI, SC, C, E, TP, CIDP>(
let inherent_data = inherent_data_providers.create_inherent_data()?;
let proposer = env
.init(&parent)
.map_err(|err| Error::StringError(format!("{:?}", err)))
.await?;
let proposer = env.init(&parent).map_err(|err| Error::StringError(err.to_string())).await?;
let inherents_len = inherent_data.len();
let digest = if let Some(digest_provider) = digest_provider {
@@ -133,7 +130,7 @@ pub async fn seal_block<B, BI, SC, C, E, TP, CIDP>(
Duration::from_secs(MAX_PROPOSAL_DURATION),
None,
)
.map_err(|err| Error::StringError(format!("{:?}", err)))
.map_err(|err| Error::StringError(err.to_string()))
.await?;
if proposal.block.extrinsics().len() == inherents_len && !create_empty {
+12 -12
View File
@@ -84,24 +84,24 @@ pub enum Error<B: BlockT> {
FailedPreliminaryVerify,
#[error("Rejecting block too far in future")]
TooFarInFuture,
#[error("Fetching best header failed using select chain: {0:?}")]
#[error("Fetching best header failed using select chain: {0}")]
BestHeaderSelectChain(ConsensusError),
#[error("Fetching best header failed: {0:?}")]
#[error("Fetching best header failed: {0}")]
BestHeader(sp_blockchain::Error),
#[error("Best header does not exist")]
NoBestHeader,
#[error("Block proposing error: {0:?}")]
#[error("Block proposing error: {0}")]
BlockProposingError(String),
#[error("Fetch best hash failed via select chain: {0:?}")]
#[error("Fetch best hash failed via select chain: {0}")]
BestHashSelectChain(ConsensusError),
#[error("Error with block built on {0:?}: {1:?}")]
#[error("Error with block built on {0:?}: {1}")]
BlockBuiltError(B::Hash, ConsensusError),
#[error("Creating inherents failed: {0}")]
CreateInherents(sp_inherents::Error),
#[error("Checking inherents failed: {0}")]
CheckInherents(sp_inherents::Error),
#[error(
"Checking inherents unknown error for identifier: {:?}",
"Checking inherents unknown error for identifier: {}",
String::from_utf8_lossy(.0)
)]
CheckInherentsUnknownError(sp_inherents::InherentIdentifier),
@@ -350,7 +350,7 @@ where
.select_chain
.best_chain()
.await
.map_err(|e| format!("Fetch best chain failed via select chain: {:?}", e))?;
.map_err(|e| format!("Fetch best chain failed via select chain: {}", e))?;
let best_hash = best_header.hash();
let parent_hash = *block.header.parent_hash();
@@ -565,7 +565,7 @@ where
warn!(
target: "pow",
"Unable to pull new block for authoring. \
Select best chain error: {:?}",
Select best chain error: {}",
err
);
continue
@@ -596,7 +596,7 @@ where
warn!(
target: "pow",
"Unable to propose new block for authoring. \
Fetch difficulty failed: {:?}",
Fetch difficulty failed: {}",
err,
);
continue
@@ -612,7 +612,7 @@ where
warn!(
target: "pow",
"Unable to propose new block for authoring. \
Creating inherent data providers failed: {:?}",
Creating inherent data providers failed: {}",
err,
);
continue
@@ -625,7 +625,7 @@ where
warn!(
target: "pow",
"Unable to propose new block for authoring. \
Creating inherent data failed: {:?}",
Creating inherent data failed: {}",
e,
);
continue
@@ -661,7 +661,7 @@ where
warn!(
target: "pow",
"Unable to propose new block for authoring. \
Creating proposal failed: {:?}",
Creating proposal failed: {}",
err,
);
continue
+2 -2
View File
@@ -169,7 +169,7 @@ where
Err(err) => {
warn!(
target: "pow",
"Unable to import mined block: {:?}",
"Unable to import mined block: {}",
err,
);
return false
@@ -238,7 +238,7 @@ where
Err(err) => {
warn!(
target: "pow",
"Unable to import mined block: {:?}",
"Unable to import mined block: {}",
err,
);
false
+7 -10
View File
@@ -214,7 +214,7 @@ pub trait SimpleSlotWorker<B: BlockT> {
Err(err) => {
warn!(
target: logging_target,
"Unable to fetch epoch data at block {:?}: {:?}",
"Unable to fetch epoch data at block {:?}: {}",
slot_info.chain_head.hash(),
err,
);
@@ -274,10 +274,7 @@ pub trait SimpleSlotWorker<B: BlockT> {
let proposer = match self.proposer(&slot_info.chain_head).await {
Ok(p) => p,
Err(err) => {
warn!(
target: logging_target,
"Unable to author block in slot {:?}: {:?}", slot, err,
);
warn!(target: logging_target, "Unable to author block in slot {:?}: {}", slot, err,);
telemetry!(
telemetry;
@@ -303,12 +300,12 @@ pub trait SimpleSlotWorker<B: BlockT> {
proposing_remaining_duration.mul_f32(0.98),
None,
)
.map_err(|e| sp_consensus::Error::ClientImport(format!("{:?}", e)));
.map_err(|e| sp_consensus::Error::ClientImport(e.to_string()));
let proposal = match futures::future::select(proposing, proposing_remaining).await {
Either::Left((Ok(p), _)) => p,
Either::Left((Err(err), _)) => {
warn!(target: logging_target, "Proposing failed: {:?}", err);
warn!(target: logging_target, "Proposing failed: {}", err);
return None
},
@@ -353,7 +350,7 @@ pub trait SimpleSlotWorker<B: BlockT> {
{
Ok(bi) => bi,
Err(err) => {
warn!(target: logging_target, "Failed to create block import params: {:?}", err);
warn!(target: logging_target, "Failed to create block import params: {}", err);
return None
},
@@ -388,7 +385,7 @@ pub trait SimpleSlotWorker<B: BlockT> {
Err(err) => {
warn!(
target: logging_target,
"Error with block built on {:?}: {:?}", parent_hash, err,
"Error with block built on {:?}: {}", parent_hash, err,
);
telemetry!(
@@ -488,7 +485,7 @@ pub async fn start_slot_worker<B, C, W, T, SO, CIDP, CAW, Proof>(
let slot_info = match slots.next_slot().await {
Ok(r) => r,
Err(e) => {
warn!(target: "slots", "Error while polling for next slot: {:?}", e);
warn!(target: "slots", "Error while polling for next slot: {}", e);
return
},
};
@@ -150,7 +150,7 @@ where
Err(e) => {
log::warn!(
target: "slots",
"Unable to author block in slot. No best block header: {:?}",
"Unable to author block in slot. No best block header: {}",
e,
);
// Let's try at the next slot..