Custom runtime module errors (#3433)

* srml-system checks

* wip

* more modules compiles

* node-runtime checks

* build.sh passes

* include dispatch error in failed event

* revert some unnecessary changes

* refactor based on comments

* more compile error fixes

* avoid unnecessary into

* reorder code

* fixes some tests

* manually implement encode & decode to avoid i8 workaround

* more test fixes

* more fixes

* more error fixes

* Apply suggestions from code review

Co-Authored-By: Tomasz Drwięga <tomusdrw@users.noreply.github.com>

* address comments

* test for DispatchError encoding

* tyep alias for democracy

* make error printable

* line width

* fix balances tests

* fix executive test

* fix system tests

* bump version

* ensure consistent method signature

* Apply suggestions from code review

Co-Authored-By: Gavin Wood <github@gavwood.com>

* changes based on review

* Add issue number for TODOs

* fix

* line width

* fix test

* Update core/sr-primitives/src/lib.rs

Co-Authored-By: Bastian Köcher <bkchr@users.noreply.github.com>

* Update core/sr-primitives/src/traits.rs

Co-Authored-By: Bastian Köcher <bkchr@users.noreply.github.com>

* Update srml/council/src/motions.rs

Co-Authored-By: Bastian Köcher <bkchr@users.noreply.github.com>

* Update srml/council/src/motions.rs

Co-Authored-By: Bastian Köcher <bkchr@users.noreply.github.com>

* update based on review

* More concrete macro matching

* fix test build issue

* Update hex-literal dependency version. (#3141)

* Update hex-literal dep version.

* Update lock file.

* Start to rework the new error handling

* More work to get it back compiling

* Start to fix after master merge

* The great transaction error handling refactoring

* Make `decl_error` errors convertible to `&'static str`

* Make srml-executive build again

* Fix `sr-primitives` tests

* More fixes

* Last round of fix ups

* Fix build

* Fix build

* Apply suggestions from code review

Co-Authored-By: Tomasz Drwięga <tomusdrw@users.noreply.github.com>

* Rename some stuff

* Fixes after master merge

* Adds `CheckBlockGasLimit` signed extension

* Remove debug stuff

* Fix srml-balances test

* Rename `InvalidIndex` to `CannotLookup`

* Remove weird generic parameters

* Rename function again

* Fix import

* Document the signed extension

* Change from `Into` to `From`

* Update srml/contracts/src/lib.rs

Co-Authored-By: Sergei Pepyakin <sergei@parity.io>

* Fix compilation

* Update srml/contracts/src/lib.rs

Co-Authored-By: Tomasz Drwięga <tomusdrw@users.noreply.github.com>

* Update core/sr-primitives/src/transaction_validity.rs

Co-Authored-By: Tomasz Drwięga <tomusdrw@users.noreply.github.com>

* Remove unused code

* Fix compilation

* Some cleanups

* Fix compile errors

* Make `TransactionValidity` a `Result`

* Apply suggestions from code review

Co-Authored-By: Gavin Wood <gavin@parity.io>

* Beautify the code a little bit and fix test

* Make `CannotLookup` an inherent error declared by `decl_error!`

* Adds some documentation

* Make `ApplyOutcome` a result

* Up the spec_version

* Apply suggestions from code review

Co-Authored-By: Gavin Wood <gavin@parity.io>
Co-Authored-By: DemiMarie-parity <48690212+DemiMarie-parity@users.noreply.github.com>
This commit is contained in:
Bastian Köcher
2019-09-04 16:21:42 +02:00
committed by GitHub
parent 5e4bc7c9b6
commit c6f3798078
46 changed files with 1259 additions and 630 deletions
+114 -48
View File
@@ -58,19 +58,6 @@ pub use generic::{DigestItem, Digest};
pub use primitives::crypto::{key_types, KeyTypeId, CryptoType};
pub use app_crypto::AppKey;
/// A message indicating an invalid signature in extrinsic.
pub const BAD_SIGNATURE: &str = "bad signature in extrinsic";
/// Full block error message.
///
/// This allows modules to indicate that given transaction is potentially valid
/// in the future, but can't be executed in the current state.
/// Note this error should be returned early in the execution to prevent DoS,
/// cause the fees are not being paid if this error is returned.
///
/// Example: block gas limit is reached (the transaction can be retried in the next block though).
pub const BLOCK_FULL: &str = "block size limit is reached";
/// Justification type.
pub type Justification = Vec<u8>;
@@ -636,53 +623,111 @@ impl From<ed25519::Signature> for AnySignature {
}
}
#[derive(Eq, PartialEq, Clone, Copy, Decode)]
#[derive(Eq, PartialEq, Clone, Copy, Decode, Encode)]
#[cfg_attr(feature = "std", derive(Debug, Serialize))]
#[repr(u8)]
/// Outcome of a valid extrinsic application. Capable of being sliced.
pub enum ApplyOutcome {
/// Successful application (extrinsic reported no issue).
Success = 0,
/// Failed application (extrinsic was probably a no-op other than fees).
Fail = 1,
}
impl codec::Encode for ApplyOutcome {
fn using_encoded<R, F: FnOnce(&[u8]) -> R>(&self, f: F) -> R {
f(&[*self as u8])
}
}
impl codec::EncodeLike for ApplyOutcome {}
#[derive(Eq, PartialEq, Clone, Copy, Decode)]
#[cfg_attr(feature = "std", derive(Debug, Serialize))]
#[repr(u8)]
/// Reason why an extrinsic couldn't be applied (i.e. invalid extrinsic).
pub enum ApplyError {
/// Bad signature.
BadSignature = 0,
/// Nonce too low.
Stale = 1,
/// Nonce too high.
Future = 2,
/// Sending account had too low a balance.
CantPay = 3,
/// Block is full, no more extrinsics can be applied.
FullBlock = 255,
/// General error to do with the permissions of the sender.
NoPermission,
/// General error to do with the state of the system in general.
BadState,
/// Any error to do with the transaction validity.
Validity(transaction_validity::TransactionValidityError),
}
impl codec::Encode for ApplyError {
fn using_encoded<R, F: FnOnce(&[u8]) -> R>(&self, f: F) -> R {
f(&[*self as u8])
impl ApplyError {
/// Returns if the reason for the error was block resource exhaustion.
pub fn exhausted_resources(&self) -> bool {
match self {
Self::Validity(e) => e.exhausted_resources(),
_ => false,
}
}
}
impl codec::EncodeLike for ApplyError {}
impl From<ApplyError> for &'static str {
fn from(err: ApplyError) -> &'static str {
match err {
ApplyError::NoPermission => "Transaction does not have required permissions",
ApplyError::BadState => "System state currently prevents this transaction",
ApplyError::Validity(v) => v.into(),
}
}
}
impl From<transaction_validity::TransactionValidityError> for ApplyError {
fn from(err: transaction_validity::TransactionValidityError) -> Self {
ApplyError::Validity(err)
}
}
/// The outcome of applying a transaction.
pub type ApplyOutcome = Result<(), DispatchError>;
impl From<DispatchError> for ApplyOutcome {
fn from(err: DispatchError) -> Self {
Err(err)
}
}
/// Result from attempt to apply an extrinsic.
pub type ApplyResult = Result<ApplyOutcome, ApplyError>;
#[derive(Eq, PartialEq, Clone, Copy, Encode, Decode)]
#[cfg_attr(feature = "std", derive(Debug, Serialize))]
/// Reason why a dispatch call failed
pub struct DispatchError {
/// Module index, matching the metadata module index
pub module: Option<u8>,
/// Module specific error value
pub error: u8,
/// Optional error message.
#[codec(skip)]
pub message: Option<&'static str>,
}
impl DispatchError {
/// Create a new instance of `DispatchError`.
pub fn new(module: Option<u8>, error: u8, message: Option<&'static str>) -> Self {
Self {
module,
error,
message,
}
}
}
impl runtime_io::Printable for DispatchError {
fn print(&self) {
"DispatchError".print();
if let Some(module) = self.module {
module.print();
}
self.error.print();
if let Some(msg) = self.message {
msg.print();
}
}
}
impl traits::ModuleDispatchError for &'static str {
fn as_u8(&self) -> u8 {
0
}
fn as_str(&self) -> &'static str {
self
}
}
impl From<&'static str> for DispatchError {
fn from(err: &'static str) -> DispatchError {
DispatchError::new(None, 0, Some(err))
}
}
/// Verify a signature on an encoded value in a lazy manner. This can be
/// an optimization if the signature scheme has an "unsigned" escape hash.
pub fn verify_encoded_lazy<V: Verify, T: codec::Encode>(sig: &V, item: &T, signer: &V::Signer) -> bool {
@@ -852,6 +897,7 @@ impl traits::Extrinsic for OpaqueExtrinsic {
#[cfg(test)]
mod tests {
use super::DispatchError;
use crate::codec::{Encode, Decode};
use super::{Perbill, Permill};
@@ -967,6 +1013,26 @@ mod tests {
);
}
#[test]
fn dispatch_error_encoding() {
let error = DispatchError {
module: Some(1),
error: 2,
message: Some("error message"),
};
let encoded = error.encode();
let decoded = DispatchError::decode(&mut &encoded[..]).unwrap();
assert_eq!(encoded, vec![1, 1, 2]);
assert_eq!(
decoded,
DispatchError {
module: Some(1),
error: 2,
message: None,
},
);
}
#[test]
fn per_bill_square() {
const FIXTURES: &[(u32, u32)] = &[