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
+25 -15
View File
@@ -161,19 +161,26 @@
use rstd::prelude::*;
use rstd::{cmp, result, mem};
use codec::{Codec, Encode, Decode};
use support::{StorageValue, StorageMap, Parameter, decl_event, decl_storage, decl_module};
use support::traits::{
UpdateBalanceOutcome, Currency, OnFreeBalanceZero, OnUnbalanced,
WithdrawReason, WithdrawReasons, LockIdentifier, LockableCurrency, ExistenceRequirement,
Imbalance, SignedImbalance, ReservableCurrency, Get,
use support::{
StorageValue, StorageMap, Parameter, decl_event, decl_storage, decl_module,
traits::{
UpdateBalanceOutcome, Currency, OnFreeBalanceZero, OnUnbalanced,
WithdrawReason, WithdrawReasons, LockIdentifier, LockableCurrency, ExistenceRequirement,
Imbalance, SignedImbalance, ReservableCurrency, Get,
},
dispatch::Result,
};
use support::dispatch::Result;
use sr_primitives::traits::{
Zero, SimpleArithmetic, StaticLookup, Member, CheckedAdd, CheckedSub, MaybeSerializeDebug,
Saturating, Bounded, SignedExtension, SaturatedConversion, DispatchError, Convert,
use sr_primitives::{
transaction_validity::{
TransactionPriority, ValidTransaction, InvalidTransaction, TransactionValidityError,
TransactionValidity,
},
traits::{
Zero, SimpleArithmetic, StaticLookup, Member, CheckedAdd, CheckedSub, MaybeSerializeDebug,
Saturating, Bounded, SignedExtension, SaturatedConversion, Convert,
},
weights::{DispatchInfo, SimpleDispatchInfo, Weight},
};
use sr_primitives::transaction_validity::{TransactionPriority, ValidTransaction};
use sr_primitives::weights::{DispatchInfo, SimpleDispatchInfo, Weight};
use system::{IsDeadAccount, OnNewAccount, ensure_signed, ensure_root};
mod mock;
@@ -1235,7 +1242,7 @@ impl<T: Trait<I>, I: Instance + Clone + Eq> SignedExtension for TakeFees<T, I> {
type Call = T::Call;
type AdditionalSigned = ();
type Pre = ();
fn additional_signed(&self) -> rstd::result::Result<(), &'static str> { Ok(()) }
fn additional_signed(&self) -> rstd::result::Result<(), TransactionValidityError> { Ok(()) }
fn validate(
&self,
@@ -1243,15 +1250,18 @@ impl<T: Trait<I>, I: Instance + Clone + Eq> SignedExtension for TakeFees<T, I> {
_call: &Self::Call,
info: DispatchInfo,
len: usize,
) -> rstd::result::Result<ValidTransaction, DispatchError> {
) -> TransactionValidity {
// pay any fees.
let fee = Self::compute_fee(len, info, self.0);
let imbalance = <Module<T, I>>::withdraw(
let imbalance = match <Module<T, I>>::withdraw(
who,
fee,
WithdrawReason::TransactionPayment,
ExistenceRequirement::KeepAlive,
).map_err(|_| DispatchError::Payment)?;
) {
Ok(imbalance) => imbalance,
Err(_) => return InvalidTransaction::Payment.into(),
};
T::TransactionPayment::on_unbalanced(imbalance);
let mut r = ValidTransaction::default();
+9 -6
View File
@@ -232,7 +232,7 @@ fn default_indexing_on_new_accounts_should_not_work2() {
// ext_deposit is 10, value is 9, not satisfies for ext_deposit
assert_noop!(
Balances::transfer(Some(1).into(), 5, 9),
"value too low to create account"
"value too low to create account",
);
assert_eq!(Balances::is_dead_account(&5), true); // account 5 should not exist
assert_eq!(Balances::free_balance(&1), 100);
@@ -359,7 +359,7 @@ fn force_transfer_works() {
let _ = Balances::deposit_creating(&1, 111);
assert_noop!(
Balances::force_transfer(Some(2).into(), 1, 2, 69),
"bad origin: expected to be a root origin"
"RequireRootOrigin",
);
assert_ok!(Balances::force_transfer(RawOrigin::Root.into(), 1, 2, 69));
assert_eq!(Balances::total_balance(&1), 42);
@@ -389,7 +389,10 @@ fn balance_transfer_when_reserved_should_not_work() {
with_externalities(&mut ExtBuilder::default().build(), || {
let _ = Balances::deposit_creating(&1, 111);
assert_ok!(Balances::reserve(&1, 69));
assert_noop!(Balances::transfer(Some(1).into(), 2, 69), "balance too low to send value");
assert_noop!(
Balances::transfer(Some(1).into(), 2, 69),
"balance too low to send value",
);
});
}
@@ -517,7 +520,7 @@ fn transferring_too_high_value_should_not_panic() {
assert_err!(
Balances::transfer(Some(1).into(), 2, u64::max_value()),
"destination balance too high to receive value"
"destination balance too high to receive value",
);
assert_eq!(Balances::free_balance(&1), u64::max_value());
@@ -595,7 +598,7 @@ fn transfer_overflow_isnt_exploitable() {
assert_err!(
Balances::transfer(Some(1).into(), 5, evil_value),
"got overflow after adding a fee to value"
"got overflow after adding a fee to value",
);
}
);
@@ -680,7 +683,7 @@ fn unvested_balance_should_not_transfer() {
assert_eq!(Balances::vesting_balance(&1), 45);
assert_noop!(
Balances::transfer(Some(1).into(), 2, 56),
"vesting balance too high to send value"
"vesting balance too high to send value",
); // Account 1 cannot send more than vested amount
}
);
+6 -12
View File
@@ -16,10 +16,12 @@
use crate::{GasSpent, Module, Trait, BalanceOf, NegativeImbalanceOf};
use rstd::convert::TryFrom;
use sr_primitives::BLOCK_FULL;
use sr_primitives::traits::{CheckedMul, Zero, SaturatedConversion, SimpleArithmetic, UniqueSaturatedInto};
use support::StorageValue;
use support::traits::{Currency, ExistenceRequirement, Get, Imbalance, OnUnbalanced, WithdrawReason};
use sr_primitives::traits::{
CheckedMul, Zero, SaturatedConversion, SimpleArithmetic, UniqueSaturatedInto,
};
use support::{
traits::{Currency, ExistenceRequirement, Imbalance, OnUnbalanced, WithdrawReason}, StorageValue,
};
#[cfg(test)]
use std::{any::Any, fmt::Debug};
@@ -200,14 +202,6 @@ pub fn buy_gas<T: Trait>(
transactor: &T::AccountId,
gas_limit: Gas,
) -> Result<(GasMeter<T>, NegativeImbalanceOf<T>), &'static str> {
// Check if the specified amount of gas is available in the current block.
// This cannot underflow since `gas_spent` is never greater than `T::BlockGasLimit`.
let gas_available = T::BlockGasLimit::get() - <Module<T>>::gas_spent();
if gas_limit > gas_available {
// gas limit reached, revert the transaction and retry again in the future
return Err(BLOCK_FULL);
}
// Buy the specified amount of gas.
let gas_price = <Module<T>>::gas_price();
let cost = if gas_price.is_zero() {
+85 -11
View File
@@ -63,6 +63,15 @@
//! This creates a new smart contract account and calls its contract deploy handler to initialize the contract.
//! * `call` - Makes a call to an account, optionally transferring some balance.
//!
//! ### Signed Extensions
//!
//! The contracts module defines the following extension:
//!
//! - [`CheckBlockGasLimit`]: Ensures that the transaction does not exceeds the block gas limit.
//!
//! The signed extension needs to be added as signed extra to the transaction type to be used in the
//! runtime.
//!
//! ## Usage
//!
//! The Contract module is a work in progress. The following examples show how this Contract module can be
@@ -100,15 +109,19 @@ use primitives::crypto::UncheckedFrom;
use rstd::{prelude::*, marker::PhantomData};
use codec::{Codec, Encode, Decode};
use runtime_io::blake2_256;
use sr_primitives::traits::{
Hash, StaticLookup, Zero, MaybeSerializeDebug, Member
use sr_primitives::{
traits::{Hash, StaticLookup, Zero, MaybeSerializeDebug, Member, SignedExtension},
weights::DispatchInfo,
transaction_validity::{
ValidTransaction, InvalidTransaction, TransactionValidity, TransactionValidityError,
},
};
use support::dispatch::{Result, Dispatchable};
use support::{
Parameter, StorageMap, StorageValue, decl_module, decl_event, decl_storage, storage::child,
parameter_types,
};
use support::traits::{OnFreeBalanceZero, OnUnbalanced, Currency, Get};
use support::{traits::{OnFreeBalanceZero, OnUnbalanced, Currency, Get}, IsSubType};
use system::{ensure_signed, RawOrigin, ensure_root};
use primitives::storage::well_known_keys::CHILD_STORAGE_KEY_PREFIX;
use timestamp;
@@ -321,7 +334,7 @@ pub trait Trait: timestamp::Trait {
type Currency: Currency<Self::AccountId>;
/// The outer call dispatch type.
type Call: Parameter + Dispatchable<Origin=<Self as system::Trait>::Origin>;
type Call: Parameter + Dispatchable<Origin=<Self as system::Trait>::Origin> + IsSubType<Module<Self>, Self>;
/// The overarching event type.
type Event: From<Event<Self>> + Into<<Self as system::Trait>::Event>;
@@ -597,15 +610,17 @@ decl_module! {
/// the sender is not eligible for the reward.
fn claim_surcharge(origin, dest: T::AccountId, aux_sender: Option<T::AccountId>) {
let origin = origin.into();
let (signed, rewarded) = match origin {
Ok(system::RawOrigin::Signed(ref account)) if aux_sender.is_none() => {
let (signed, rewarded) = match (origin, aux_sender) {
(Ok(system::RawOrigin::Signed(account)), None) => {
(true, account)
},
Ok(system::RawOrigin::None) if aux_sender.is_some() => {
(false, aux_sender.as_ref().expect("checked above"))
(Ok(system::RawOrigin::None), Some(aux_sender)) => {
(false, aux_sender)
},
_ => return Err("Invalid surcharge claim: origin must be signed or \
inherent and auxiliary sender only provided on inherent")
_ => return Err(
"Invalid surcharge claim: origin must be signed or \
inherent and auxiliary sender only provided on inherent"
),
};
// Add some advantage for block producers (who send unsigned extrinsics) by
@@ -619,7 +634,7 @@ decl_module! {
// If poking the contract has lead to eviction of the contract, give out the rewards.
if rent::try_evict::<T>(&dest, handicap) == rent::RentOutcome::Evicted {
T::Currency::deposit_into_existing(rewarded, T::SurchargeReward::get())?;
T::Currency::deposit_into_existing(&rewarded, T::SurchargeReward::get())?;
}
}
@@ -937,3 +952,62 @@ impl Default for Schedule {
}
}
}
/// `SignedExtension` that checks if a transaction would exhausts the block gas limit.
#[derive(Encode, Decode, Clone, Eq, PartialEq)]
pub struct CheckBlockGasLimit<T: Trait + Send + Sync>(PhantomData<T>);
impl<T: Trait + Send + Sync> Default for CheckBlockGasLimit<T> {
fn default() -> Self {
Self(PhantomData)
}
}
#[cfg(feature = "std")]
impl<T: Trait + Send + Sync> std::fmt::Debug for CheckBlockGasLimit<T> {
fn fmt(&self, _: &mut std::fmt::Formatter) -> std::fmt::Result {
Ok(())
}
}
impl<T: Trait + Send + Sync> SignedExtension for CheckBlockGasLimit<T> {
type AccountId = T::AccountId;
type Call = <T as Trait>::Call;
type AdditionalSigned = ();
type Pre = ();
fn additional_signed(&self) -> rstd::result::Result<(), TransactionValidityError> { Ok(()) }
fn validate(
&self,
_: &Self::AccountId,
call: &Self::Call,
_: DispatchInfo,
_: usize,
) -> TransactionValidity {
let call = match call.is_sub_type() {
Some(call) => call,
None => return Ok(ValidTransaction::default()),
};
match call {
Call::claim_surcharge(_, _) | Call::update_schedule(_) =>
Ok(ValidTransaction::default()),
Call::put_code(gas_limit, _)
| Call::call(_, _, gas_limit, _)
| Call::create(_, gas_limit, _, _)
=> {
// Check if the specified amount of gas is available in the current block.
// This cannot underflow since `gas_spent` is never greater than `T::BlockGasLimit`.
let gas_available = T::BlockGasLimit::get() - <Module<T>>::gas_spent();
if *gas_limit > gas_available {
// gas limit reached, revert the transaction and retry again in the future
InvalidTransaction::ExhaustsResources.into()
} else {
Ok(ValidTransaction::default())
}
},
Call::__PhantomItem(_, _) => unreachable!("Variant is never constructed"),
}
}
}
+29 -10
View File
@@ -22,27 +22,27 @@
use crate::account_db::{AccountDb, DirectAccountDb, OverlayAccountDb};
use crate::{
BalanceOf, ComputeDispatchFee, ContractAddressFor, ContractInfo, ContractInfoOf, GenesisConfig,
Module, RawAliveContractInfo, RawEvent, Trait, TrieId, TrieIdFromParentCounter,
TrieIdGenerator, Schedule,
Module, RawAliveContractInfo, RawEvent, Trait, TrieId, TrieIdFromParentCounter, Schedule,
TrieIdGenerator, CheckBlockGasLimit,
};
use assert_matches::assert_matches;
use hex_literal::*;
use codec::{Decode, Encode, KeyedVec};
use runtime_io;
use runtime_io::with_externalities;
use sr_primitives::testing::{Digest, DigestItem, Header, UintAuthorityId, H256};
use sr_primitives::traits::{BlakeTwo256, Hash, IdentityLookup};
use sr_primitives::{Perbill, BuildStorage};
use sr_primitives::{
Perbill, BuildStorage, transaction_validity::{InvalidTransaction, ValidTransaction},
traits::{BlakeTwo256, Hash, IdentityLookup, SignedExtension},
weights::{DispatchInfo, DispatchClass},
testing::{Digest, DigestItem, Header, UintAuthorityId, H256},
};
use support::{
assert_ok, assert_err, impl_outer_dispatch, impl_outer_event, impl_outer_origin, parameter_types,
storage::child, StorageMap, StorageValue, traits::{Currency, Get},
};
use std::cell::RefCell;
use std::sync::atomic::{AtomicUsize, Ordering};
use primitives::storage::well_known_keys;
use primitives::Blake2Hasher;
use std::{cell::RefCell, sync::atomic::{AtomicUsize, Ordering}};
use primitives::{storage::well_known_keys, Blake2Hasher};
use system::{self, EventRecord, Phase};
use {balances, wabt};
mod contract {
// Re-export contents of the root. This basically
@@ -2390,3 +2390,22 @@ fn cannot_self_destruct_in_constructor() {
}
);
}
#[test]
fn check_block_gas_limit_works() {
with_externalities(
&mut ExtBuilder::default().block_gas_limit(50).build(),
|| {
let info = DispatchInfo { weight: 100, class: DispatchClass::Normal };
let check = CheckBlockGasLimit::<Test>(Default::default());
let call: Call = crate::Call::put_code(1000, vec![]).into();
assert_eq!(
check.validate(&0, &call, info, 0), InvalidTransaction::ExhaustsResources.into(),
);
let call: Call = crate::Call::update_schedule(Default::default()).into();
assert_eq!(check.validate(&0, &call, info, 0), Ok(Default::default()));
}
);
}
+4
View File
@@ -62,6 +62,8 @@ mod tests {
impl_outer_dispatch! {
pub enum Call for Test where origin: Origin {
type Error = Error;
balances::Balances,
democracy::Democracy,
}
@@ -115,6 +117,7 @@ mod tests {
type Header = Header;
type WeightMultiplierUpdate = ();
type Event = Event;
type Error = Error;
type BlockHashCount = BlockHashCount;
type MaximumBlockWeight = MaximumBlockWeight;
type MaximumBlockLength = MaximumBlockLength;
@@ -136,6 +139,7 @@ mod tests {
type TransactionPayment = ();
type TransferPayment = ();
type DustRemoval = ();
type Error = Error;
type ExistentialDeposit = ExistentialDeposit;
type TransferFee = TransferFee;
type CreationFee = CreationFee;
+5 -3
View File
@@ -20,12 +20,14 @@
use rstd::prelude::*;
use rstd::{result, convert::TryFrom};
use sr_primitives::traits::{Zero, Bounded, CheckedMul, CheckedDiv, EnsureOrigin, Hash};
use sr_primitives::weights::SimpleDispatchInfo;
use sr_primitives::{
traits::{Zero, Bounded, CheckedMul, CheckedDiv, EnsureOrigin, Hash, Dispatchable},
weights::SimpleDispatchInfo,
};
use codec::{Encode, Decode, Input, Output, Error};
use support::{
decl_module, decl_storage, decl_event, ensure, StorageValue, StorageMap, StorageLinkedMap,
Parameter, Dispatchable,
Parameter,
traits::{
Currency, ReservableCurrency, LockableCurrency, WithdrawReason, LockIdentifier, Get,
OnFreeBalanceZero
+2 -2
View File
@@ -504,7 +504,7 @@ decl_module! {
let who = ensure_signed(origin)?;
ensure!(
!total.is_zero(),
"stake deposited to present winner and be added to leaderboard should be non-zero"
"stake deposited to present winner and be added to leaderboard should be non-zero",
);
let candidate = T::Lookup::lookup(candidate)?;
@@ -1234,7 +1234,7 @@ mod tests {
UncheckedExtrinsic = UncheckedExtrinsic
{
System: system::{Module, Call, Event},
Balances: balances::{Module, Call, Event<T>, Config<T>},
Balances: balances::{Module, Call, Event<T>, Config<T>, Error},
Elections: elections::{Module, Call, Event<T>, Config<T>},
}
);
+15 -10
View File
@@ -258,9 +258,10 @@ use support::{StorageValue, dispatch::Result, decl_module, decl_storage, decl_ev
use system::{ensure_signed, ensure_root};
use codec::{Encode, Decode};
use sr_primitives::{
traits::{SignedExtension, DispatchError, Bounded},
transaction_validity::ValidTransaction,
weights::{SimpleDispatchInfo, DispatchInfo},
traits::{SignedExtension, Bounded}, weights::{SimpleDispatchInfo, DispatchInfo},
transaction_validity::{
ValidTransaction, TransactionValidityError, InvalidTransaction, TransactionValidity,
},
};
/// Our module's configuration trait. All our types and consts go in here. If the
@@ -561,7 +562,7 @@ impl<T: Trait + Send + Sync> SignedExtension for WatchDummy<T> {
type AdditionalSigned = ();
type Pre = ();
fn additional_signed(&self) -> rstd::result::Result<(), &'static str> { Ok(()) }
fn additional_signed(&self) -> rstd::result::Result<(), TransactionValidityError> { Ok(()) }
fn validate(
&self,
@@ -569,9 +570,11 @@ impl<T: Trait + Send + Sync> SignedExtension for WatchDummy<T> {
call: &Self::Call,
_info: DispatchInfo,
len: usize,
) -> rstd::result::Result<ValidTransaction, DispatchError> {
) -> TransactionValidity {
// if the transaction is too big, just drop it.
if len > 200 { return Err(DispatchError::Exhausted) }
if len > 200 {
return InvalidTransaction::ExhaustsResources.into()
}
// check for `set_dummy`
match call {
@@ -582,7 +585,7 @@ impl<T: Trait + Send + Sync> SignedExtension for WatchDummy<T> {
valid_tx.priority = Bounded::max_value();
Ok(valid_tx)
}
_ => Ok(Default::default())
_ => Ok(Default::default()),
}
}
}
@@ -712,12 +715,14 @@ mod tests {
let info = DispatchInfo::default();
assert_eq!(
WatchDummy::<Test>(PhantomData).validate(&1, &call, info, 150).unwrap().priority,
Bounded::max_value()
WatchDummy::<Test>(PhantomData).validate(&1, &call, info, 150)
.unwrap()
.priority,
Bounded::max_value(),
);
assert_eq!(
WatchDummy::<Test>(PhantomData).validate(&1, &call, info, 250),
Err(DispatchError::Exhausted)
InvalidTransaction::ExhaustsResources.into(),
);
})
}
+66 -104
View File
@@ -59,13 +59,13 @@
//! # pub type Balances = u64;
//! # pub type AllModules = u64;
//! # pub enum Runtime {};
//! # use sr_primitives::transaction_validity::TransactionValidity;
//! # use sr_primitives::transaction_validity::{TransactionValidity, UnknownTransaction};
//! # use sr_primitives::traits::ValidateUnsigned;
//! # impl ValidateUnsigned for Runtime {
//! # type Call = ();
//! #
//! # fn validate_unsigned(_call: &Self::Call) -> TransactionValidity {
//! # TransactionValidity::Invalid(0)
//! # UnknownTransaction::NoUnsignedValidator.into()
//! # }
//! # }
//! /// Executive: handles dispatch to the various modules.
@@ -74,50 +74,17 @@
#![cfg_attr(not(feature = "std"), no_std)]
use rstd::prelude::*;
use rstd::marker::PhantomData;
use rstd::result;
use sr_primitives::{generic::Digest, traits::{
self, Header, Zero, One, Checkable, Applyable, CheckEqual, OnFinalize,
OnInitialize, NumberFor, Block as BlockT, OffchainWorker, ValidateUnsigned
}};
use support::Dispatchable;
use rstd::{prelude::*, marker::PhantomData};
use sr_primitives::{
generic::Digest, ApplyResult, weights::GetDispatchInfo,
traits::{
self, Header, Zero, One, Checkable, Applyable, CheckEqual, OnFinalize, OnInitialize,
NumberFor, Block as BlockT, OffchainWorker, ValidateUnsigned, Dispatchable
},
transaction_validity::TransactionValidity,
};
use codec::{Codec, Encode};
use system::{extrinsics_root, DigestOf};
use sr_primitives::{ApplyOutcome, ApplyError};
use sr_primitives::transaction_validity::TransactionValidity;
use sr_primitives::weights::GetDispatchInfo;
mod internal {
use sr_primitives::traits::DispatchError;
pub enum ApplyError {
BadSignature(&'static str),
Stale,
Future,
CantPay,
FullBlock,
}
pub enum ApplyOutcome {
Success,
Fail(&'static str),
}
impl From<DispatchError> for ApplyError {
fn from(d: DispatchError) -> Self {
match d {
DispatchError::Payment => ApplyError::CantPay,
DispatchError::Exhausted => ApplyError::FullBlock,
DispatchError::NoPermission => ApplyError::CantPay,
DispatchError::BadState => ApplyError::CantPay,
DispatchError::Stale => ApplyError::Stale,
DispatchError::Future => ApplyError::Future,
DispatchError::BadProof => ApplyError::BadSignature(""),
}
}
}
}
/// Trait that can be used to execute a block.
pub trait ExecuteBlock<Block: BlockT> {
@@ -239,30 +206,19 @@ where
/// Apply extrinsic outside of the block execution function.
/// This doesn't attempt to validate anything regarding the block, but it builds a list of uxt
/// hashes.
pub fn apply_extrinsic(uxt: Block::Extrinsic) -> result::Result<ApplyOutcome, ApplyError> {
pub fn apply_extrinsic(uxt: Block::Extrinsic) -> ApplyResult {
let encoded = uxt.encode();
let encoded_len = encoded.len();
match Self::apply_extrinsic_with_len(uxt, encoded_len, Some(encoded)) {
Ok(internal::ApplyOutcome::Success) => Ok(ApplyOutcome::Success),
Ok(internal::ApplyOutcome::Fail(_)) => Ok(ApplyOutcome::Fail),
Err(internal::ApplyError::CantPay) => Err(ApplyError::CantPay),
Err(internal::ApplyError::BadSignature(_)) => Err(ApplyError::BadSignature),
Err(internal::ApplyError::Stale) => Err(ApplyError::Stale),
Err(internal::ApplyError::Future) => Err(ApplyError::Future),
Err(internal::ApplyError::FullBlock) => Err(ApplyError::FullBlock),
}
Self::apply_extrinsic_with_len(uxt, encoded_len, Some(encoded))
}
/// Apply an extrinsic inside the block execution function.
fn apply_extrinsic_no_note(uxt: Block::Extrinsic) {
let l = uxt.encode().len();
match Self::apply_extrinsic_with_len(uxt, l, None) {
Ok(internal::ApplyOutcome::Success) => (),
Ok(internal::ApplyOutcome::Fail(e)) => runtime_io::print(e),
Err(internal::ApplyError::CantPay) => panic!("All extrinsics should have sender able to pay their fees"),
Err(internal::ApplyError::BadSignature(_)) => panic!("All extrinsics should be properly signed"),
Err(internal::ApplyError::Stale) | Err(internal::ApplyError::Future) => panic!("All extrinsics should have the correct nonce"),
Err(internal::ApplyError::FullBlock) => panic!("Extrinsics should not exceed block limit"),
Ok(Ok(())) => (),
Ok(Err(e)) => runtime_io::print(e),
Err(e) => { let err: &'static str = e.into(); panic!(err) },
}
}
@@ -271,9 +227,9 @@ where
uxt: Block::Extrinsic,
encoded_len: usize,
to_note: Option<Vec<u8>>,
) -> result::Result<internal::ApplyOutcome, internal::ApplyError> {
) -> ApplyResult {
// Verify that the signature is good.
let xt = uxt.check(&Default::default()).map_err(internal::ApplyError::BadSignature)?;
let xt = uxt.check(&Default::default())?;
// We don't need to make sure to `note_extrinsic` only after we know it's going to be
// executed to prevent it from leaking in storage since at this point, it will either
@@ -286,15 +242,11 @@ where
// Decode parameters and dispatch
let dispatch_info = xt.get_dispatch_info();
let r = Applyable::dispatch(xt, dispatch_info, encoded_len)
.map_err(internal::ApplyError::from)?;
let r = Applyable::apply(xt, dispatch_info, encoded_len)?;
<system::Module<System>>::note_applied_extrinsic(&r, encoded_len as u32);
r.map(|_| internal::ApplyOutcome::Success).or_else(|e| match e {
sr_primitives::BLOCK_FULL => Err(internal::ApplyError::FullBlock),
e => Ok(internal::ApplyOutcome::Fail(e))
})
Ok(r)
}
fn final_checks(header: &System::Header) {
@@ -324,21 +276,8 @@ where
///
/// Changes made to storage should be discarded.
pub fn validate_transaction(uxt: Block::Extrinsic) -> TransactionValidity {
// Note errors > 0 are from ApplyError
const UNKNOWN_ERROR: i8 = -127;
const INVALID_INDEX: i8 = -10;
let encoded_len = uxt.using_encoded(|d| d.len());
let xt = match uxt.check(&Default::default()) {
// Checks out. Carry on.
Ok(xt) => xt,
// An unknown account index implies that the transaction may yet become valid.
Err("invalid account index") => return TransactionValidity::Unknown(INVALID_INDEX),
// Technically a bad signature could also imply an out-of-date account index, but
// that's more of an edge case.
Err(sr_primitives::BAD_SIGNATURE) => return TransactionValidity::Invalid(ApplyError::BadSignature as i8),
Err(_) => return TransactionValidity::Invalid(UNKNOWN_ERROR),
};
let xt = uxt.check(&Default::default())?;
let dispatch_info = xt.get_dispatch_info();
xt.validate::<UnsignedValidator>(dispatch_info, encoded_len)
@@ -357,13 +296,15 @@ mod tests {
use balances::Call;
use runtime_io::with_externalities;
use primitives::{H256, Blake2Hasher};
use sr_primitives::generic::Era;
use sr_primitives::Perbill;
use sr_primitives::weights::Weight;
use sr_primitives::traits::{Header as HeaderT, BlakeTwo256, IdentityLookup, ConvertInto};
use sr_primitives::testing::{Digest, Header, Block};
use support::{impl_outer_event, impl_outer_origin, parameter_types};
use support::traits::{Currency, LockIdentifier, LockableCurrency, WithdrawReasons, WithdrawReason};
use sr_primitives::{
generic::Era, Perbill, DispatchError, weights::Weight, testing::{Digest, Header, Block},
traits::{Header as HeaderT, BlakeTwo256, IdentityLookup, ConvertInto},
transaction_validity::{InvalidTransaction, UnknownTransaction}, ApplyError,
};
use support::{
impl_outer_event, impl_outer_origin, parameter_types,
traits::{Currency, LockIdentifier, LockableCurrency, WithdrawReasons, WithdrawReason},
};
use system;
use hex_literal::hex;
@@ -432,8 +373,8 @@ mod tests {
fn validate_unsigned(call: &Self::Call) -> TransactionValidity {
match call {
Call::set_balance(_, _, _) => TransactionValidity::Valid(Default::default()),
_ => TransactionValidity::Invalid(0),
Call::set_balance(_, _, _) => Ok(Default::default()),
_ => UnknownTransaction::NoUnsignedValidator.into(),
}
}
}
@@ -479,7 +420,7 @@ mod tests {
Digest::default(),
));
let r = Executive::apply_extrinsic(xt);
assert_eq!(r, Ok(ApplyOutcome::Success));
assert!(r.is_ok());
assert_eq!(<balances::Module<Runtime>>::total_balance(&1), 142 - 10 - weight);
assert_eq!(<balances::Module<Runtime>>::total_balance(&2), 69);
});
@@ -582,14 +523,19 @@ mod tests {
assert_eq!(<system::Module<Runtime>>::all_extrinsics_weight(), 0);
for nonce in 0..=num_to_exhaust_block {
let xt = sr_primitives::testing::TestXt(sign_extra(1, nonce.into(), 0), Call::transfer::<Runtime>(33, 0));
let xt = sr_primitives::testing::TestXt(
sign_extra(1, nonce.into(), 0), Call::transfer::<Runtime>(33, 0),
);
let res = Executive::apply_extrinsic(xt);
if nonce != num_to_exhaust_block {
assert_eq!(res.unwrap(), ApplyOutcome::Success);
assert_eq!(<system::Module<Runtime>>::all_extrinsics_weight(), encoded_len * (nonce + 1));
assert!(res.is_ok());
assert_eq!(
<system::Module<Runtime>>::all_extrinsics_weight(),
encoded_len * (nonce + 1),
);
assert_eq!(<system::Module<Runtime>>::extrinsic_index(), Some(nonce as u32 + 1));
} else {
assert_eq!(res, Err(ApplyError::FullBlock));
assert_eq!(res, Err(InvalidTransaction::ExhaustsResources.into()));
}
}
});
@@ -606,9 +552,9 @@ mod tests {
assert_eq!(<system::Module<Runtime>>::all_extrinsics_weight(), 0);
assert_eq!(<system::Module<Runtime>>::all_extrinsics_weight(), 0);
assert_eq!(Executive::apply_extrinsic(xt.clone()).unwrap(), ApplyOutcome::Success);
assert_eq!(Executive::apply_extrinsic(x1.clone()).unwrap(), ApplyOutcome::Success);
assert_eq!(Executive::apply_extrinsic(x2.clone()).unwrap(), ApplyOutcome::Success);
assert!(Executive::apply_extrinsic(xt.clone()).unwrap().is_ok());
assert!(Executive::apply_extrinsic(x1.clone()).unwrap().is_ok());
assert!(Executive::apply_extrinsic(x2.clone()).unwrap().is_ok());
// default weight for `TestXt` == encoded length.
assert_eq!(<system::Module<Runtime>>::all_extrinsics_weight(), (3 * len).into());
@@ -624,12 +570,18 @@ mod tests {
#[test]
fn validate_unsigned() {
let xt = sr_primitives::testing::TestXt(None, Call::set_balance(33, 69, 69));
let valid = TransactionValidity::Valid(Default::default());
let mut t = new_test_ext(1);
with_externalities(&mut t, || {
assert_eq!(Executive::validate_transaction(xt.clone()), valid);
assert_eq!(Executive::apply_extrinsic(xt), Ok(ApplyOutcome::Fail));
assert_eq!(Executive::validate_transaction(xt.clone()), Ok(Default::default()));
assert_eq!(
Executive::apply_extrinsic(xt),
Ok(
Err(
DispatchError { module: None, error: 0, message: Some("RequireRootOrigin") }
)
)
);
});
}
@@ -657,11 +609,21 @@ mod tests {
));
if lock == WithdrawReasons::except(WithdrawReason::TransactionPayment) {
assert_eq!(Executive::apply_extrinsic(xt).unwrap(), ApplyOutcome::Fail);
assert_eq!(
Executive::apply_extrinsic(xt).unwrap(),
Err(DispatchError {
module: None,
error: 0,
message: Some("account liquidity restrictions prevent withdrawal"),
}),
);
// but tx fee has been deducted. the transaction failed on transfer, not on fee.
assert_eq!(<balances::Module<Runtime>>::total_balance(&1), 111 - 10 - weight);
} else {
assert_eq!(Executive::apply_extrinsic(xt), Err(ApplyError::CantPay));
assert_eq!(
Executive::apply_extrinsic(xt),
Err(ApplyError::Validity(InvalidTransaction::Payment.into())),
);
assert_eq!(<balances::Module<Runtime>>::total_balance(&1), 111);
}
});
+2 -2
View File
@@ -37,9 +37,9 @@ pub fn grandpa_log(log: ConsensusLog<u64>) -> DigestItem<H256> {
// Workaround for https://github.com/rust-lang/rust/issues/26925 . Remove when sorted.
#[derive(Clone, PartialEq, Eq, Debug, Decode, Encode)]
pub struct Test;
impl Trait for Test {
type Event = TestEvent;
}
parameter_types! {
pub const BlockHashCount: u64 = 250;
@@ -53,7 +53,7 @@ impl system::Trait for Test {
type BlockNumber = u64;
type Call = ();
type Hash = H256;
type Hashing = ::sr_primitives::traits::BlakeTwo256;
type Hashing = sr_primitives::traits::BlakeTwo256;
type AccountId = u64;
type Lookup = IdentityLookup<Self::AccountId>;
type Header = Header;
+13 -12
View File
@@ -74,9 +74,10 @@ use rstd::prelude::*;
use session::historical::IdentificationTuple;
use runtime_io::Printable;
use sr_primitives::{
Perbill, ApplyError,
traits::{Convert, Member},
transaction_validity::{TransactionValidity, TransactionLongevity, ValidTransaction},
traits::{Convert, Member}, Perbill,
transaction_validity::{
TransactionValidity, TransactionLongevity, ValidTransaction, InvalidTransaction,
},
};
use sr_staking_primitives::{
SessionIndex, CurrentElectedSet,
@@ -160,7 +161,7 @@ enum OffchainErr {
}
impl Printable for OffchainErr {
fn print(self) {
fn print(&self) {
match self {
OffchainErr::DecodeWorkerStatus => print("Offchain error: decoding WorkerStatus failed!"),
OffchainErr::FailedSigning => print("Offchain error: signing failed!"),
@@ -489,24 +490,24 @@ impl<T: Trait> session::OneSessionHandler<T::AccountId> for Module<T> {
impl<T: Trait> support::unsigned::ValidateUnsigned for Module<T> {
type Call = Call<T>;
fn validate_unsigned(call: &Self::Call) -> support::unsigned::TransactionValidity {
fn validate_unsigned(call: &Self::Call) -> TransactionValidity {
if let Call::heartbeat(heartbeat, signature) = call {
if <Module<T>>::is_online_in_current_session(heartbeat.authority_index) {
// we already received a heartbeat for this authority
return TransactionValidity::Invalid(ApplyError::Stale as i8);
return InvalidTransaction::Stale.into();
}
// check if session index from heartbeat is recent
let current_session = <session::Module<T>>::current_index();
if heartbeat.session_index != current_session {
return TransactionValidity::Invalid(ApplyError::Stale as i8);
return InvalidTransaction::Stale.into();
}
// verify that the incoming (unverified) pubkey is actually an authority id
let keys = Keys::<T>::get();
let authority_id = match keys.get(heartbeat.authority_index as usize) {
Some(id) => id,
None => return TransactionValidity::Invalid(ApplyError::BadSignature as i8),
None => return InvalidTransaction::BadProof.into(),
};
// check signature (this is expensive so we do it last).
@@ -515,19 +516,19 @@ impl<T: Trait> support::unsigned::ValidateUnsigned for Module<T> {
});
if !signature_valid {
return TransactionValidity::Invalid(ApplyError::BadSignature as i8);
return InvalidTransaction::BadProof.into();
}
return TransactionValidity::Valid(ValidTransaction {
Ok(ValidTransaction {
priority: 0,
requires: vec![],
provides: vec![(current_session, authority_id).encode()],
longevity: TransactionLongevity::max_value(),
propagate: true,
})
} else {
InvalidTransaction::Call.into()
}
TransactionValidity::Invalid(0)
}
}
+6 -4
View File
@@ -19,10 +19,10 @@
#![cfg_attr(not(feature = "std"), no_std)]
use rstd::{prelude::*, result, marker::PhantomData, convert::TryInto};
use rstd::{prelude::*, marker::PhantomData, convert::TryInto};
use codec::{Encode, Codec};
use support::{StorageValue, StorageMap, Parameter, decl_module, decl_event, decl_storage};
use sr_primitives::traits::{One, SimpleArithmetic, StaticLookup, Member};
use sr_primitives::traits::{One, SimpleArithmetic, StaticLookup, Member, LookupError};
use system::{IsDeadAccount, OnNewAccount};
use self::address::Address as RawAddress;
@@ -224,9 +224,11 @@ impl<T: Trait> OnNewAccount<T::AccountId> for Module<T> {
impl<T: Trait> StaticLookup for Module<T> {
type Source = address::Address<T::AccountId, T::AccountIndex>;
type Target = T::AccountId;
fn lookup(a: Self::Source) -> result::Result<Self::Target, &'static str> {
Self::lookup_address(a).ok_or("invalid account index")
fn lookup(a: Self::Source) -> Result<T::AccountId, LookupError> {
Self::lookup_address(a).ok_or(LookupError)
}
fn unlookup(a: Self::Target) -> Self::Source {
address::Address::Id(a)
}
+2 -2
View File
@@ -882,8 +882,8 @@ decl_module! {
ensure!(!targets.is_empty(), "targets cannot be empty");
let targets = targets.into_iter()
.take(MAX_NOMINATIONS)
.map(T::Lookup::lookup)
.collect::<result::Result<Vec<T::AccountId>, &'static str>>()?;
.map(|t| T::Lookup::lookup(t))
.collect::<result::Result<Vec<T::AccountId>, _>>()?;
<Validators<T>>::remove(stash);
<Nominators<T>>::insert(stash, targets);
+8 -2
View File
@@ -748,7 +748,10 @@ fn cannot_transfer_staked_balance() {
// Confirm account 11 (via controller 10) is totally staked
assert_eq!(Staking::stakers(&11).total, 1000);
// Confirm account 11 cannot transfer as a result
assert_noop!(Balances::transfer(Origin::signed(11), 20, 1), "account liquidity restrictions prevent withdrawal");
assert_noop!(
Balances::transfer(Origin::signed(11), 20, 1),
"account liquidity restrictions prevent withdrawal",
);
// Give account 11 extra free balance
let _ = Balances::make_free_balance_be(&11, 10000);
@@ -774,7 +777,10 @@ fn cannot_transfer_staked_balance_2() {
// Confirm account 21 (via controller 20) is totally staked
assert_eq!(Staking::stakers(&21).total, 1000);
// Confirm account 21 can transfer at most 1000
assert_noop!(Balances::transfer(Origin::signed(21), 20, 1001), "account liquidity restrictions prevent withdrawal");
assert_noop!(
Balances::transfer(Origin::signed(21), 20, 1001),
"account liquidity restrictions prevent withdrawal",
);
assert_ok!(Balances::transfer(Origin::signed(21), 20, 1000));
});
}
+4 -5
View File
@@ -87,12 +87,10 @@
#![cfg_attr(not(feature = "std"), no_std)]
use rstd::prelude::*;
use sr_primitives::traits::StaticLookup;
use sr_primitives::weights::SimpleDispatchInfo;
use support::{
StorageValue, Parameter, Dispatchable, decl_module, decl_event,
decl_storage, ensure
use sr_primitives::{
traits::{StaticLookup, Dispatchable}, weights::SimpleDispatchInfo, DispatchError,
};
use support::{StorageValue, Parameter, decl_module, decl_event, decl_storage, ensure};
use system::ensure_signed;
pub trait Trait: system::Trait {
@@ -126,6 +124,7 @@ decl_module! {
let res = match proposal.dispatch(system::RawOrigin::Root.into()) {
Ok(_) => true,
Err(e) => {
let e: DispatchError = e.into();
runtime_io::print(e);
false
}
+161 -14
View File
@@ -25,18 +25,18 @@ pub use srml_metadata::{
FunctionMetadata, DecodeDifferent, DecodeDifferentArray, FunctionArgumentMetadata,
ModuleConstantMetadata, DefaultByte, DefaultByteGetter,
};
pub use sr_primitives::weights::{SimpleDispatchInfo, GetDispatchInfo, DispatchInfo, WeighData,
ClassifyDispatch,
TransactionPriority
pub use sr_primitives::{
weights::{
SimpleDispatchInfo, GetDispatchInfo, DispatchInfo, WeighData, ClassifyDispatch,
TransactionPriority
}, traits::{Dispatchable, DispatchResult, ModuleDispatchError}, DispatchError
};
pub use sr_primitives::traits::{Dispatchable, DispatchResult};
/// A type that cannot be instantiated.
pub enum Never {}
/// Result of a module function call; either nothing (functions are only called for "side effects")
/// or an error message.
pub type Result = DispatchResult;
/// Result with string error message. This exists for backward compatibility purpose.
pub type Result = DispatchResult<&'static str>;
/// Serializable version of Dispatchable.
/// This value can be used as a "function" in an extrinsic.
@@ -239,6 +239,7 @@ macro_rules! decl_module {
{}
{}
{}
{}
[]
$($t)*
);
@@ -270,6 +271,7 @@ macro_rules! decl_module {
{}
{}
{}
{}
[]
$($t)*
);
@@ -286,6 +288,7 @@ macro_rules! decl_module {
{ $( $on_finalize:tt )* }
{ $( $offchain:tt )* }
{ $( $constants:tt )* }
{ $( $error_type:tt )* }
[ $( $dispatchables:tt )* ]
$(#[doc = $doc_attr:tt])*
$vis:vis fn deposit_event() = default;
@@ -301,6 +304,7 @@ macro_rules! decl_module {
{ $( $on_finalize )* }
{ $( $offchain )* }
{ $( $constants )* }
{ $( $error_type )* }
[ $( $dispatchables )* ]
$($rest)*
);
@@ -315,6 +319,7 @@ macro_rules! decl_module {
{ $( $on_finalize:tt )* }
{ $( $offchain:tt )* }
{ $( $constants:tt )* }
{ $( $error_type:tt )* }
[ $( $dispatchables:tt )* ]
$(#[doc = $doc_attr:tt])*
$vis:vis fn deposit_event
@@ -334,6 +339,7 @@ macro_rules! decl_module {
{}
{ $( $offchain:tt )* }
{ $( $constants:tt )* }
{ $( $error_type:tt )* }
[ $( $dispatchables:tt )* ]
$(#[doc = $doc_attr:tt])*
fn on_finalize($($param_name:ident : $param:ty),* ) { $( $impl:tt )* }
@@ -349,6 +355,7 @@ macro_rules! decl_module {
{ fn on_finalize( $( $param_name : $param ),* ) { $( $impl )* } }
{ $( $offchain )* }
{ $( $constants )* }
{ $( $error_type )* }
[ $( $dispatchables )* ]
$($rest)*
);
@@ -363,6 +370,7 @@ macro_rules! decl_module {
{ $( $on_finalize:tt )* }
{ $( $offchain:tt )* }
{ $( $constants:tt )* }
{ $( $error_type:tt )* }
[ $( $dispatchables:tt )* ]
$(#[doc = $doc_attr:tt])*
fn on_initialize($($param_name:ident : $param:ty),* ) { $( $impl:tt )* }
@@ -378,6 +386,7 @@ macro_rules! decl_module {
{ $( $on_finalize )* }
{ $( $offchain )* }
{ $( $constants )* }
{ $( $error_type )* }
[ $( $dispatchables )* ]
$($rest)*
);
@@ -395,6 +404,7 @@ macro_rules! decl_module {
{ $( $on_finalize:tt )* }
{ }
{ $( $constants:tt )* }
{ $( $error_type:tt )* }
[ $( $dispatchables:tt )* ]
$(#[doc = $doc_attr:tt])*
fn offchain_worker($($param_name:ident : $param:ty),* ) { $( $impl:tt )* }
@@ -412,6 +422,7 @@ macro_rules! decl_module {
{ $( $on_finalize )* }
{ fn offchain_worker( $( $param_name : $param ),* ) { $( $impl )* } }
{ $( $constants )* }
{ $( $error_type )* }
[ $( $dispatchables )* ]
$($rest)*
);
@@ -431,6 +442,7 @@ macro_rules! decl_module {
{ $( $on_finalize:tt )* }
{ $( $offchain:tt )* }
{ $( $constants:tt )* }
{ $( $error_type:tt )* }
[ $( $dispatchables:tt )* ]
$( #[doc = $doc_attr:tt] )*
const $name:ident: $ty:ty = $value:expr;
@@ -453,11 +465,85 @@ macro_rules! decl_module {
$( #[doc = $doc_attr ] )*
$name: $ty = $value;
}
{ $( $error_type )* }
[ $( $dispatchables )* ]
$($rest)*
);
};
// Parse error type
(@normalize
$(#[$attr:meta])*
pub struct $mod_type:ident<
$trait_instance:ident:
$trait_name:ident$(<I>, $instance:ident: $instantiable:path $(= $module_default_instance:path)?)?
>
for enum $call_type:ident where origin: $origin_type:ty, system = $system:ident
{ $( $other_where_bounds:tt )* }
{ $( $deposit_event:tt )* }
{ $( $on_initialize:tt )* }
{ $( $on_finalize:tt )* }
{ $( $offchain:tt )* }
{ $( $constants:tt )* }
{ }
[ $( $dispatchables:tt )* ]
$(#[doc = $doc_attr:tt])*
type Error = $error_type:ty;
$($rest:tt)*
) => {
$crate::decl_module!(@normalize
$(#[$attr])*
pub struct $mod_type<
$trait_instance: $trait_name$(<I>, $instance: $instantiable $(= $module_default_instance)?)?
>
for enum $call_type where origin: $origin_type, system = $system
{ $( $other_where_bounds )* }
{ $( $deposit_event )* }
{ $( $on_initialize )* }
{ $( $on_finalize )* }
{ $( $offchain )* }
{ $( $constants )* }
{ $error_type }
[ $( $dispatchables )* ]
$($rest)*
);
};
// Add default Error if none supplied
(@normalize
$(#[$attr:meta])*
pub struct $mod_type:ident<
$trait_instance:ident:
$trait_name:ident$(<I>, $instance:ident: $instantiable:path $(= $module_default_instance:path)?)?
>
for enum $call_type:ident where origin: $origin_type:ty, system = $system:ident
{ $( $other_where_bounds:tt )* }
{ $( $deposit_event:tt )* }
{ $( $on_initialize:tt )* }
{ $( $on_finalize:tt )* }
{ $( $offchain:tt )* }
{ $( $constants:tt )* }
{ }
[ $($t:tt)* ]
$($rest:tt)*
) => {
$crate::decl_module!(@normalize
$(#[$attr])*
pub struct $mod_type<
$trait_instance: $trait_name$(<I>, $instance: $instantiable $(= $module_default_instance)?)?
>
for enum $call_type where origin: $origin_type, system = $system
{ $( $other_where_bounds )* }
{ $( $deposit_event )* }
{ $( $on_initialize )* }
{ $( $on_finalize )* }
{ $( $offchain )* }
{ $( $constants )* }
{ &'static str }
[ $($t)* ]
$($rest)*
);
};
// This puts the function statement into the [], decreasing `$rest` and moving toward finishing the parse.
(@normalize
$(#[$attr:meta])*
@@ -472,6 +558,7 @@ macro_rules! decl_module {
{ $( $on_finalize:tt )* }
{ $( $offchain:tt )* }
{ $( $constants:tt )* }
{ $error_type:ty }
[ $( $dispatchables:tt )* ]
$(#[doc = $doc_attr:tt])*
#[weight = $weight:expr]
@@ -492,6 +579,7 @@ macro_rules! decl_module {
{ $( $on_finalize )* }
{ $( $offchain )* }
{ $( $constants )* }
{ $error_type }
[
$( $dispatchables )*
$(#[doc = $doc_attr])*
@@ -518,6 +606,7 @@ macro_rules! decl_module {
{ $( $on_finalize:tt )* }
{ $( $offchain:tt )* }
{ $( $constants:tt )* }
{ $( $error_type:tt )* }
[ $( $dispatchables:tt )* ]
$(#[doc = $doc_attr:tt])*
$fn_vis:vis fn $fn_name:ident(
@@ -537,6 +626,7 @@ macro_rules! decl_module {
{ $( $on_finalize )* }
{ $( $offchain )* }
{ $( $constants )* }
{ $( $error_type )* }
[ $( $dispatchables )* ]
$(#[doc = $doc_attr])*
#[weight = $crate::dispatch::SimpleDispatchInfo::default()]
@@ -557,6 +647,7 @@ macro_rules! decl_module {
{ $( $on_finalize:tt )* }
{ $( $offchain:tt )* }
{ $( $constants:tt )* }
{ $( $error_type:tt )* }
[ $( $dispatchables:tt )* ]
$(#[doc = $doc_attr:tt])*
$(#[weight = $weight:expr])?
@@ -581,6 +672,7 @@ macro_rules! decl_module {
{ $( $on_finalize:tt )* }
{ $( $offchain:tt )* }
{ $( $constants:tt )* }
{ $( $error_type:tt )* }
[ $( $dispatchables:tt )* ]
$(#[doc = $doc_attr:tt])*
$(#[weight = $weight:expr])?
@@ -605,6 +697,7 @@ macro_rules! decl_module {
{ $( $on_finalize:tt )* }
{ $( $offchain:tt )* }
{ $( $constants:tt )* }
{ $( $error_type:tt )* }
[ $( $dispatchables:tt )* ]
$(#[doc = $doc_attr:tt])*
$(#[weight = $weight:expr])?
@@ -630,6 +723,7 @@ macro_rules! decl_module {
{ $( $on_finalize:tt )* }
{ $( $offchain:tt )* }
{ $( $constants:tt )* }
{ $( $error_type:tt )* }
[ $( $dispatchables:tt )* ]
) => {
$crate::decl_module!(@imp
@@ -644,6 +738,7 @@ macro_rules! decl_module {
{ $( $on_finalize )* }
{ $( $offchain )* }
{ $( $constants )* }
{ $( $error_type )* }
);
};
@@ -794,6 +889,7 @@ macro_rules! decl_module {
(@impl_function
$module:ident<$trait_instance:ident: $trait_name:ident$(<I>, $instance:ident: $instantiable:path)?>;
$origin_ty:ty;
$error_type:ty;
$ignore:ident;
$(#[doc = $doc_attr:tt])*
$vis:vis fn $name:ident (
@@ -804,7 +900,7 @@ macro_rules! decl_module {
#[allow(unreachable_code)]
$vis fn $name(
$origin: $origin_ty $(, $param: $param_ty )*
) -> $crate::dispatch::Result {
) -> $crate::dispatch::DispatchResult<$error_type> {
{ $( $impl )* }
// May be unreachable.
Ok(())
@@ -815,6 +911,7 @@ macro_rules! decl_module {
(@impl_function
$module:ident<$trait_instance:ident: $trait_name:ident$(<I>, $instance:ident: $instantiable:path)?>;
$origin_ty:ty;
$error_type:ty;
$ignore:ident;
$(#[doc = $doc_attr:tt])*
$vis:vis fn $name:ident (
@@ -969,6 +1066,7 @@ macro_rules! decl_module {
{ $( $on_finalize:tt )* }
{ $( $offchain:tt )* }
{ $( $constants:tt )* }
{ $error_type:ty }
) => {
$crate::__check_reserved_fn_name! { $( $fn_name )* }
@@ -1020,6 +1118,7 @@ macro_rules! decl_module {
@impl_function
$mod_type<$trait_instance: $trait_name $(<I>, $fn_instance: $fn_instantiable)?>;
$origin_type;
$error_type;
$from;
$(#[doc = $doc_attr])*
$fn_vis fn $fn_name (
@@ -1150,7 +1249,8 @@ macro_rules! decl_module {
{
type Trait = $trait_instance;
type Origin = $origin_type;
fn dispatch(self, _origin: Self::Origin) -> $crate::dispatch::Result {
type Error = $error_type;
fn dispatch(self, _origin: Self::Origin) -> $crate::dispatch::DispatchResult<Self::Error> {
match self {
$(
$call_type::$fn_name( $( $param_name ),* ) => {
@@ -1177,8 +1277,8 @@ macro_rules! decl_module {
#[doc(hidden)]
pub fn dispatch<D: $crate::dispatch::Dispatchable<Trait = $trait_instance>>(
d: D,
origin: D::Origin,
) -> $crate::dispatch::Result {
origin: D::Origin
) -> $crate::dispatch::DispatchResult<D::Error> {
d.dispatch(origin)
}
}
@@ -1234,9 +1334,19 @@ macro_rules! impl_outer_dispatch {
impl $crate::dispatch::Dispatchable for $call_type {
type Origin = $origin;
type Trait = $call_type;
fn dispatch(self, origin: $origin) -> $crate::dispatch::Result {
match self {
$( $call_type::$camelcase(call) => call.dispatch(origin), )*
type Error = $crate::dispatch::DispatchError;
fn dispatch(
self,
origin: $origin,
) -> $crate::dispatch::DispatchResult<$crate::dispatch::DispatchError> {
$crate::impl_outer_dispatch! {
@DISPATCH_MATCH
self
$call_type
origin
{}
0;
$( $camelcase ),*
}
}
}
@@ -1258,6 +1368,43 @@ macro_rules! impl_outer_dispatch {
}
}
)*
};
(@DISPATCH_MATCH
$self:ident
$call_type:ident
$origin:ident
{ $( $generated:tt )* }
$index:expr;
$name:ident
$( , $rest:ident )*
) => {
$crate::impl_outer_dispatch! {
@DISPATCH_MATCH
$self
$call_type
$origin
{
$( $generated )*
$call_type::$name(call) => call.dispatch($origin).map_err(|e| {
let mut error: $crate::dispatch::DispatchError = e.into();
error.module = Some($index);
error
}),
}
$index + 1;
$( $rest ),*
}
};
(@DISPATCH_MATCH
$self:ident
$call_type:ident
$origin:ident
{ $( $generated:tt )* }
$index:expr;
) => {
match $self {
$( $generated )*
}
}
}
+151
View File
@@ -0,0 +1,151 @@
// Copyright 2019 Parity Technologies (UK) Ltd.
// This file is part of Substrate.
// Substrate is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Substrate is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Substrate. If not, see <http://www.gnu.org/licenses/>.
//! Macro for declaring a module error.
#[doc(hidden)]
pub use sr_primitives::traits::LookupError;
/// Declare an error type for a runtime module.
///
/// The generated error type inherently has the variants `Other` and `CannotLookup`. `Other` can
/// hold any `&'static str` error message and is present for convenience/backward compatibility.
/// The `CannotLookup` variant indicates that some lookup could not be done. For both variants the
/// error type implements `From<&'static str>` and `From<LookupError>` to make them usable with the
/// try operator.
///
/// # Usage
///
/// ```
/// # use srml_support::decl_error;
/// decl_error! {
/// /// Errors that can occur in my module.
/// pub enum MyError {
/// /// Hey this is an error message that indicates bla.
/// MyCoolErrorMessage,
/// /// You are just not cool enough for my module!
/// YouAreNotCoolEnough,
/// }
/// }
/// ```
///
/// `decl_error!` supports only variants that do not hold any data.
#[macro_export]
macro_rules! decl_error {
(
$(#[$attr:meta])*
pub enum $error:ident {
$(
$( #[$variant_attr:meta] )*
$name:ident
),*
$(,)?
}
) => {
#[derive(Clone, PartialEq, Eq)]
#[cfg_attr(feature = "std", derive(Debug))]
$(#[$attr])*
pub enum $error {
Other(&'static str),
CannotLookup,
$(
$(#[$variant_attr])*
$name
),*
}
impl $crate::dispatch::ModuleDispatchError for $error {
fn as_u8(&self) -> u8 {
$crate::decl_error! {
@GENERATE_AS_U8
self
$error
{}
2,
$( $name ),*
}
}
fn as_str(&self) -> &'static str {
match self {
$error::Other(err) => err,
$error::CannotLookup => "Can not lookup",
$(
$error::$name => stringify!($name),
)*
}
}
}
impl From<&'static str> for $error {
fn from(val: &'static str) -> $error {
$error::Other(val)
}
}
impl From<$crate::error::LookupError> for $error {
fn from(_: $crate::error::LookupError) -> $error {
$error::CannotLookup
}
}
impl From<$error> for &'static str {
fn from(err: $error) -> &'static str {
use $crate::dispatch::ModuleDispatchError;
err.as_str()
}
}
impl Into<$crate::dispatch::DispatchError> for $error {
fn into(self) -> $crate::dispatch::DispatchError {
use $crate::dispatch::ModuleDispatchError;
$crate::dispatch::DispatchError::new(None, self.as_u8(), Some(self.as_str()))
}
}
};
(@GENERATE_AS_U8
$self:ident
$error:ident
{ $( $generated:tt )* }
$index:expr,
$name:ident
$( , $rest:ident )*
) => {
$crate::decl_error! {
@GENERATE_AS_U8
$self
$error
{
$( $generated )*
$error::$name => $index,
}
$index + 1,
$( $rest ),*
}
};
(@GENERATE_AS_U8
$self:ident
$error:ident
{ $( $generated:tt )* }
$index:expr,
) => {
match $self {
$error::Other(_) => 0,
$error::CannotLookup => 1,
$( $generated )*
}
}
}
+10 -5
View File
@@ -58,14 +58,16 @@ mod runtime;
pub mod inherent;
#[macro_use]
pub mod unsigned;
#[macro_use]
pub mod error;
mod double_map;
pub mod traits;
pub use self::storage::{StorageValue, StorageMap, StorageLinkedMap, StorageDoubleMap};
pub use self::hashable::Hashable;
pub use self::dispatch::{Parameter, Dispatchable, Callable, IsSubType};
pub use self::dispatch::{Parameter, Callable, IsSubType};
pub use self::double_map::StorageDoubleMapWithHasher;
pub use runtime_io::{print, storage_root};
pub use runtime_io::{print, storage_root, Printable};
pub use sr_primitives::{self, ConsensusEngineId};
/// Macro for easily creating a new implementation of the `Get` trait. Use similarly to
@@ -128,7 +130,7 @@ macro_rules! fail {
/// Used as `ensure!(expression_to_ensure, expression_to_return_on_false)`.
#[macro_export]
macro_rules! ensure {
( $x:expr, $y:expr ) => {{
( $x:expr, $y:expr $(,)? ) => {{
if !$x {
$crate::fail!($y);
}
@@ -142,7 +144,10 @@ macro_rules! ensure {
#[macro_export]
#[cfg(feature = "std")]
macro_rules! assert_noop {
( $x:expr , $y:expr ) => {
(
$x:expr,
$y:expr $(,)?
) => {
let h = $crate::storage_root();
$crate::assert_err!($x, $y);
assert_eq!(h, $crate::storage_root());
@@ -159,7 +164,7 @@ macro_rules! assert_noop {
#[macro_export]
#[cfg(feature = "std")]
macro_rules! assert_err {
( $x:expr , $y:expr ) => {
( $x:expr , $y:expr $(,)? ) => {
assert_eq!($x, Err($y));
}
}
+3 -4
View File
@@ -17,7 +17,7 @@
#[doc(hidden)]
pub use crate::sr_primitives::traits::ValidateUnsigned;
#[doc(hidden)]
pub use crate::sr_primitives::transaction_validity::TransactionValidity;
pub use crate::sr_primitives::transaction_validity::{TransactionValidity, UnknownTransaction};
#[doc(hidden)]
pub use crate::sr_primitives::ApplyError;
@@ -72,7 +72,7 @@ macro_rules! impl_outer_validate_unsigned {
#[allow(unreachable_patterns)]
match call {
$( Call::$module(inner_call) => $module::validate_unsigned(inner_call), )*
_ => $crate::unsigned::TransactionValidity::Invalid($crate::unsigned::ApplyError::BadSignature as i8),
_ => $crate::unsigned::UnknownTransaction::NoUnsignedValidator.into(),
}
}
}
@@ -81,8 +81,7 @@ macro_rules! impl_outer_validate_unsigned {
#[cfg(test)]
mod test_empty_call {
pub enum Call {
}
pub enum Call {}
#[allow(unused)]
pub struct Runtime;
@@ -27,6 +27,13 @@ support::decl_event!(
}
);
support::decl_error! {
pub enum Error {
TestError,
AnotherError
}
}
/// Origin for the system module.
#[derive(PartialEq, Eq, Clone)]
#[cfg_attr(feature = "std", derive(Debug))]
+108 -72
View File
@@ -95,22 +95,24 @@ use rstd::prelude::*;
use rstd::map;
use rstd::marker::PhantomData;
use sr_version::RuntimeVersion;
use sr_primitives::generic::{self, Era};
use sr_primitives::Perbill;
use sr_primitives::weights::{
Weight, DispatchInfo, DispatchClass, WeightMultiplier, SimpleDispatchInfo
};
use sr_primitives::transaction_validity::{
ValidTransaction, TransactionPriority, TransactionLongevity
};
use sr_primitives::traits::{self, CheckEqual, SimpleArithmetic, Zero, SignedExtension, Convert,
SimpleBitOps, Hash, Member, MaybeDisplay, EnsureOrigin, DispatchError, SaturatedConversion,
MaybeSerializeDebugButNotDeserialize, MaybeSerializeDebug, StaticLookup, One, Bounded, Lookup,
use sr_primitives::{
generic::{self, Era}, Perbill, ApplyError, ApplyOutcome, DispatchError,
weights::{Weight, DispatchInfo, DispatchClass, WeightMultiplier, SimpleDispatchInfo},
transaction_validity::{
ValidTransaction, TransactionPriority, TransactionLongevity, TransactionValidityError,
InvalidTransaction, TransactionValidity,
},
traits::{
self, CheckEqual, SimpleArithmetic, Zero, SignedExtension, Convert, Lookup, LookupError,
SimpleBitOps, Hash, Member, MaybeDisplay, EnsureOrigin, SaturatedConversion,
MaybeSerializeDebugButNotDeserialize, MaybeSerializeDebug, StaticLookup, One, Bounded,
},
};
use primitives::storage::well_known_keys;
use support::{
storage, decl_module, decl_event, decl_storage, StorageDoubleMap, StorageValue, StorageMap,
Parameter, for_each_tuple, traits::{Contains, Get}
Parameter, for_each_tuple, traits::{Contains, Get}, decl_error,
};
use safe_mix::TripletMix;
use codec::{Encode, Decode};
@@ -248,6 +250,8 @@ pub type KeyValue = (Vec<u8>, Vec<u8>);
decl_module! {
pub struct Module<T: Trait> for enum Call where origin: T::Origin {
type Error = Error;
/// A big dispatch that will disallow any other transaction to be included.
// TODO: this must be preferable available for testing really (not possible at the moment).
#[weight = SimpleDispatchInfo::MaxOperational]
@@ -323,10 +327,21 @@ decl_event!(
/// An extrinsic completed successfully.
ExtrinsicSuccess,
/// An extrinsic failed.
ExtrinsicFailed,
ExtrinsicFailed(DispatchError),
}
);
decl_error! {
/// Error for the System module
pub enum Error {
BadSignature,
BlockFull,
RequireSignedOrigin,
RequireRootOrigin,
RequireNoOrigin,
}
}
/// Origin for the System module.
#[derive(PartialEq, Eq, Clone)]
#[cfg_attr(feature = "std", derive(Debug))]
@@ -510,32 +525,32 @@ impl<O, T> EnsureOrigin<O> for EnsureNever<T> {
/// Ensure that the origin `o` represents a signed extrinsic (i.e. transaction).
/// Returns `Ok` with the account that signed the extrinsic or an `Err` otherwise.
pub fn ensure_signed<OuterOrigin, AccountId>(o: OuterOrigin) -> Result<AccountId, &'static str>
pub fn ensure_signed<OuterOrigin, AccountId>(o: OuterOrigin) -> Result<AccountId, Error>
where OuterOrigin: Into<Result<RawOrigin<AccountId>, OuterOrigin>>
{
match o.into() {
Ok(RawOrigin::Signed(t)) => Ok(t),
_ => Err("bad origin: expected to be a signed origin"),
_ => Err(Error::RequireSignedOrigin),
}
}
/// Ensure that the origin `o` represents the root. Returns `Ok` or an `Err` otherwise.
pub fn ensure_root<OuterOrigin, AccountId>(o: OuterOrigin) -> Result<(), &'static str>
pub fn ensure_root<OuterOrigin, AccountId>(o: OuterOrigin) -> Result<(), Error>
where OuterOrigin: Into<Result<RawOrigin<AccountId>, OuterOrigin>>
{
match o.into() {
Ok(RawOrigin::Root) => Ok(()),
_ => Err("bad origin: expected to be a root origin"),
_ => Err(Error::RequireRootOrigin),
}
}
/// Ensure that the origin `o` represents an unsigned extrinsic. Returns `Ok` or an `Err` otherwise.
pub fn ensure_none<OuterOrigin, AccountId>(o: OuterOrigin) -> Result<(), &'static str>
pub fn ensure_none<OuterOrigin, AccountId>(o: OuterOrigin) -> Result<(), Error>
where OuterOrigin: Into<Result<RawOrigin<AccountId>, OuterOrigin>>
{
match o.into() {
Ok(RawOrigin::None) => Ok(()),
_ => Err("bad origin: expected to be no origin"),
_ => Err(Error::RequireNoOrigin),
}
}
@@ -811,11 +826,13 @@ impl<T: Trait> Module<T> {
}
/// To be called immediately after an extrinsic has been applied.
pub fn note_applied_extrinsic(r: &Result<(), &'static str>, _encoded_len: u32) {
Self::deposit_event(match r {
Ok(_) => Event::ExtrinsicSuccess,
Err(_) => Event::ExtrinsicFailed,
});
pub fn note_applied_extrinsic(r: &ApplyOutcome, _encoded_len: u32) {
Self::deposit_event(
match r {
Ok(()) => Event::ExtrinsicSuccess,
Err(err) => Event::ExtrinsicFailed(err.clone()),
}
);
let next_extrinsic_index = Self::extrinsic_index().unwrap_or_default() + 1u32;
@@ -844,7 +861,6 @@ impl<T: Trait> Module<T> {
pub struct CheckWeight<T: Trait + Send + Sync>(PhantomData<T>);
impl<T: Trait + Send + Sync> CheckWeight<T> {
/// Get the quota ratio of each dispatch class type. This indicates that all operational
/// dispatches can use the full capacity of any resource, while user-triggered ones can consume
/// a portion.
@@ -859,31 +875,33 @@ impl<T: Trait + Send + Sync> CheckWeight<T> {
/// Checks if the current extrinsic can fit into the block with respect to block weight limits.
///
/// Upon successes, it returns the new block weight as a `Result`.
fn check_weight(info: DispatchInfo) -> Result<Weight, DispatchError> {
fn check_weight(info: DispatchInfo) -> Result<Weight, TransactionValidityError> {
let current_weight = Module::<T>::all_extrinsics_weight();
let maximum_weight = T::MaximumBlockWeight::get();
let limit = Self::get_dispatch_limit_ratio(info.class) * maximum_weight;
let added_weight = info.weight.min(limit);
let next_weight = current_weight.saturating_add(added_weight);
if next_weight > limit {
return Err(DispatchError::Exhausted)
Err(InvalidTransaction::ExhaustsResources.into())
} else {
Ok(next_weight)
}
Ok(next_weight)
}
/// Checks if the current extrinsic can fit into the block with respect to block length limits.
///
/// Upon successes, it returns the new block length as a `Result`.
fn check_block_length(info: DispatchInfo, len: usize) -> Result<u32, DispatchError> {
fn check_block_length(info: DispatchInfo, len: usize) -> Result<u32, TransactionValidityError> {
let current_len = Module::<T>::all_extrinsics_len();
let maximum_len = T::MaximumBlockLength::get();
let limit = Self::get_dispatch_limit_ratio(info.class) * maximum_len;
let added_len = len as u32;
let next_len = current_len.saturating_add(added_len);
if next_len > limit {
return Err(DispatchError::Exhausted)
Err(InvalidTransaction::ExhaustsResources.into())
} else {
Ok(next_len)
}
Ok(next_len)
}
/// get the priority of an extrinsic denoted by `info`.
@@ -906,7 +924,7 @@ impl<T: Trait + Send + Sync> SignedExtension for CheckWeight<T> {
type AdditionalSigned = ();
type Pre = ();
fn additional_signed(&self) -> rstd::result::Result<(), &'static str> { Ok(()) }
fn additional_signed(&self) -> rstd::result::Result<(), TransactionValidityError> { Ok(()) }
fn pre_dispatch(
self,
@@ -914,7 +932,7 @@ impl<T: Trait + Send + Sync> SignedExtension for CheckWeight<T> {
_call: &Self::Call,
info: DispatchInfo,
len: usize,
) -> Result<(), DispatchError> {
) -> Result<(), ApplyError> {
let next_len = Self::check_block_length(info, len)?;
AllExtrinsicsLen::put(next_len);
let next_weight = Self::check_weight(info)?;
@@ -928,12 +946,18 @@ impl<T: Trait + Send + Sync> SignedExtension for CheckWeight<T> {
_call: &Self::Call,
info: DispatchInfo,
len: usize,
) -> Result<ValidTransaction, DispatchError> {
) -> TransactionValidity {
// There is no point in writing to storage here since changes are discarded. This basically
// discards any transaction which is bigger than the length or weight limit **alone**,which
// discards any transaction which is bigger than the length or weight limit **alone**, which
// is a guarantee that it will fail in the pre-dispatch phase.
let _ = Self::check_block_length(info, len)?;
let _ = Self::check_weight(info)?;
if let Err(e) = Self::check_block_length(info, len) {
return Err(e);
}
if let Err(e) = Self::check_weight(info) {
return Err(e);
}
Ok(ValidTransaction { priority: Self::get_priority(info), ..Default::default() })
}
}
@@ -969,7 +993,7 @@ impl<T: Trait> SignedExtension for CheckNonce<T> {
type AdditionalSigned = ();
type Pre = ();
fn additional_signed(&self) -> rstd::result::Result<(), &'static str> { Ok(()) }
fn additional_signed(&self) -> rstd::result::Result<(), TransactionValidityError> { Ok(()) }
fn pre_dispatch(
self,
@@ -977,13 +1001,18 @@ impl<T: Trait> SignedExtension for CheckNonce<T> {
_call: &Self::Call,
_info: DispatchInfo,
_len: usize,
) -> Result<(), DispatchError> {
) -> Result<(), ApplyError> {
let expected = <AccountNonce<T>>::get(who);
if self.0 != expected {
return Err(
if self.0 < expected { DispatchError::Stale } else { DispatchError::Future }
if self.0 < expected {
InvalidTransaction::Stale
} else {
InvalidTransaction::Future
}.into()
)
}
<AccountNonce<T>>::insert(who, expected + T::Index::one());
Ok(())
}
@@ -994,11 +1023,11 @@ impl<T: Trait> SignedExtension for CheckNonce<T> {
_call: &Self::Call,
info: DispatchInfo,
_len: usize,
) -> Result<ValidTransaction, DispatchError> {
) -> TransactionValidity {
// check index
let expected = <AccountNonce<T>>::get(who);
if self.0 < expected {
return Err(DispatchError::Stale)
return InvalidTransaction::Stale.into()
}
let provides = vec![Encode::encode(&(who, self.0))];
@@ -1048,7 +1077,7 @@ impl<T: Trait + Send + Sync> SignedExtension for CheckEra<T> {
_call: &Self::Call,
_info: DispatchInfo,
_len: usize,
) -> Result<ValidTransaction, DispatchError> {
) -> TransactionValidity {
let current_u64 = <Module<T>>::block_number().saturated_into::<u64>();
let valid_till = (self.0).0.death(current_u64);
Ok(ValidTransaction {
@@ -1057,11 +1086,14 @@ impl<T: Trait + Send + Sync> SignedExtension for CheckEra<T> {
})
}
fn additional_signed(&self) -> Result<Self::AdditionalSigned, &'static str> {
fn additional_signed(&self) -> Result<Self::AdditionalSigned, TransactionValidityError> {
let current_u64 = <Module<T>>::block_number().saturated_into::<u64>();
let n = (self.0).0.birth(current_u64).saturated_into::<T::BlockNumber>();
if !<BlockHash<T>>::exists(n) { Err("transaction birth block ancient")? }
Ok(<Module<T>>::block_hash(n))
if !<BlockHash<T>>::exists(n) {
Err(InvalidTransaction::AncientBirthBlock.into())
} else {
Ok(<Module<T>>::block_hash(n))
}
}
}
@@ -1089,7 +1121,7 @@ impl<T: Trait + Send + Sync> SignedExtension for CheckGenesis<T> {
type AdditionalSigned = T::Hash;
type Pre = ();
fn additional_signed(&self) -> Result<Self::AdditionalSigned, &'static str> {
fn additional_signed(&self) -> Result<Self::AdditionalSigned, TransactionValidityError> {
Ok(<Module<T>>::block_hash(T::BlockNumber::zero()))
}
}
@@ -1118,7 +1150,7 @@ impl<T: Trait + Send + Sync> SignedExtension for CheckVersion<T> {
type AdditionalSigned = u32;
type Pre = ();
fn additional_signed(&self) -> Result<Self::AdditionalSigned, &'static str> {
fn additional_signed(&self) -> Result<Self::AdditionalSigned, TransactionValidityError> {
Ok(<Module<T>>::runtime_version().spec_version)
}
}
@@ -1133,7 +1165,8 @@ impl<T> Default for ChainContext<T> {
impl<T: Trait> Lookup for ChainContext<T> {
type Source = <T::Lookup as StaticLookup>::Source;
type Target = <T::Lookup as StaticLookup>::Target;
fn lookup(&self, s: Self::Source) -> rstd::result::Result<Self::Target, &'static str> {
fn lookup(&self, s: Self::Source) -> Result<Self::Target, LookupError> {
<T::Lookup as StaticLookup>::lookup(s)
}
}
@@ -1143,10 +1176,10 @@ mod tests {
use super::*;
use runtime_io::with_externalities;
use primitives::H256;
use sr_primitives::{traits::{BlakeTwo256, IdentityLookup}, testing::Header};
use sr_primitives::{traits::{BlakeTwo256, IdentityLookup}, testing::Header, DispatchError};
use support::{impl_outer_origin, parameter_types};
impl_outer_origin!{
impl_outer_origin! {
pub enum Origin for Test where system = super {}
}
@@ -1183,7 +1216,7 @@ mod tests {
fn from(e: Event) -> u16 {
match e {
Event::ExtrinsicSuccess => 100,
Event::ExtrinsicFailed => 101,
Event::ExtrinsicFailed(_) => 101,
}
}
}
@@ -1232,16 +1265,19 @@ mod tests {
System::initialize(&2, &[0u8; 32].into(), &[0u8; 32].into(), &Default::default());
System::deposit_event(42u16);
System::note_applied_extrinsic(&Ok(()), 0);
System::note_applied_extrinsic(&Err(""), 0);
System::note_applied_extrinsic(&Err(DispatchError::new(Some(1), 2, None)), 0);
System::note_finished_extrinsics();
System::deposit_event(3u16);
System::finalize();
assert_eq!(System::events(), vec![
EventRecord { phase: Phase::ApplyExtrinsic(0), event: 42u16, topics: vec![] },
EventRecord { phase: Phase::ApplyExtrinsic(0), event: 100u16, topics: vec![] },
EventRecord { phase: Phase::ApplyExtrinsic(1), event: 101u16, topics: vec![] },
EventRecord { phase: Phase::Finalization, event: 3u16, topics: vec![] }
]);
assert_eq!(
System::events(),
vec![
EventRecord { phase: Phase::ApplyExtrinsic(0), event: 42u16, topics: vec![] },
EventRecord { phase: Phase::ApplyExtrinsic(0), event: 100u16, topics: vec![] },
EventRecord { phase: Phase::ApplyExtrinsic(1), event: 101u16, topics: vec![] },
EventRecord { phase: Phase::Finalization, event: 3u16, topics: vec![] }
]
);
});
}
@@ -1440,14 +1476,17 @@ mod tests {
let op = DispatchInfo { weight: 100, class: DispatchClass::Operational };
let len = 0_usize;
assert_eq!(
CheckWeight::<Test>(PhantomData).validate(&1, CALL, normal, len).unwrap().priority,
100,
);
assert_eq!(
CheckWeight::<Test>(PhantomData).validate(&1, CALL, op, len).unwrap().priority,
Bounded::max_value(),
);
let priority = CheckWeight::<Test>(PhantomData)
.validate(&1, CALL, normal, len)
.unwrap()
.priority;
assert_eq!(priority, 100);
let priority = CheckWeight::<Test>(PhantomData)
.validate(&1, CALL, op, len)
.unwrap()
.priority;
assert_eq!(priority, Bounded::max_value());
})
}
@@ -1481,7 +1520,7 @@ mod tests {
// future
assert_eq!(
CheckEra::<Test>::from(Era::mortal(4, 2)).additional_signed().err().unwrap(),
"transaction birth block ancient"
InvalidTransaction::AncientBirthBlock.into(),
);
// correct
@@ -1503,10 +1542,7 @@ mod tests {
System::set_block_number(17);
<BlockHash<Test>>::insert(16, H256::repeat_byte(1));
assert_eq!(
ext.validate(&1, CALL, normal, len).unwrap().longevity,
15,
);
assert_eq!(ext.validate(&1, CALL, normal, len).unwrap().longevity, 15);
})
}
}