Commit d6b0e1f7 authored by Andrew Jones's avatar Andrew Jones Committed by Bastian Köcher
Browse files

Remove dependency on error_chain (#277)



* Convert validation error

* Convert wasm_executor error

* Convert block evaluation error

* Convert collation errors and the compilation

* Remove error-chain dep from service

* Remove unused Result type

* Remove unused error variants

* Remove redundant intos

* Add missing comments

* Update validation/src/collation.rs

Co-Authored-By: thiolliere's avatarthiolliere <gui.thiolliere@gmail.com>

* Fix new error variant
parent 6c40a4ae
Pipeline #39584 passed with stages
in 25 minutes and 32 seconds
......@@ -2365,7 +2365,7 @@ dependencies = [
name = "polkadot-parachain"
version = "0.1.0"
dependencies = [
"error-chain 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
"derive_more 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)",
"parity-codec 3.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
"parity-codec-derive 3.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)",
......@@ -2441,7 +2441,6 @@ dependencies = [
name = "polkadot-service"
version = "0.5.0"
dependencies = [
"error-chain 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
"hex-literal 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
......@@ -2481,7 +2480,7 @@ dependencies = [
name = "polkadot-validation"
version = "0.1.0"
dependencies = [
"error-chain 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
"derive_more 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)",
"exit-future 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
"futures 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
......
......@@ -8,7 +8,7 @@ description = "Types and utilities for creating and working with parachains"
parity-codec = { version = "3.5", default-features = false }
parity-codec-derive = { version = "3.3", default-features = false }
wasmi = { version = "0.4.3", optional = true }
error-chain = { version = "0.12", optional = true }
derive_more = { version = "0.14", optional = true }
serde = { version = "1.0", default-features = false }
serde_derive = { version = "1.0", optional = true }
......@@ -18,4 +18,4 @@ tiny-keccak = "1.4"
[features]
default = ["std"]
wasm-api = []
std = ["parity-codec/std", "wasmi", "error-chain", "serde_derive", "serde/std"]
std = ["parity-codec/std", "wasmi", "derive_more", "serde_derive", "serde/std"]
......@@ -57,10 +57,6 @@ extern crate core;
#[cfg(feature = "std")]
extern crate wasmi;
#[cfg(feature = "std")]
#[macro_use]
extern crate error_chain;
#[cfg(feature = "std")]
extern crate serde;
......
......@@ -37,22 +37,27 @@ mod ids {
pub const POST_UPWARDS_MESSAGE: usize = 2;
}
error_chain! {
types { Error, ErrorKind, ResultExt; }
foreign_links {
Wasm(WasmError);
Externalities(ExternalitiesError);
}
errors {
/// Call data too big. WASM32 only has a 32-bit address space.
ParamsTooLarge(len: usize) {
description("Validation parameters took up too much space to execute in WASM"),
display("Validation parameters took up {} bytes, max allowed by WASM is {}", len, i32::max_value()),
}
/// Bad return data or type.
BadReturn {
description("Validation function returned invalid data."),
display("Validation function returned invalid data."),
/// Error type for the wasm executor
#[derive(Debug, derive_more::Display, derive_more::From)]
pub enum Error {
/// Wasm error
Wasm(WasmError),
/// Externalities error
Externalities(ExternalitiesError),
/// Call data too big. WASM32 only has a 32-bit address space.
#[display(fmt = "Validation parameters took up {} bytes, max allowed by WASM is {}", _0, i32::max_value())]
ParamsTooLarge(usize),
/// Bad return data or type.
#[display(fmt = "Validation function returned invalid data.")]
BadReturn,
}
impl std::error::Error for Error {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match self {
Error::Wasm(ref err) => Some(err),
Error::Externalities(ref err) => Some(err),
_ => None,
}
}
}
......@@ -284,7 +289,7 @@ pub fn validate_candidate<E: Externalities>(
// hard limit from WASM.
if encoded_call_data.len() > i32::max_value() as usize {
bail!(ErrorKind::ParamsTooLarge(encoded_call_data.len()));
return Err(Error::ParamsTooLarge(encoded_call_data.len()));
}
// allocate sufficient amount of wasm pages to fit encoded call data.
......@@ -308,7 +313,7 @@ pub fn validate_candidate<E: Externalities>(
.map_err(|e| -> Error {
e.as_host_error()
.and_then(|he| he.downcast_ref::<ExternalitiesError>())
.map(|ee| ErrorKind::Externalities(ee.clone()).into())
.map(|ee| Error::Externalities(ee.clone()))
.unwrap_or_else(move || e.into())
})?;
......@@ -321,24 +326,24 @@ pub fn validate_candidate<E: Externalities>(
let len_offset = len_offset as usize;
let len = u32::decode(&mut &len_bytes[..])
.ok_or_else(|| ErrorKind::BadReturn)? as usize;
.ok_or_else(|| Error::BadReturn)? as usize;
let return_offset = if len > len_offset {
bail!(ErrorKind::BadReturn);
return Err(Error::BadReturn);
} else {
len_offset - len
};
memory.with_direct_access(|mem| {
if mem.len() < return_offset + len {
return Err(ErrorKind::BadReturn.into());
return Err(Error::BadReturn);
}
ValidationResult::decode(&mut &mem[return_offset..][..len])
.ok_or_else(|| ErrorKind::BadReturn)
.ok_or_else(|| Error::BadReturn)
.map_err(Into::into)
})
}
_ => bail!(ErrorKind::BadReturn),
_ => return Err(Error::BadReturn),
}
}
......@@ -6,7 +6,6 @@ edition = "2018"
[dependencies]
parking_lot = "0.7.1"
error-chain = "0.12"
lazy_static = "1.0"
log = "0.4.6"
slog = "^2"
......
......@@ -8,7 +8,7 @@ edition = "2018"
futures = "0.1.17"
parking_lot = "0.7.1"
tokio = "0.1.7"
error-chain = "0.12"
derive_more = "0.14.0"
log = "0.4.6"
exit-future = "0.1"
parity-codec = "3.1"
......
......@@ -27,10 +27,8 @@ use polkadot_primitives::{Block, Hash, BlockId, parachain::CollatorId, parachain
}};
use runtime_primitives::traits::ProvideRuntimeApi;
use parachain::{wasm_executor::{self, ExternalitiesError}, MessageRef, UpwardMessageRef};
use error_chain::bail;
use futures::prelude::*;
use error_chain::*;
use log::debug;
/// Encapsulates connections to collators and allows collation on any parachain.
......@@ -136,62 +134,47 @@ impl<C: Collators, P: ProvideRuntimeApi> Future for CollationFetch<C, P>
}
// Errors that can occur when validating a parachain.
error_chain! {
types { Error, ErrorKind, ResultExt; }
foreign_links {
Client(::client::error::Error);
}
links {
WasmValidation(wasm_executor::Error, wasm_executor::ErrorKind);
}
#[derive(Debug, derive_more::Display, derive_more::From)]
pub enum Error {
/// Client error
Client(client::error::Error),
/// Wasm validation error
WasmValidation(wasm_executor::Error),
/// Collated for inactive parachain
#[display(fmt = "Collated for inactive parachain: {:?}", _0)]
InactiveParachain(ParaId),
/// Unexpected egress root
#[display(fmt = "Got unexpected egress root to {:?}. (expected: {:?}, got {:?})", id, expected, got)]
EgressRootMismatch { id: ParaId, expected: Hash, got: Hash },
/// Unexpected ingress root
#[display(fmt = "Got unexpected ingress root to {:?}. (expected: {:?}, got {:?})", id, expected, got)]
IngressRootMismatch { id: ParaId, expected: Hash, got: Hash },
/// Ingress from wrong chain
#[display(fmt = "Got ingress from wrong chain. (expected: {:?}, got {:?})", expected, got)]
IngressChainMismatch { expected: ParaId, got: ParaId },
/// Ingress canonicality mismatch
#[display(fmt = "Got data for {} roots, expected {}", expected, got)]
IngressCanonicalityMismatch { expected: usize, got: usize },
/// Missing or extra egress root
#[display(fmt = "Missing or extra egress root. (expected: {:?}, got {:?})", expected, got)]
MissingEgressRoot { expected: Option<ParaId>, got: Option<ParaId>, },
/// Parachain validation produced wrong head data
#[display(fmt = "Parachain validation produced wrong head data (expected: {:?}, got {:?})", expected, got)]
WrongHeadData { expected: Vec<u8>, got: Vec<u8> },
/// Block data is too big
#[display(fmt = "Block data is too big (maximum allowed size: {}, actual size: {})", size, max_size)]
BlockDataTooBig { size: u64, max_size: u64 },
/// Parachain validation produced wrong relay-chain messages
#[display(fmt = "Parachain validation produced wrong relay-chain messages (expected: {:?}, got {:?})", expected, got)]
UpwardMessagesInvalid { expected: Vec<UpwardMessage>, got: Vec<UpwardMessage> },
}
errors {
InactiveParachain(id: ParaId) {
description("Collated for inactive parachain"),
display("Collated for inactive parachain: {:?}", id),
}
EgressRootMismatch(id: ParaId, expected: Hash, got: Hash) {
description("Got unexpected egress root."),
display(
"Got unexpected egress root to {:?}. (expected: {:?}, got {:?})",
id, expected, got
),
}
IngressRootMismatch(id: ParaId, expected: Hash, got: Hash) {
description("Got unexpected ingress root."),
display(
"Got unexpected ingress root to {:?}. (expected: {:?}, got {:?})",
id, expected, got
),
}
IngressChainMismatch(expected: ParaId, got: ParaId) {
description("Got ingress from wrong chain"),
display(
"Got ingress from wrong chain. (expected: {:?}, got {:?})",
expected, got
),
}
IngressCanonicalityMismatch(expected: usize, got: usize) {
description("Ingress canonicality mismatch."),
display("Got data for {} roots, expected {}", got, expected),
}
MissingEgressRoot(expected: Option<ParaId>, got: Option<ParaId>) {
description("Missing or extra egress root."),
display("Missing or extra egress root. (expected: {:?}, got {:?})", expected, got),
}
WrongHeadData(expected: Vec<u8>, got: Vec<u8>) {
description("Parachain validation produced wrong head data."),
display("Parachain validation produced wrong head data (expected: {:?}, got {:?})", expected, got),
}
BlockDataTooBig(size: u64, max_size: u64) {
description("Block data is too big."),
display("Block data is too big (maximum allowed size: {}, actual size: {})", max_size, size),
}
UpwardMessagesInvalid(expected: Vec<UpwardMessage>, got: Vec<UpwardMessage>) {
description("Parachain validation produced wrong relay-chain messages."),
display("Parachain validation produced wrong relay-chain messages (expected: {:?}, got {:?})", expected, got),
impl std::error::Error for Error {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match self {
Error::Client(ref err) => Some(err),
Error::WasmValidation(ref err) => Some(err),
_ => None,
}
}
}
......@@ -240,11 +223,17 @@ fn check_extrinsic(
let mut expected_egress_roots = expected_egress_roots.iter();
while let Some(batch_target) = messages_iter.peek().map(|o| o.target) {
let expected_root = match expected_egress_roots.next() {
None => return Err(ErrorKind::MissingEgressRoot(Some(batch_target), None).into()),
None => return Err(Error::MissingEgressRoot {
expected: Some(batch_target),
got: None
}),
Some(&(id, ref root)) => if id == batch_target {
root
} else {
return Err(ErrorKind::MissingEgressRoot(Some(batch_target), Some(id)).into());
return Err(Error::MissingEgressRoot{
expected: Some(batch_target),
got: Some(id)
});
}
};
......@@ -258,17 +247,17 @@ fn check_extrinsic(
let computed_root = message_queue_root(messages_to);
if &computed_root != expected_root {
return Err(ErrorKind::EgressRootMismatch(
batch_target,
expected_root.clone(),
computed_root,
).into());
return Err(Error::EgressRootMismatch {
id: batch_target,
expected: expected_root.clone(),
got: computed_root,
});
}
}
// also check that there are no more additional expected roots.
if let Some((next_target, _)) = expected_egress_roots.next() {
return Err(ErrorKind::MissingEgressRoot(None, Some(*next_target)).into());
return Err(Error::MissingEgressRoot { expected: None, got: Some(*next_target) });
}
}
......@@ -320,10 +309,10 @@ impl Externalities {
candidate: &CandidateReceipt,
) -> Result<Extrinsic, Error> {
if &self.upward != &candidate.upward_messages {
bail!(ErrorKind::UpwardMessagesInvalid(
candidate.upward_messages.clone(),
self.upward.clone(),
));
return Err(Error::UpwardMessagesInvalid {
expected: candidate.upward_messages.clone(),
got: self.upward.clone(),
});
}
check_extrinsic(
......@@ -339,18 +328,28 @@ pub fn validate_incoming(
ingress: &ConsolidatedIngress,
) -> Result<(), Error> {
if roots.0.len() != ingress.0.len() {
bail!(ErrorKind::IngressCanonicalityMismatch(roots.0.len(), ingress.0.len()));
return Err(Error::IngressCanonicalityMismatch {
expected: roots.0.len(),
got: ingress.0.len()
});
}
let all_iter = roots.0.iter().zip(&ingress.0);
for ((expected_id, root), (got_id, messages)) in all_iter {
if expected_id != got_id {
bail!(ErrorKind::IngressChainMismatch(*expected_id, *got_id));
return Err(Error::IngressChainMismatch {
expected: *expected_id,
got: *got_id
});
}
let got_root = message_queue_root(messages.iter().map(|msg| &msg.0[..]));
if &got_root != root {
bail!(ErrorKind::IngressRootMismatch(*expected_id, *root, got_root));
return Err(Error::IngressRootMismatch{
id: *expected_id,
expected: *root,
got: got_root
});
}
}
......@@ -375,20 +374,20 @@ pub fn validate_collation<P>(
if let Some(max_size) = max_block_data_size {
let block_data_size = collation.pov.block_data.0.len() as u64;
if block_data_size > max_size {
return Err(ErrorKind::BlockDataTooBig(block_data_size, max_size).into());
return Err(Error::BlockDataTooBig { size: block_data_size, max_size });
}
}
let api = client.runtime_api();
let para_id = collation.receipt.parachain_index;
let validation_code = api.parachain_code(relay_parent, para_id)?
.ok_or_else(|| ErrorKind::InactiveParachain(para_id))?;
.ok_or_else(|| Error::InactiveParachain(para_id))?;
let chain_head = api.parachain_head(relay_parent, para_id)?
.ok_or_else(|| ErrorKind::InactiveParachain(para_id))?;
.ok_or_else(|| Error::InactiveParachain(para_id))?;
let roots = api.ingress(relay_parent, para_id)?
.ok_or_else(|| ErrorKind::InactiveParachain(para_id))?;
.ok_or_else(|| Error::InactiveParachain(para_id))?;
validate_incoming(&roots, &collation.pov.ingress)?;
let params = ValidationParams {
......@@ -415,10 +414,10 @@ pub fn validate_collation<P>(
if result.head_data == collation.receipt.head_data.0 {
ext.final_checks(&collation.receipt)
} else {
Err(ErrorKind::WrongHeadData(
collation.receipt.head_data.0.clone(),
result.head_data
).into())
Err(Error::WrongHeadData {
expected: collation.receipt.head_data.0.clone(),
got: result.head_data
})
}
}
Err(e) => Err(e.into())
......
......@@ -18,38 +18,44 @@
use runtime_primitives::RuntimeString;
use primitives::ed25519::Public as AuthorityId;
use error_chain::*;
error_chain! {
foreign_links {
Client(::client::error::Error);
Consensus(::consensus::error::Error);
}
/// Error type for validation
#[derive(Debug, derive_more::Display, derive_more::From)]
pub enum Error {
/// Client error
Client(client::error::Error),
/// Consensus error
Consensus(consensus::error::Error),
#[display(fmt = "Invalid duty roster length: expected {}, got {}", expected, got)]
InvalidDutyRosterLength {
/// Expected roster length
expected: usize,
/// Actual roster length
got: usize,
},
/// Local account not a validator at this block
#[display(fmt = "Local account ID ({:?}) not a validator at this block.", _0)]
NotValidator(AuthorityId),
/// Unexpected error checking inherents
#[display(fmt = "Unexpected error while checking inherents: {}", _0)]
InherentError(RuntimeString),
/// Proposer destroyed before finishing proposing or evaluating
#[display(fmt = "Proposer destroyed before finishing proposing or evaluating")]
PrematureDestruction,
/// Timer failed
#[display(fmt = "Timer failed: {}", _0)]
Timer(tokio::timer::Error),
/// Unable to dispatch agreement future
#[display(fmt = "Unable to dispatch agreement future: {:?}", _0)]
Executor(futures::future::ExecuteErrorKind),
}
errors {
InvalidDutyRosterLength(expected: usize, got: usize) {
description("Duty Roster had invalid length"),
display("Invalid duty roster length: expected {}, got {}", expected, got),
}
NotValidator(id: AuthorityId) {
description("Local account ID not a validator at this block."),
display("Local account ID ({:?}) not a validator at this block.", id),
}
InherentError(reason: RuntimeString) {
description("Unexpected error while checking inherents"),
display("Unexpected error while checking inherents: {}", reason),
}
PrematureDestruction {
description("Proposer destroyed before finishing proposing or evaluating"),
display("Proposer destroyed before finishing proposing or evaluating"),
}
Timer(e: ::tokio::timer::Error) {
description("Failed to register or resolve async timer."),
display("Timer failed: {}", e),
}
Executor(e: ::futures::future::ExecuteErrorKind) {
description("Unable to dispatch agreement future"),
display("Unable to dispatch agreement future: {:?}", e),
impl std::error::Error for Error {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match self {
Error::Client(ref err) => Some(err),
Error::Consensus(ref err) => Some(err),
_ => None,
}
}
}
......@@ -21,44 +21,40 @@ use super::MAX_TRANSACTIONS_SIZE;
use parity_codec::Encode;
use polkadot_primitives::{Block, Hash, BlockNumber};
use polkadot_primitives::parachain::Id as ParaId;
use error_chain::*;
error_chain! {
foreign_links {
Client(::client::error::Error);
}
/// Result type alias for block evaluation
pub type Result<T> = std::result::Result<T, Error>;
errors {
ProposalNotForPolkadot {
description("Proposal provided not a Polkadot block."),
display("Proposal provided not a Polkadot block."),
}
TooManyCandidates(expected: usize, got: usize) {
description("Proposal included more candidates than is possible."),
display("Proposal included {} candidates for {} parachains", got, expected),
}
ParachainOutOfOrder {
description("Proposal included parachains out of order."),
display("Proposal included parachains out of order."),
}
UnknownParachain(id: ParaId) {
description("Proposal included unregistered parachain."),
display("Proposal included unregistered parachain {:?}", id),
}
WrongParentHash(expected: Hash, got: Hash) {
description("Proposal had wrong parent hash."),
display("Proposal had wrong parent hash. Expected {:?}, got {:?}", expected, got),
}
WrongNumber(expected: BlockNumber, got: BlockNumber) {
description("Proposal had wrong number."),
display("Proposal had wrong number. Expected {:?}, got {:?}", expected, got),
}
ProposalTooLarge(size: usize) {
description("Proposal exceeded the maximum size."),
display(
"Proposal exceeded the maximum size of {} by {} bytes.",
MAX_TRANSACTIONS_SIZE, MAX_TRANSACTIONS_SIZE.saturating_sub(*size)
),
/// Error type for block evaluation
#[derive(Debug, derive_more::Display, derive_more::From)]
pub enum Error {
/// Client error
Client(client::error::Error),
/// Too many parachain candidates in proposal
#[display(fmt = "Proposal included {} candidates for {} parachains", expected, got)]
TooManyCandidates { expected: usize, got: usize },
/// Proposal included unregistered parachain
#[display(fmt = "Proposal included unregistered parachain {:?}", _0)]
UnknownParachain(ParaId),
/// Proposal had wrong parent hash
#[display(fmt = "Proposal had wrong parent hash. Expected {:?}, got {:?}", expected, got)]
WrongParentHash { expected: Hash, got: Hash },
/// Proposal had wrong number
#[display(fmt = "Proposal had wrong number. Expected {:?}, got {:?}", expected, got)]
WrongNumber { expected: BlockNumber, got: BlockNumber },
/// Proposal exceeded the maximum size
#[display(
fmt = "Proposal exceeded the maximum size of {} by {} bytes.",
MAX_TRANSACTIONS_SIZE, MAX_TRANSACTIONS_SIZE.saturating_sub(*_0)
)]
ProposalTooLarge(usize),
}
impl std::error::Error for Error {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match self {
Error::Client(ref err) => Some(err),
_ => None,
}
}
}
......@@ -77,15 +73,21 @@ pub fn evaluate_initial(
});
if transactions_size > MAX_TRANSACTIONS_SIZE {
bail!(ErrorKind::ProposalTooLarge(transactions_size))
return Err(Error::ProposalTooLarge(transactions_size))
}
if proposal.header.parent_hash != *parent_hash {
bail!(ErrorKind::WrongParentHash(*parent_hash, proposal.header.parent_hash));
return Err(Error::WrongParentHash {
expected: *parent_hash,
got: proposal.header.parent_hash
});
}
if proposal.header.number != parent_number + 1 {
bail!(ErrorKind::WrongNumber(parent_number + 1, proposal.header.number));
return Err(Error::WrongNumber {
expected: parent_number + 1,
got: proposal.header.number
});
}
Ok(())
......
......@@ -62,14 +62,13 @@ use dynamic_inclusion::DynamicInclusion;
use inherents::InherentData;
use runtime_aura::timestamp::TimestampInherentData;
use log::{info, debug, warn, trace};
use error_chain::bail;
use ed25519::Public as AuthorityId;
pub use self::collation::{
validate_collation, validate_incoming, message_queue_root, egress_roots, Collators,
};
pub use self::error::{ErrorKind, Error};
pub use self::error::Error;
pub use self::shared_table::{
SharedTable, ParachainWork, PrimedParachainWork, Validated, Statement, SignedStatement,
GenericStatement,
......@@ -188,7 +187,10 @@ pub fn make_group_info(
local_id: AuthorityId,
) -> Result<(HashMap<ParaId, GroupInfo>, LocalDuty), Error> {
if roster.validator_duty.len() != authorities.len() {
bail!(ErrorKind::InvalidDutyRosterLength(authorities.len(), roster.validator_duty.len()))
return Err(Error::InvalidDutyRosterLength {
expected: authorities.len(),
got: roster.validator_duty.len()
});
}