mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-14 01:41:09 +00:00
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:
@@ -38,7 +38,7 @@ pub enum Error {
|
||||
#[error("Failed to hash the authority id to be used as a dht key.")]
|
||||
HashingAuthorityId(#[from] libp2p::core::multiaddr::multihash::Error),
|
||||
|
||||
#[error("Failed calling into the Substrate runtime.")]
|
||||
#[error("Failed calling into the Substrate runtime: {0}")]
|
||||
CallingRuntime(#[from] sp_blockchain::Error),
|
||||
|
||||
#[error("Received a dht record with a key that does not match any in-flight awaited keys.")]
|
||||
|
||||
@@ -187,7 +187,7 @@ where
|
||||
Some(registry) => match Metrics::register(®istry) {
|
||||
Ok(metrics) => Some(metrics),
|
||||
Err(e) => {
|
||||
error!(target: LOG_TARGET, "Failed to register metrics: {:?}", e);
|
||||
error!(target: LOG_TARGET, "Failed to register metrics: {}", e);
|
||||
None
|
||||
},
|
||||
},
|
||||
@@ -242,7 +242,7 @@ where
|
||||
if let Err(e) = self.publish_ext_addresses(only_if_changed).await {
|
||||
error!(
|
||||
target: LOG_TARGET,
|
||||
"Failed to publish external addresses: {:?}", e,
|
||||
"Failed to publish external addresses: {}", e,
|
||||
);
|
||||
}
|
||||
},
|
||||
@@ -251,7 +251,7 @@ where
|
||||
if let Err(e) = self.refill_pending_lookups_queue().await {
|
||||
error!(
|
||||
target: LOG_TARGET,
|
||||
"Failed to request addresses of authorities: {:?}", e,
|
||||
"Failed to request addresses of authorities: {}", e,
|
||||
);
|
||||
}
|
||||
},
|
||||
@@ -426,7 +426,7 @@ where
|
||||
metrics.handle_value_found_event_failure.inc();
|
||||
}
|
||||
|
||||
debug!(target: LOG_TARGET, "Failed to handle Dht value found event: {:?}", e);
|
||||
debug!(target: LOG_TARGET, "Failed to handle Dht value found event: {}", e);
|
||||
}
|
||||
},
|
||||
DhtEvent::ValueNotFound(hash) => {
|
||||
|
||||
@@ -378,7 +378,7 @@ where
|
||||
.expect("forwards closure result; the closure always returns Ok; qed.");
|
||||
}
|
||||
}) {
|
||||
error!(target: "beefy", "🥩 Failed to get hash for block number {}; err: {:?}",
|
||||
error!(target: "beefy", "🥩 Failed to get hash for block number {}: {}",
|
||||
block_num, err);
|
||||
}
|
||||
|
||||
|
||||
@@ -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))
|
||||
}
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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..
|
||||
|
||||
@@ -31,9 +31,6 @@ pub enum Error {
|
||||
#[error("Unserializable data encountered")]
|
||||
InvalidData(#[from] sp_serializer::Error),
|
||||
|
||||
#[error(transparent)]
|
||||
Trap(#[from] wasmi::Trap),
|
||||
|
||||
#[error(transparent)]
|
||||
Wasmi(#[from] wasmi::Error),
|
||||
|
||||
@@ -108,6 +105,12 @@ pub enum Error {
|
||||
|
||||
#[error("Invalid initializer expression provided {0}")]
|
||||
InvalidInitializerExpression(String),
|
||||
|
||||
#[error("Execution aborted due to panic: {0}")]
|
||||
AbortedDueToPanic(MessageWithBacktrace),
|
||||
|
||||
#[error("Execution aborted due to trap: {0}")]
|
||||
AbortedDueToTrap(MessageWithBacktrace),
|
||||
}
|
||||
|
||||
impl wasmi::HostError for Error {}
|
||||
@@ -160,3 +163,38 @@ pub enum WasmError {
|
||||
#[error("{0}")]
|
||||
Other(String),
|
||||
}
|
||||
|
||||
/// An error message with an attached backtrace.
|
||||
#[derive(Debug)]
|
||||
pub struct MessageWithBacktrace {
|
||||
/// The error message.
|
||||
pub message: String,
|
||||
|
||||
/// The backtrace associated with the error message.
|
||||
pub backtrace: Option<Backtrace>,
|
||||
}
|
||||
|
||||
impl std::fmt::Display for MessageWithBacktrace {
|
||||
fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
fmt.write_str(&self.message)?;
|
||||
if let Some(ref backtrace) = self.backtrace {
|
||||
fmt.write_str("\nWASM backtrace:\n")?;
|
||||
backtrace.backtrace_string.fmt(fmt)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// A WASM backtrace.
|
||||
#[derive(Debug)]
|
||||
pub struct Backtrace {
|
||||
/// The string containing the backtrace.
|
||||
pub backtrace_string: String,
|
||||
}
|
||||
|
||||
impl std::fmt::Display for Backtrace {
|
||||
fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
fmt.write_str(&self.backtrace_string)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"]
|
||||
|
||||
[dependencies]
|
||||
sp-core = { version = "5.0.0", default-features = false, path = "../../../primitives/core" }
|
||||
sp-io = { version = "5.0.0", default-features = false, path = "../../../primitives/io" }
|
||||
sp-io = { version = "5.0.0", default-features = false, path = "../../../primitives/io", features = ["improved_panic_error_reporting"] }
|
||||
sp-runtime = { version = "5.0.0", default-features = false, path = "../../../primitives/runtime" }
|
||||
sp-sandbox = { version = "0.10.0-dev", default-features = false, path = "../../../primitives/sandbox" }
|
||||
sp-std = { version = "4.0.0", default-features = false, path = "../../../primitives/std" }
|
||||
|
||||
@@ -341,6 +341,14 @@ sp_core::wasm_export_functions! {
|
||||
fn test_take_i8(value: i8) {
|
||||
assert_eq!(value, -66);
|
||||
}
|
||||
|
||||
fn test_abort_on_panic() {
|
||||
sp_io::panic_handler::abort_on_panic("test_abort_on_panic called");
|
||||
}
|
||||
|
||||
fn test_unreachable_intrinsic() {
|
||||
core::arch::wasm32::unreachable()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "std"))]
|
||||
|
||||
@@ -22,7 +22,7 @@ mod sandbox;
|
||||
|
||||
use codec::{Decode, Encode};
|
||||
use hex_literal::hex;
|
||||
use sc_executor_common::{runtime_blob::RuntimeBlob, wasm_runtime::WasmModule};
|
||||
use sc_executor_common::{error::Error, runtime_blob::RuntimeBlob, wasm_runtime::WasmModule};
|
||||
use sc_runtime_test::wasm_binary_unwrap;
|
||||
use sp_core::{
|
||||
blake2_128, blake2_256, ed25519, map,
|
||||
@@ -122,7 +122,7 @@ fn call_in_wasm<E: Externalities>(
|
||||
call_data: &[u8],
|
||||
execution_method: WasmExecutionMethod,
|
||||
ext: &mut E,
|
||||
) -> Result<Vec<u8>, String> {
|
||||
) -> Result<Vec<u8>, Error> {
|
||||
let executor =
|
||||
crate::WasmExecutor::<HostFunctions>::new(execution_method, Some(1024), 8, None, 2);
|
||||
executor.uncached_call(
|
||||
@@ -148,25 +148,16 @@ fn call_not_existing_function(wasm_method: WasmExecutionMethod) {
|
||||
let mut ext = TestExternalities::default();
|
||||
let mut ext = ext.ext();
|
||||
|
||||
match call_in_wasm(
|
||||
"test_calling_missing_external",
|
||||
&[],
|
||||
wasm_method,
|
||||
&mut ext,
|
||||
) {
|
||||
Ok(_) => panic!("was expected an `Err`"),
|
||||
Err(e) => {
|
||||
match wasm_method {
|
||||
WasmExecutionMethod::Interpreted => assert_eq!(
|
||||
&format!("{:?}", e),
|
||||
"\"Trap: Trap { kind: Host(Other(\\\"Function `missing_external` is only a stub. Calling a stub is not allowed.\\\")) }\""
|
||||
),
|
||||
match call_in_wasm("test_calling_missing_external", &[], wasm_method, &mut ext).unwrap_err() {
|
||||
Error::AbortedDueToTrap(error) => {
|
||||
let expected = match wasm_method {
|
||||
WasmExecutionMethod::Interpreted => "Trap: Host(Other(\"Function `missing_external` is only a stub. Calling a stub is not allowed.\"))",
|
||||
#[cfg(feature = "wasmtime")]
|
||||
WasmExecutionMethod::Compiled => assert!(
|
||||
format!("{:?}", e).contains("Wasm execution trapped: call to a missing function env:missing_external")
|
||||
),
|
||||
}
|
||||
}
|
||||
WasmExecutionMethod::Compiled => "call to a missing function env:missing_external"
|
||||
};
|
||||
assert_eq!(error.message, expected);
|
||||
},
|
||||
error => panic!("unexpected error: {:?}", error),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -175,25 +166,18 @@ fn call_yet_another_not_existing_function(wasm_method: WasmExecutionMethod) {
|
||||
let mut ext = TestExternalities::default();
|
||||
let mut ext = ext.ext();
|
||||
|
||||
match call_in_wasm(
|
||||
"test_calling_yet_another_missing_external",
|
||||
&[],
|
||||
wasm_method,
|
||||
&mut ext,
|
||||
) {
|
||||
Ok(_) => panic!("was expected an `Err`"),
|
||||
Err(e) => {
|
||||
match wasm_method {
|
||||
WasmExecutionMethod::Interpreted => assert_eq!(
|
||||
&format!("{:?}", e),
|
||||
"\"Trap: Trap { kind: Host(Other(\\\"Function `yet_another_missing_external` is only a stub. Calling a stub is not allowed.\\\")) }\""
|
||||
),
|
||||
match call_in_wasm("test_calling_yet_another_missing_external", &[], wasm_method, &mut ext)
|
||||
.unwrap_err()
|
||||
{
|
||||
Error::AbortedDueToTrap(error) => {
|
||||
let expected = match wasm_method {
|
||||
WasmExecutionMethod::Interpreted => "Trap: Host(Other(\"Function `yet_another_missing_external` is only a stub. Calling a stub is not allowed.\"))",
|
||||
#[cfg(feature = "wasmtime")]
|
||||
WasmExecutionMethod::Compiled => assert!(
|
||||
format!("{:?}", e).contains("Wasm execution trapped: call to a missing function env:yet_another_missing_external")
|
||||
),
|
||||
}
|
||||
}
|
||||
WasmExecutionMethod::Compiled => "call to a missing function env:yet_another_missing_external"
|
||||
};
|
||||
assert_eq!(error.message, expected);
|
||||
},
|
||||
error => panic!("unexpected error: {:?}", error),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -485,6 +469,7 @@ fn should_trap_when_heap_exhausted(wasm_method: WasmExecutionMethod) {
|
||||
"test_exhaust_heap",
|
||||
&[0],
|
||||
)
|
||||
.map_err(|e| e.to_string())
|
||||
.unwrap_err();
|
||||
|
||||
assert!(err.contains("Allocator ran out of space"));
|
||||
@@ -691,7 +676,7 @@ fn panic_in_spawned_instance_panics_on_joining_its_result(wasm_method: WasmExecu
|
||||
let error_result =
|
||||
call_in_wasm("test_panic_in_spawned", &[], wasm_method, &mut ext).unwrap_err();
|
||||
|
||||
assert!(error_result.contains("Spawned task"));
|
||||
assert!(error_result.to_string().contains("Spawned task"));
|
||||
}
|
||||
|
||||
test_wasm_execution!(memory_is_cleared_between_invocations);
|
||||
@@ -789,3 +774,32 @@ fn take_i8(wasm_method: WasmExecutionMethod) {
|
||||
|
||||
call_in_wasm("test_take_i8", &(-66_i8).encode(), wasm_method, &mut ext).unwrap();
|
||||
}
|
||||
|
||||
test_wasm_execution!(abort_on_panic);
|
||||
fn abort_on_panic(wasm_method: WasmExecutionMethod) {
|
||||
let mut ext = TestExternalities::default();
|
||||
let mut ext = ext.ext();
|
||||
|
||||
match call_in_wasm("test_abort_on_panic", &[], wasm_method, &mut ext).unwrap_err() {
|
||||
Error::AbortedDueToPanic(error) => assert_eq!(error.message, "test_abort_on_panic called"),
|
||||
error => panic!("unexpected error: {:?}", error),
|
||||
}
|
||||
}
|
||||
|
||||
test_wasm_execution!(unreachable_intrinsic);
|
||||
fn unreachable_intrinsic(wasm_method: WasmExecutionMethod) {
|
||||
let mut ext = TestExternalities::default();
|
||||
let mut ext = ext.ext();
|
||||
|
||||
match call_in_wasm("test_unreachable_intrinsic", &[], wasm_method, &mut ext).unwrap_err() {
|
||||
Error::AbortedDueToTrap(error) => {
|
||||
let expected = match wasm_method {
|
||||
WasmExecutionMethod::Interpreted => "Trap: Unreachable",
|
||||
#[cfg(feature = "wasmtime")]
|
||||
WasmExecutionMethod::Compiled => "wasm trap: wasm `unreachable` instruction executed",
|
||||
};
|
||||
assert_eq!(error.message, expected);
|
||||
},
|
||||
error => panic!("unexpected error: {:?}", error),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -220,7 +220,7 @@ where
|
||||
allow_missing_host_functions: bool,
|
||||
export_name: &str,
|
||||
call_data: &[u8],
|
||||
) -> std::result::Result<Vec<u8>, String> {
|
||||
) -> std::result::Result<Vec<u8>, Error> {
|
||||
let module = crate::wasm_runtime::create_wasm_runtime_with_code::<H>(
|
||||
self.method,
|
||||
self.default_heap_pages,
|
||||
@@ -228,11 +228,10 @@ where
|
||||
allow_missing_host_functions,
|
||||
self.cache_path.as_deref(),
|
||||
)
|
||||
.map_err(|e| format!("Failed to create module: {:?}", e))?;
|
||||
.map_err(|e| format!("Failed to create module: {}", e))?;
|
||||
|
||||
let instance = module
|
||||
.new_instance()
|
||||
.map_err(|e| format!("Failed to create instance: {:?}", e))?;
|
||||
let instance =
|
||||
module.new_instance().map_err(|e| format!("Failed to create instance: {}", e))?;
|
||||
|
||||
let mut instance = AssertUnwindSafe(instance);
|
||||
let mut ext = AssertUnwindSafe(ext);
|
||||
@@ -243,7 +242,6 @@ where
|
||||
instance.call_export(export_name, call_data)
|
||||
})
|
||||
.and_then(|r| r)
|
||||
.map_err(|e| e.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -281,6 +279,7 @@ where
|
||||
"Core_version",
|
||||
&[],
|
||||
)
|
||||
.map_err(|e| e.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -456,12 +455,18 @@ impl RuntimeSpawn for RuntimeInstanceSpawn {
|
||||
// pool of instances should be used.
|
||||
//
|
||||
// https://github.com/paritytech/substrate/issues/7354
|
||||
let mut instance =
|
||||
module.new_instance().expect("Failed to create new instance from module");
|
||||
let mut instance = match module.new_instance() {
|
||||
Ok(instance) => instance,
|
||||
Err(error) =>
|
||||
panic!("failed to create new instance from module: {}", error),
|
||||
};
|
||||
|
||||
instance
|
||||
match instance
|
||||
.call(InvokeMethod::TableWithWrapper { dispatcher_ref, func }, &data[..])
|
||||
.expect("Failed to invoke instance.")
|
||||
{
|
||||
Ok(result) => result,
|
||||
Err(error) => panic!("failed to invoke instance: {}", error),
|
||||
}
|
||||
});
|
||||
|
||||
match result {
|
||||
@@ -471,7 +476,7 @@ impl RuntimeSpawn for RuntimeInstanceSpawn {
|
||||
Err(error) => {
|
||||
// If execution is panicked, the `join` in the original runtime code will
|
||||
// panic as well, since the sender is dropped without sending anything.
|
||||
log::error!("Call error in spawned task: {:?}", error);
|
||||
log::error!("Call error in spawned task: {}", error);
|
||||
},
|
||||
}
|
||||
}),
|
||||
|
||||
@@ -105,13 +105,13 @@ impl VersionedRuntime {
|
||||
if new_inst {
|
||||
log::warn!(
|
||||
target: "wasm-runtime",
|
||||
"Fresh runtime instance failed with {:?}",
|
||||
"Fresh runtime instance failed with {}",
|
||||
e,
|
||||
)
|
||||
} else {
|
||||
log::warn!(
|
||||
target: "wasm-runtime",
|
||||
"Evicting failed runtime instance: {:?}",
|
||||
"Evicting failed runtime instance: {}",
|
||||
e,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
use codec::{Decode, Encode};
|
||||
use log::{debug, error, trace};
|
||||
use sc_executor_common::{
|
||||
error::{Error, WasmError},
|
||||
error::{Error, MessageWithBacktrace, WasmError},
|
||||
runtime_blob::{DataSegmentsSnapshot, RuntimeBlob},
|
||||
sandbox,
|
||||
util::MemoryTransfer,
|
||||
@@ -48,6 +48,7 @@ struct FunctionExecutor {
|
||||
host_functions: Arc<Vec<&'static dyn Function>>,
|
||||
allow_missing_func_imports: bool,
|
||||
missing_functions: Arc<Vec<String>>,
|
||||
panic_message: Option<String>,
|
||||
}
|
||||
|
||||
impl FunctionExecutor {
|
||||
@@ -69,6 +70,7 @@ impl FunctionExecutor {
|
||||
host_functions,
|
||||
allow_missing_func_imports,
|
||||
missing_functions,
|
||||
panic_message: None,
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -100,7 +102,10 @@ impl<'a> sandbox::SandboxContext for SandboxContext<'a> {
|
||||
match result {
|
||||
Ok(Some(RuntimeValue::I64(val))) => Ok(val),
|
||||
Ok(_) => return Err("Supervisor function returned unexpected result!".into()),
|
||||
Err(err) => Err(Error::Trap(err)),
|
||||
Err(err) => Err(Error::AbortedDueToTrap(MessageWithBacktrace {
|
||||
message: err.to_string(),
|
||||
backtrace: None,
|
||||
})),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -133,6 +138,10 @@ impl FunctionContext for FunctionExecutor {
|
||||
fn sandbox(&mut self) -> &mut dyn Sandbox {
|
||||
self
|
||||
}
|
||||
|
||||
fn register_panic_error_message(&mut self, message: &str) {
|
||||
self.panic_message = Some(message.to_owned());
|
||||
}
|
||||
}
|
||||
|
||||
impl Sandbox for FunctionExecutor {
|
||||
@@ -502,12 +511,31 @@ fn call_in_wasm_module(
|
||||
let offset = function_executor.allocate_memory(data.len() as u32)?;
|
||||
function_executor.write_memory(offset, data)?;
|
||||
|
||||
fn convert_trap(executor: &mut FunctionExecutor, trap: wasmi::Trap) -> Error {
|
||||
if let Some(message) = executor.panic_message.take() {
|
||||
Error::AbortedDueToPanic(MessageWithBacktrace { message, backtrace: None })
|
||||
} else {
|
||||
Error::AbortedDueToTrap(MessageWithBacktrace {
|
||||
message: trap.to_string(),
|
||||
backtrace: None,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
let result = match method {
|
||||
InvokeMethod::Export(method) => module_instance.invoke_export(
|
||||
method,
|
||||
&[I32(u32::from(offset) as i32), I32(data.len() as i32)],
|
||||
&mut function_executor,
|
||||
),
|
||||
InvokeMethod::Export(method) => module_instance
|
||||
.invoke_export(
|
||||
method,
|
||||
&[I32(u32::from(offset) as i32), I32(data.len() as i32)],
|
||||
&mut function_executor,
|
||||
)
|
||||
.map_err(|error| {
|
||||
if let wasmi::Error::Trap(trap) = error {
|
||||
convert_trap(&mut function_executor, trap)
|
||||
} else {
|
||||
error.into()
|
||||
}
|
||||
}),
|
||||
InvokeMethod::Table(func_ref) => {
|
||||
let func = table
|
||||
.ok_or(Error::NoTable)?
|
||||
@@ -518,7 +546,7 @@ fn call_in_wasm_module(
|
||||
&[I32(u32::from(offset) as i32), I32(data.len() as i32)],
|
||||
&mut function_executor,
|
||||
)
|
||||
.map_err(Into::into)
|
||||
.map_err(|trap| convert_trap(&mut function_executor, trap))
|
||||
},
|
||||
InvokeMethod::TableWithWrapper { dispatcher_ref, func } => {
|
||||
let dispatcher = table
|
||||
@@ -531,7 +559,7 @@ fn call_in_wasm_module(
|
||||
&[I32(func as _), I32(u32::from(offset) as i32), I32(data.len() as i32)],
|
||||
&mut function_executor,
|
||||
)
|
||||
.map_err(Into::into)
|
||||
.map_err(|trap| convert_trap(&mut function_executor, trap))
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
@@ -45,6 +45,7 @@ unsafe impl Send for SandboxStore {}
|
||||
pub struct HostState {
|
||||
sandbox_store: SandboxStore,
|
||||
allocator: FreeingBumpHeapAllocator,
|
||||
panic_message: Option<String>,
|
||||
}
|
||||
|
||||
impl HostState {
|
||||
@@ -55,8 +56,14 @@ impl HostState {
|
||||
sandbox::SandboxBackend::TryWasmer,
|
||||
)))),
|
||||
allocator,
|
||||
panic_message: None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Takes the error message out of the host state, leaving a `None` in its place.
|
||||
pub fn take_panic_message(&mut self) -> Option<String> {
|
||||
self.panic_message.take()
|
||||
}
|
||||
}
|
||||
|
||||
/// A `HostContext` implements `FunctionContext` for making host calls from a Wasmtime
|
||||
@@ -134,6 +141,14 @@ impl<'a> sp_wasm_interface::FunctionContext for HostContext<'a> {
|
||||
fn sandbox(&mut self) -> &mut dyn Sandbox {
|
||||
self
|
||||
}
|
||||
|
||||
fn register_panic_error_message(&mut self, message: &str) {
|
||||
self.caller
|
||||
.data_mut()
|
||||
.host_state_mut()
|
||||
.expect("host state is not empty when calling a function in wasm; qed")
|
||||
.panic_message = Some(message.to_owned());
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Sandbox for HostContext<'a> {
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
|
||||
use crate::runtime::{Store, StoreData};
|
||||
use sc_executor_common::{
|
||||
error::{Error, Result},
|
||||
error::{Backtrace, Error, MessageWithBacktrace, Result},
|
||||
wasm_runtime::InvokeMethod,
|
||||
};
|
||||
use sp_wasm_interface::{HostFunctions, Pointer, Value, WordSize};
|
||||
@@ -53,25 +53,51 @@ pub struct EntryPoint {
|
||||
|
||||
impl EntryPoint {
|
||||
/// Call this entry point.
|
||||
pub fn call(
|
||||
pub(crate) fn call(
|
||||
&self,
|
||||
ctx: impl AsContextMut,
|
||||
store: &mut Store,
|
||||
data_ptr: Pointer<u8>,
|
||||
data_len: WordSize,
|
||||
) -> Result<u64> {
|
||||
let data_ptr = u32::from(data_ptr);
|
||||
let data_len = u32::from(data_len);
|
||||
|
||||
fn handle_trap(err: wasmtime::Trap) -> Error {
|
||||
Error::from(format!("Wasm execution trapped: {}", err))
|
||||
}
|
||||
|
||||
match self.call_type {
|
||||
EntryPointType::Direct { ref entrypoint } =>
|
||||
entrypoint.call(ctx, (data_ptr, data_len)).map_err(handle_trap),
|
||||
entrypoint.call(&mut *store, (data_ptr, data_len)),
|
||||
EntryPointType::Wrapped { func, ref dispatcher } =>
|
||||
dispatcher.call(ctx, (func, data_ptr, data_len)).map_err(handle_trap),
|
||||
dispatcher.call(&mut *store, (func, data_ptr, data_len)),
|
||||
}
|
||||
.map_err(|trap| {
|
||||
let host_state = store
|
||||
.data_mut()
|
||||
.host_state
|
||||
.as_mut()
|
||||
.expect("host state cannot be empty while a function is being called; qed");
|
||||
|
||||
// The logic to print out a backtrace is somewhat complicated,
|
||||
// so let's get wasmtime to print it out for us.
|
||||
let mut backtrace_string = trap.to_string();
|
||||
let suffix = "\nwasm backtrace:";
|
||||
if let Some(index) = backtrace_string.find(suffix) {
|
||||
// Get rid of the error message and just grab the backtrace,
|
||||
// since we're storing the error message ourselves separately.
|
||||
backtrace_string.replace_range(0..index + suffix.len(), "");
|
||||
}
|
||||
|
||||
let backtrace = Backtrace { backtrace_string };
|
||||
if let Some(error) = host_state.take_panic_message() {
|
||||
Error::AbortedDueToPanic(MessageWithBacktrace {
|
||||
message: error,
|
||||
backtrace: Some(backtrace),
|
||||
})
|
||||
} else {
|
||||
Error::AbortedDueToTrap(MessageWithBacktrace {
|
||||
message: trap.display_reason().to_string(),
|
||||
backtrace: Some(backtrace),
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub fn direct(
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
use codec::{Decode as _, Encode as _};
|
||||
use sc_executor_common::{runtime_blob::RuntimeBlob, wasm_runtime::WasmModule};
|
||||
use sc_executor_common::{error::Error, runtime_blob::RuntimeBlob, wasm_runtime::WasmModule};
|
||||
use sc_runtime_test::wasm_binary_unwrap;
|
||||
use std::sync::Arc;
|
||||
|
||||
@@ -158,11 +158,13 @@ fn test_stack_depth_reaching() {
|
||||
};
|
||||
let mut instance = runtime.new_instance().expect("failed to instantiate a runtime");
|
||||
|
||||
let err = instance.call_export("test-many-locals", &[]).unwrap_err();
|
||||
|
||||
assert!(format!("{:?}", err).starts_with(
|
||||
"Other(\"Wasm execution trapped: wasm trap: wasm `unreachable` instruction executed"
|
||||
));
|
||||
match instance.call_export("test-many-locals", &[]).unwrap_err() {
|
||||
Error::AbortedDueToTrap(error) => {
|
||||
let expected = "wasm trap: wasm `unreachable` instruction executed";
|
||||
assert_eq!(error.message, expected);
|
||||
},
|
||||
error => panic!("unexpected error: {:?}", error),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
@@ -100,7 +100,7 @@ where
|
||||
// previously we only supported at most one pending change per fork
|
||||
&|_, _| Ok(false),
|
||||
) {
|
||||
warn!(target: "afg", "Error migrating pending authority set change: {:?}.", err);
|
||||
warn!(target: "afg", "Error migrating pending authority set change: {}", err);
|
||||
warn!(target: "afg", "Node is in a potentially inconsistent state.");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -609,7 +609,7 @@ where
|
||||
let tree_route = match tree_route_res {
|
||||
Ok(tree_route) => tree_route,
|
||||
Err(e) => {
|
||||
debug!(target: "afg", "Encountered error computing ancestry between block {:?} and base {:?}: {:?}",
|
||||
debug!(target: "afg", "Encountered error computing ancestry between block {:?} and base {:?}: {}",
|
||||
block, base, e);
|
||||
|
||||
return Err(GrandpaError::NotDescendent)
|
||||
@@ -1098,7 +1098,7 @@ where
|
||||
) {
|
||||
warn!(target: "afg", "Detected prevote equivocation in the finality worker: {:?}", equivocation);
|
||||
if let Err(err) = self.report_equivocation(equivocation.into()) {
|
||||
warn!(target: "afg", "Error reporting prevote equivocation: {:?}", err);
|
||||
warn!(target: "afg", "Error reporting prevote equivocation: {}", err);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1109,7 +1109,7 @@ where
|
||||
) {
|
||||
warn!(target: "afg", "Detected precommit equivocation in the finality worker: {:?}", equivocation);
|
||||
if let Err(err) = self.report_equivocation(equivocation.into()) {
|
||||
warn!(target: "afg", "Error reporting precommit equivocation: {:?}", err);
|
||||
warn!(target: "afg", "Error reporting precommit equivocation: {}", err);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1224,7 +1224,7 @@ where
|
||||
.or_else(|| Some((target_header.hash(), *target_header.number())))
|
||||
},
|
||||
Err(e) => {
|
||||
warn!(target: "afg", "Encountered error finding best chain containing {:?}: {:?}", block, e);
|
||||
warn!(target: "afg", "Encountered error finding best chain containing {:?}: {}", block, e);
|
||||
None
|
||||
},
|
||||
};
|
||||
@@ -1293,7 +1293,7 @@ where
|
||||
) {
|
||||
if let Some(sender) = justification_sender {
|
||||
if let Err(err) = sender.notify(justification) {
|
||||
warn!(target: "afg", "Error creating justification for subscriber: {:?}", err);
|
||||
warn!(target: "afg", "Error creating justification for subscriber: {}", err);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1344,7 +1344,7 @@ where
|
||||
client
|
||||
.apply_finality(import_op, BlockId::Hash(hash), persisted_justification, true)
|
||||
.map_err(|e| {
|
||||
warn!(target: "afg", "Error applying finality to block {:?}: {:?}", (hash, number), e);
|
||||
warn!(target: "afg", "Error applying finality to block {:?}: {}", (hash, number), e);
|
||||
e
|
||||
})?;
|
||||
|
||||
|
||||
@@ -598,7 +598,7 @@ where
|
||||
Err(e) => {
|
||||
debug!(
|
||||
target: "afg",
|
||||
"Restoring old authority set after block import error: {:?}",
|
||||
"Restoring old authority set after block import error: {}",
|
||||
e,
|
||||
);
|
||||
pending_changes.revert();
|
||||
@@ -663,8 +663,12 @@ where
|
||||
|
||||
import_res.unwrap_or_else(|err| {
|
||||
if needs_justification {
|
||||
debug!(target: "afg", "Imported block #{} that enacts authority set change with \
|
||||
invalid justification: {:?}, requesting justification from peers.", number, err);
|
||||
debug!(
|
||||
target: "afg",
|
||||
"Requesting justification from peers due to imported block #{} that enacts authority set change with invalid justification: {}",
|
||||
number,
|
||||
err
|
||||
);
|
||||
imported_aux.bad_justification = true;
|
||||
imported_aux.needs_justification = true;
|
||||
}
|
||||
|
||||
@@ -275,23 +275,38 @@ impl Config {
|
||||
}
|
||||
|
||||
/// Errors that can occur while voting in GRANDPA.
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
pub enum Error {
|
||||
/// An error within grandpa.
|
||||
#[error("grandpa error: {0}")]
|
||||
Grandpa(GrandpaError),
|
||||
|
||||
/// A network error.
|
||||
#[error("network error: {0}")]
|
||||
Network(String),
|
||||
|
||||
/// A blockchain error.
|
||||
#[error("blockchain error: {0}")]
|
||||
Blockchain(String),
|
||||
|
||||
/// Could not complete a round on disk.
|
||||
#[error("could not complete a round on disk: {0}")]
|
||||
Client(ClientError),
|
||||
|
||||
/// Could not sign outgoing message
|
||||
#[error("could not sign outgoing message: {0}")]
|
||||
Signing(String),
|
||||
|
||||
/// An invariant has been violated (e.g. not finalizing pending change blocks in-order)
|
||||
#[error("safety invariant has been violated: {0}")]
|
||||
Safety(String),
|
||||
|
||||
/// A timer failed to fire.
|
||||
#[error("a timer failed to fire: {0}")]
|
||||
Timer(io::Error),
|
||||
|
||||
/// A runtime api request failed.
|
||||
#[error("runtime API request failed: {0}")]
|
||||
RuntimeApi(sp_api::ApiError),
|
||||
}
|
||||
|
||||
@@ -322,7 +337,7 @@ where
|
||||
{
|
||||
fn block_number(&self, hash: Block::Hash) -> Result<Option<NumberFor<Block>>, Error> {
|
||||
self.block_number_from_id(&BlockId::Hash(hash))
|
||||
.map_err(|e| Error::Blockchain(format!("{:?}", e)))
|
||||
.map_err(|e| Error::Blockchain(e.to_string()))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -459,7 +474,7 @@ impl<H: fmt::Debug, N: fmt::Debug> ::std::error::Error for CommandOrError<H, N>
|
||||
impl<H, N> fmt::Display for CommandOrError<H, N> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match *self {
|
||||
CommandOrError::Error(ref e) => write!(f, "{:?}", e),
|
||||
CommandOrError::Error(ref e) => write!(f, "{}", e),
|
||||
CommandOrError::VoterCommand(ref cmd) => write!(f, "{}", cmd),
|
||||
}
|
||||
}
|
||||
@@ -838,7 +853,7 @@ where
|
||||
Ok(()) => error!(target: "afg",
|
||||
"GRANDPA voter future has concluded naturally, this should be unreachable."
|
||||
),
|
||||
Err(e) => error!(target: "afg", "GRANDPA voter error: {:?}", e),
|
||||
Err(e) => error!(target: "afg", "GRANDPA voter error: {}", e),
|
||||
});
|
||||
|
||||
// Make sure that `telemetry_task` doesn't accidentally finish and kill grandpa.
|
||||
|
||||
@@ -203,7 +203,7 @@ where
|
||||
);
|
||||
|
||||
let observer_work = observer_work.map_ok(|_| ()).map_err(|e| {
|
||||
warn!("GRANDPA Observer failed: {:?}", e);
|
||||
warn!("GRANDPA Observer failed: {}", e);
|
||||
});
|
||||
|
||||
Ok(observer_work.map(drop))
|
||||
|
||||
@@ -886,7 +886,7 @@ impl<B: BlockT> Protocol<B> {
|
||||
return
|
||||
},
|
||||
Err(e) => {
|
||||
warn!("Error reading block header {}: {:?}", hash, e);
|
||||
warn!("Error reading block header {}: {}", hash, e);
|
||||
return
|
||||
},
|
||||
};
|
||||
|
||||
@@ -665,7 +665,7 @@ impl<B: BlockT> ChainSync<B> {
|
||||
// There is nothing sync can get from the node that has no blockchain data.
|
||||
match self.block_status(&best_hash) {
|
||||
Err(e) => {
|
||||
debug!(target:"sync", "Error reading blockchain: {:?}", e);
|
||||
debug!(target:"sync", "Error reading blockchain: {}", e);
|
||||
Err(BadPeer(who, rep::BLOCKCHAIN_READ_ERROR))
|
||||
},
|
||||
Ok(BlockStatus::KnownBad) => {
|
||||
@@ -1192,7 +1192,7 @@ impl<B: BlockT> ChainSync<B> {
|
||||
(_, Err(e)) => {
|
||||
info!(
|
||||
target: "sync",
|
||||
"❌ Error answering legitimate blockchain query: {:?}",
|
||||
"❌ Error answering legitimate blockchain query: {}",
|
||||
e,
|
||||
);
|
||||
return Err(BadPeer(*who, rep::BLOCKCHAIN_READ_ERROR))
|
||||
@@ -1629,7 +1629,7 @@ impl<B: BlockT> ChainSync<B> {
|
||||
trace!(target: "sync", "Obsolete block {:?}", hash);
|
||||
},
|
||||
e @ Err(BlockImportError::UnknownParent) | e @ Err(BlockImportError::Other(_)) => {
|
||||
warn!(target: "sync", "💔 Error importing block {:?}: {:?}", hash, e);
|
||||
warn!(target: "sync", "💔 Error importing block {:?}: {}", hash, e.unwrap_err());
|
||||
self.state_sync = None;
|
||||
self.warp_sync = None;
|
||||
output.extend(self.restart());
|
||||
@@ -1683,7 +1683,7 @@ impl<B: BlockT> ChainSync<B> {
|
||||
if let Err(err) = r {
|
||||
warn!(
|
||||
target: "sync",
|
||||
"💔 Error cleaning up pending extra justification data requests: {:?}",
|
||||
"💔 Error cleaning up pending extra justification data requests: {}",
|
||||
err,
|
||||
);
|
||||
}
|
||||
@@ -2081,7 +2081,7 @@ impl<B: BlockT> ChainSync<B> {
|
||||
) -> impl Iterator<Item = Result<(PeerId, BlockRequest<B>), BadPeer>> + 'a {
|
||||
self.blocks.clear();
|
||||
if let Err(e) = self.reset_sync_start_point() {
|
||||
warn!(target: "sync", "💔 Unable to restart sync. :{:?}", e);
|
||||
warn!(target: "sync", "💔 Unable to restart sync: {}", e);
|
||||
}
|
||||
self.pending_requests.set_all();
|
||||
debug!(target:"sync", "Restarted with {} ({})", self.best_queued_number, self.best_queued_hash);
|
||||
|
||||
@@ -108,7 +108,7 @@ impl<B: BlockT> ExtraRequests<B> {
|
||||
// ignore the `Revert` error.
|
||||
},
|
||||
Err(err) => {
|
||||
debug!(target: "sync", "Failed to insert request {:?} into tree: {:?}", request, err);
|
||||
debug!(target: "sync", "Failed to insert request {:?} into tree: {}", request, err);
|
||||
},
|
||||
_ => (),
|
||||
}
|
||||
|
||||
@@ -99,7 +99,7 @@ impl<B: BlockT> StateSync<B> {
|
||||
Err(e) => {
|
||||
debug!(
|
||||
target: "sync",
|
||||
"StateResponse failed proof verification: {:?}",
|
||||
"StateResponse failed proof verification: {}",
|
||||
e,
|
||||
);
|
||||
return ImportResult::BadResponse
|
||||
|
||||
@@ -88,7 +88,7 @@ impl<B: BlockT> WarpSync<B> {
|
||||
Phase::WarpProof { set_id, authorities, last_hash } => {
|
||||
match self.warp_sync_provider.verify(&response, *set_id, authorities.clone()) {
|
||||
Err(e) => {
|
||||
log::debug!(target: "sync", "Bad warp proof response: {:?}", e);
|
||||
log::debug!(target: "sync", "Bad warp proof response: {}", e);
|
||||
return WarpProofImportResult::BadResponse
|
||||
},
|
||||
Ok(VerificationResult::Partial(new_set_id, new_authorities, new_last_hash)) => {
|
||||
|
||||
@@ -194,7 +194,7 @@ where
|
||||
if let Err(e) = run {
|
||||
tracing::error!(
|
||||
target: LOG_TARGET,
|
||||
"Error running offchain workers at {:?}: {:?}",
|
||||
"Error running offchain workers at {:?}: {}",
|
||||
at,
|
||||
e
|
||||
);
|
||||
|
||||
@@ -103,7 +103,7 @@ impl From<Error> for rpc::Error {
|
||||
Error::Verification(e) => rpc::Error {
|
||||
code: rpc::ErrorCode::ServerError(VERIFICATION_ERROR),
|
||||
message: format!("Verification Error: {}", e).into(),
|
||||
data: Some(format!("{:?}", e).into()),
|
||||
data: Some(e.to_string().into()),
|
||||
},
|
||||
Error::Pool(PoolError::InvalidTransaction(InvalidTransaction::Custom(e))) => rpc::Error {
|
||||
code: rpc::ErrorCode::ServerError(POOL_INVALID_TX),
|
||||
|
||||
@@ -18,11 +18,11 @@
|
||||
|
||||
use log::warn;
|
||||
|
||||
pub fn internal<E: ::std::fmt::Debug>(e: E) -> jsonrpc_core::Error {
|
||||
warn!("Unknown error: {:?}", e);
|
||||
pub fn internal<E: std::fmt::Display>(e: E) -> jsonrpc_core::Error {
|
||||
warn!("Unknown error: {}", e);
|
||||
jsonrpc_core::Error {
|
||||
code: jsonrpc_core::ErrorCode::InternalError,
|
||||
message: "Unknown error occurred".into(),
|
||||
data: Some(format!("{:?}", e).into()),
|
||||
data: Some(e.to_string().into()),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,6 +46,6 @@ where
|
||||
import_blocks(client, import_queue, reader, true, true)
|
||||
},
|
||||
Ok(None) => Box::pin(future::err("Unknown block".into())),
|
||||
Err(e) => Box::pin(future::err(format!("Error reading block: {:?}", e).into())),
|
||||
Err(e) => Box::pin(future::err(format!("Error reading block: {}", e).into())),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -322,7 +322,7 @@ where
|
||||
|
||||
for result in results {
|
||||
if let (Err(err), hash) = result {
|
||||
warn!("There was an error importing block with hash {:?}: {:?}", hash, err);
|
||||
warn!("There was an error importing block with hash {:?}: {}", hash, err);
|
||||
self.has_error = true;
|
||||
break
|
||||
}
|
||||
|
||||
@@ -285,7 +285,7 @@ where
|
||||
state_runtime_code.runtime_code().map_err(sp_blockchain::Error::RuntimeCode)?;
|
||||
self.executor
|
||||
.runtime_version(&mut ext, &runtime_code)
|
||||
.map_err(|e| sp_blockchain::Error::VersionInvalid(format!("{:?}", e)).into())
|
||||
.map_err(|e| sp_blockchain::Error::VersionInvalid(e.to_string()).into())
|
||||
}
|
||||
|
||||
fn prove_execution(
|
||||
@@ -340,7 +340,7 @@ where
|
||||
Block: BlockT,
|
||||
{
|
||||
fn runtime_version(&self, at: &BlockId<Block>) -> Result<sp_version::RuntimeVersion, String> {
|
||||
CallExecutor::runtime_version(self, at).map_err(|e| format!("{:?}", e))
|
||||
CallExecutor::runtime_version(self, at).map_err(|e| e.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1116,7 +1116,7 @@ where
|
||||
};
|
||||
let runtime_version =
|
||||
RuntimeVersionOf::runtime_version(executor, &mut ext, &runtime_code)
|
||||
.map_err(|e| sp_blockchain::Error::VersionInvalid(format!("{:?}", e)))?;
|
||||
.map_err(|e| sp_blockchain::Error::VersionInvalid(e.to_string()))?;
|
||||
Ok(runtime_version.state_version())
|
||||
} else {
|
||||
Err(sp_blockchain::Error::VersionInvalid(
|
||||
@@ -1719,7 +1719,7 @@ where
|
||||
|
||||
let storage_changes =
|
||||
match self.prepare_block_storage_changes(&mut import_block).map_err(|e| {
|
||||
warn!("Block prepare storage changes error:\n{:?}", e);
|
||||
warn!("Block prepare storage changes error: {}", e);
|
||||
ConsensusError::ClientImport(e.to_string())
|
||||
})? {
|
||||
PrepareStorageChangesResult::Discard(res) => return Ok(res),
|
||||
@@ -1730,7 +1730,7 @@ where
|
||||
self.apply_block(operation, import_block, new_cache, storage_changes)
|
||||
})
|
||||
.map_err(|e| {
|
||||
warn!("Block import error:\n{:?}", e);
|
||||
warn!("Block import error: {}", e);
|
||||
ConsensusError::ClientImport(e.to_string()).into()
|
||||
})
|
||||
}
|
||||
|
||||
@@ -243,7 +243,7 @@ impl WasmOverride {
|
||||
hash: code_hash.into(),
|
||||
},
|
||||
)
|
||||
.map_err(|e| WasmOverrideError::VersionInvalid(format!("{:?}", e)).into())
|
||||
.map_err(|e| WasmOverrideError::VersionInvalid(e.to_string()).into())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -151,6 +151,6 @@ where
|
||||
let mut ext = BasicExternalities::default();
|
||||
executor
|
||||
.runtime_version(&mut ext, &code.runtime_code(None))
|
||||
.map_err(|e| WasmSubstituteError::VersionInvalid(format!("{:?}", e)).into())
|
||||
.map_err(|e| WasmSubstituteError::VersionInvalid(e.to_string()).into())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -509,7 +509,7 @@ where
|
||||
TransactionImport::Bad
|
||||
},
|
||||
Err(e) => {
|
||||
debug!("Error converting pool error: {:?}", e);
|
||||
debug!("Error converting pool error: {}", e);
|
||||
// it is not bad at least, just some internal node logic error, so peer is
|
||||
// innocent.
|
||||
TransactionImport::KnownGood
|
||||
|
||||
@@ -253,7 +253,7 @@ where
|
||||
self.client.runtime_api().execute_block(&parent_id, block)
|
||||
}) {
|
||||
return Err(Error::Dispatch(
|
||||
format!("Failed to collect traces and execute block: {:?}", e).to_string(),
|
||||
format!("Failed to collect traces and execute block: {}", e).to_string(),
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -355,7 +355,7 @@ impl<TPool: LocalTransactionPool> OffchainSubmitTransaction<TPool::Block> for TP
|
||||
result.map(|_| ()).map_err(|e| {
|
||||
log::warn!(
|
||||
target: "txpool",
|
||||
"(offchain call) Error submitting a transaction to the pool: {:?}",
|
||||
"(offchain call) Error submitting a transaction to the pool: {}",
|
||||
e
|
||||
)
|
||||
})
|
||||
|
||||
@@ -167,18 +167,14 @@ where
|
||||
&self,
|
||||
at: &BlockId<Self::Block>,
|
||||
) -> error::Result<Option<graph::NumberFor<Self>>> {
|
||||
self.client
|
||||
.to_number(at)
|
||||
.map_err(|e| Error::BlockIdConversion(format!("{:?}", e)))
|
||||
self.client.to_number(at).map_err(|e| Error::BlockIdConversion(e.to_string()))
|
||||
}
|
||||
|
||||
fn block_id_to_hash(
|
||||
&self,
|
||||
at: &BlockId<Self::Block>,
|
||||
) -> error::Result<Option<graph::BlockHash<Self>>> {
|
||||
self.client
|
||||
.to_hash(at)
|
||||
.map_err(|e| Error::BlockIdConversion(format!("{:?}", e)))
|
||||
self.client.to_hash(at).map_err(|e| Error::BlockIdConversion(e.to_string()))
|
||||
}
|
||||
|
||||
fn hash_and_length(
|
||||
@@ -224,7 +220,7 @@ where
|
||||
}?;
|
||||
|
||||
let block_hash = client.to_hash(at)
|
||||
.map_err(|e| Error::RuntimeApi(format!("{:?}", e)))?
|
||||
.map_err(|e| Error::RuntimeApi(e.to_string()))?
|
||||
.ok_or_else(|| Error::RuntimeApi(format!("Could not get hash for block `{:?}`.", at)))?;
|
||||
|
||||
use sp_api::Core;
|
||||
@@ -237,7 +233,7 @@ where
|
||||
.map_err(|e| Error::RuntimeApi(e.to_string()))
|
||||
} else {
|
||||
let block_number = client.to_number(at)
|
||||
.map_err(|e| Error::RuntimeApi(format!("{:?}", e)))?
|
||||
.map_err(|e| Error::RuntimeApi(e.to_string()))?
|
||||
.ok_or_else(||
|
||||
Error::RuntimeApi(format!("Could not get number for block `{:?}`.", at))
|
||||
)?;
|
||||
|
||||
@@ -534,7 +534,7 @@ async fn prune_known_txs_for_block<Block: BlockT, Api: graph::ChainApi<Block = B
|
||||
.block_body(&block_id)
|
||||
.await
|
||||
.unwrap_or_else(|e| {
|
||||
log::warn!("Prune known transactions: error request {:?}!", e);
|
||||
log::warn!("Prune known transactions: error request: {}", e);
|
||||
None
|
||||
})
|
||||
.unwrap_or_default();
|
||||
@@ -550,14 +550,14 @@ async fn prune_known_txs_for_block<Block: BlockT, Api: graph::ChainApi<Block = B
|
||||
return hashes
|
||||
},
|
||||
Err(e) => {
|
||||
log::debug!(target: "txpool", "Error retrieving header for {:?}: {:?}", block_id, e);
|
||||
log::debug!(target: "txpool", "Error retrieving header for {:?}: {}", block_id, e);
|
||||
return hashes
|
||||
},
|
||||
};
|
||||
|
||||
if let Err(e) = pool.prune(&block_id, &BlockId::hash(*header.parent_hash()), &extrinsics).await
|
||||
{
|
||||
log::error!("Cannot prune known in the pool {:?}!", e);
|
||||
log::error!("Cannot prune known in the pool: {}", e);
|
||||
}
|
||||
|
||||
hashes
|
||||
@@ -639,7 +639,7 @@ where
|
||||
.block_body(&BlockId::hash(hash))
|
||||
.await
|
||||
.unwrap_or_else(|e| {
|
||||
log::warn!("Failed to fetch block body {:?}!", e);
|
||||
log::warn!("Failed to fetch block body: {}", e);
|
||||
None
|
||||
})
|
||||
.unwrap_or_default()
|
||||
@@ -685,7 +685,7 @@ where
|
||||
{
|
||||
log::debug!(
|
||||
target: "txpool",
|
||||
"[{:?}] Error re-submitting transactions: {:?}",
|
||||
"[{:?}] Error re-submitting transactions: {}",
|
||||
id,
|
||||
e,
|
||||
)
|
||||
|
||||
@@ -106,7 +106,7 @@ async fn batch_revalidate<Api: ChainApi>(
|
||||
Err(validation_err) => {
|
||||
log::debug!(
|
||||
target: "txpool",
|
||||
"[{:?}]: Error during revalidation: {:?}. Removing.",
|
||||
"[{:?}]: Removing due to error during revalidation: {}",
|
||||
ext_hash,
|
||||
validation_err
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user