mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-07-21 15:35:42 +00:00
Allow modules to validate transaction, second attempt (#2463)
* first impl * rename origin::inherent to none * fix * fix * Apply suggestions from code review Co-Authored-By: thiolliere <gui.thiolliere@gmail.com> * comment * better error * doc * (add unsigned module 🤦) * doc * fix * implement for node-template as well * add validated unsigned to executor * fix * fix * bump version * testing xt * remove extraneous logic * licence * impl test
This commit is contained in:
@@ -199,7 +199,10 @@ impl<'a, Xt> Deserialize<'a> for Block<Xt> where Block<Xt>: Decode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Test transaction
|
/// Test transaction, tuple of (sender, index, call)
|
||||||
|
/// with index only used if sender is some.
|
||||||
|
///
|
||||||
|
/// If sender is some then the transaction is signed otherwise it is unsigned.
|
||||||
#[derive(PartialEq, Eq, Clone, Encode, Decode)]
|
#[derive(PartialEq, Eq, Clone, Encode, Decode)]
|
||||||
pub struct TestXt<Call>(pub Option<u64>, pub u64, pub Call);
|
pub struct TestXt<Call>(pub Option<u64>, pub u64, pub Call);
|
||||||
|
|
||||||
@@ -222,7 +225,7 @@ impl<Call: Codec + Sync + Send, Context> Checkable<Context> for TestXt<Call> {
|
|||||||
}
|
}
|
||||||
impl<Call: Codec + Sync + Send> traits::Extrinsic for TestXt<Call> {
|
impl<Call: Codec + Sync + Send> traits::Extrinsic for TestXt<Call> {
|
||||||
fn is_signed(&self) -> Option<bool> {
|
fn is_signed(&self) -> Option<bool> {
|
||||||
None
|
Some(self.0.is_some())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl<Call> Applyable for TestXt<Call> where
|
impl<Call> Applyable for TestXt<Call> where
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ use runtime_io;
|
|||||||
#[cfg(feature = "std")] use serde::{Serialize, Deserialize, de::DeserializeOwned};
|
#[cfg(feature = "std")] use serde::{Serialize, Deserialize, de::DeserializeOwned};
|
||||||
use substrate_primitives::{self, Hasher, Blake2Hasher};
|
use substrate_primitives::{self, Hasher, Blake2Hasher};
|
||||||
use crate::codec::{Codec, Encode, HasCompact};
|
use crate::codec::{Codec, Encode, HasCompact};
|
||||||
|
use crate::transaction_validity::TransactionValidity;
|
||||||
pub use integer_sqrt::IntegerSquareRoot;
|
pub use integer_sqrt::IntegerSquareRoot;
|
||||||
pub use num_traits::{
|
pub use num_traits::{
|
||||||
Zero, One, Bounded, CheckedAdd, CheckedSub, CheckedMul, CheckedDiv,
|
Zero, One, Bounded, CheckedAdd, CheckedSub, CheckedMul, CheckedDiv,
|
||||||
@@ -786,3 +787,17 @@ pub trait RuntimeApiInfo {
|
|||||||
/// The version of the runtime api.
|
/// The version of the runtime api.
|
||||||
const VERSION: u32;
|
const VERSION: u32;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Something that can validate unsigned extrinsics.
|
||||||
|
pub trait ValidateUnsigned {
|
||||||
|
/// The call to validate
|
||||||
|
type Call;
|
||||||
|
|
||||||
|
/// Return the validity of the call
|
||||||
|
///
|
||||||
|
/// This doesn't execute any side-effects; it merely checks
|
||||||
|
/// whether the transaction would panic if it were included or not.
|
||||||
|
///
|
||||||
|
/// Changes made to storage should be discarded by caller.
|
||||||
|
fn validate_unsigned(call: &Self::Call) -> TransactionValidity;
|
||||||
|
}
|
||||||
|
|||||||
@@ -224,7 +224,7 @@ pub type UncheckedExtrinsic = generic::UncheckedMortalCompactExtrinsic<Address,
|
|||||||
/// Extrinsic type that has already been checked.
|
/// Extrinsic type that has already been checked.
|
||||||
pub type CheckedExtrinsic = generic::CheckedExtrinsic<AccountId, Nonce, Call>;
|
pub type CheckedExtrinsic = generic::CheckedExtrinsic<AccountId, Nonce, Call>;
|
||||||
/// Executive: handles dispatch to the various modules.
|
/// Executive: handles dispatch to the various modules.
|
||||||
pub type Executive = executive::Executive<Runtime, Block, Context, Balances, AllModules>;
|
pub type Executive = executive::Executive<Runtime, Block, Context, Balances, Runtime, AllModules>;
|
||||||
|
|
||||||
// Implement our runtime API endpoints. This is just a bunch of proxying.
|
// Implement our runtime API endpoints. This is just a bunch of proxying.
|
||||||
impl_runtime_apis! {
|
impl_runtime_apis! {
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ use client::{
|
|||||||
use runtime_primitives::{ApplyResult, generic, create_runtime_str};
|
use runtime_primitives::{ApplyResult, generic, create_runtime_str};
|
||||||
use runtime_primitives::transaction_validity::TransactionValidity;
|
use runtime_primitives::transaction_validity::TransactionValidity;
|
||||||
use runtime_primitives::traits::{
|
use runtime_primitives::traits::{
|
||||||
BlakeTwo256, Block as BlockT, DigestFor, NumberFor, StaticLookup, AuthorityIdFor, Convert
|
BlakeTwo256, Block as BlockT, DigestFor, NumberFor, StaticLookup, AuthorityIdFor, Convert,
|
||||||
};
|
};
|
||||||
use version::RuntimeVersion;
|
use version::RuntimeVersion;
|
||||||
use council::{motions as council_motions, voting as council_voting};
|
use council::{motions as council_motions, voting as council_voting};
|
||||||
@@ -58,8 +58,8 @@ pub const VERSION: RuntimeVersion = RuntimeVersion {
|
|||||||
spec_name: create_runtime_str!("node"),
|
spec_name: create_runtime_str!("node"),
|
||||||
impl_name: create_runtime_str!("substrate-node"),
|
impl_name: create_runtime_str!("substrate-node"),
|
||||||
authoring_version: 10,
|
authoring_version: 10,
|
||||||
spec_version: 74,
|
spec_version: 75,
|
||||||
impl_version: 74,
|
impl_version: 75,
|
||||||
apis: RUNTIME_API_VERSIONS,
|
apis: RUNTIME_API_VERSIONS,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -249,7 +249,7 @@ pub type UncheckedExtrinsic = generic::UncheckedMortalCompactExtrinsic<Address,
|
|||||||
/// Extrinsic type that has already been checked.
|
/// Extrinsic type that has already been checked.
|
||||||
pub type CheckedExtrinsic = generic::CheckedExtrinsic<AccountId, Index, Call>;
|
pub type CheckedExtrinsic = generic::CheckedExtrinsic<AccountId, Index, Call>;
|
||||||
/// Executive: handles dispatch to the various modules.
|
/// Executive: handles dispatch to the various modules.
|
||||||
pub type Executive = executive::Executive<Runtime, Block, system::ChainContext<Runtime>, Balances, AllModules>;
|
pub type Executive = executive::Executive<Runtime, Block, system::ChainContext<Runtime>, Balances, Runtime, AllModules>;
|
||||||
|
|
||||||
impl_runtime_apis! {
|
impl_runtime_apis! {
|
||||||
impl client_api::Core<Block> for Runtime {
|
impl client_api::Core<Block> for Runtime {
|
||||||
|
|||||||
@@ -105,7 +105,7 @@
|
|||||||
//! pub type NegativeImbalanceOf<T> = <<T as Trait>::Currency as Currency<<T as system::Trait>::AccountId>>::NegativeImbalance;
|
//! pub type NegativeImbalanceOf<T> = <<T as Trait>::Currency as Currency<<T as system::Trait>::AccountId>>::NegativeImbalance;
|
||||||
//!
|
//!
|
||||||
//! # fn main() {}
|
//! # fn main() {}
|
||||||
//!```
|
//! ```
|
||||||
//!
|
//!
|
||||||
//! The Staking module uses the `LockableCurrency` trait to lock a stash account's funds:
|
//! The Staking module uses the `LockableCurrency` trait to lock a stash account's funds:
|
||||||
//!
|
//!
|
||||||
|
|||||||
@@ -136,7 +136,7 @@ use srml_support::storage::StorageValue;
|
|||||||
use srml_support::storage::unhashed::StorageVec;
|
use srml_support::storage::unhashed::StorageVec;
|
||||||
use primitives::traits::{MaybeSerializeDebug, Member};
|
use primitives::traits::{MaybeSerializeDebug, Member};
|
||||||
use substrate_primitives::storage::well_known_keys;
|
use substrate_primitives::storage::well_known_keys;
|
||||||
use system::{ensure_signed, ensure_inherent};
|
use system::{ensure_signed, ensure_none};
|
||||||
use inherents::{
|
use inherents::{
|
||||||
ProvideInherent, InherentData, InherentIdentifier, RuntimeString, MakeFatalError
|
ProvideInherent, InherentData, InherentIdentifier, RuntimeString, MakeFatalError
|
||||||
};
|
};
|
||||||
@@ -298,7 +298,7 @@ decl_module! {
|
|||||||
|
|
||||||
/// Note that the previous block's validator missed its opportunity to propose a block.
|
/// Note that the previous block's validator missed its opportunity to propose a block.
|
||||||
fn note_offline(origin, offline: <T::InherentOfflineReport as InherentOfflineReport>::Inherent) {
|
fn note_offline(origin, offline: <T::InherentOfflineReport as InherentOfflineReport>::Inherent) {
|
||||||
ensure_inherent(origin)?;
|
ensure_none(origin)?;
|
||||||
|
|
||||||
T::InherentOfflineReport::handle_report(offline);
|
T::InherentOfflineReport::handle_report(offline);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -476,7 +476,7 @@ decl_module! {
|
|||||||
Some(system::RawOrigin::Signed(ref account)) if aux_sender.is_none() => {
|
Some(system::RawOrigin::Signed(ref account)) if aux_sender.is_none() => {
|
||||||
(true, account)
|
(true, account)
|
||||||
},
|
},
|
||||||
Some(system::RawOrigin::Inherent) if aux_sender.is_some() => {
|
Some(system::RawOrigin::None) if aux_sender.is_some() => {
|
||||||
(false, aux_sender.as_ref().expect("checked above"))
|
(false, aux_sender.as_ref().expect("checked above"))
|
||||||
},
|
},
|
||||||
_ => return Err("Invalid surcharge claim: origin must be signed or \
|
_ => return Err("Invalid surcharge claim: origin must be signed or \
|
||||||
|
|||||||
@@ -754,7 +754,7 @@ fn call_contract_removals() {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn inherent_claim_surcharge_contract_removals() {
|
fn inherent_claim_surcharge_contract_removals() {
|
||||||
removals(|| Contract::claim_surcharge(Origin::INHERENT, BOB, Some(ALICE)).is_ok());
|
removals(|| Contract::claim_surcharge(Origin::NONE, BOB, Some(ALICE)).is_ok());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -765,10 +765,10 @@ fn signed_claim_surcharge_contract_removals() {
|
|||||||
#[test]
|
#[test]
|
||||||
fn claim_surcharge_malus() {
|
fn claim_surcharge_malus() {
|
||||||
// Test surcharge malus for inherent
|
// Test surcharge malus for inherent
|
||||||
claim_surcharge(4, || Contract::claim_surcharge(Origin::INHERENT, BOB, Some(ALICE)).is_ok(), true);
|
claim_surcharge(4, || Contract::claim_surcharge(Origin::NONE, BOB, Some(ALICE)).is_ok(), true);
|
||||||
claim_surcharge(3, || Contract::claim_surcharge(Origin::INHERENT, BOB, Some(ALICE)).is_ok(), true);
|
claim_surcharge(3, || Contract::claim_surcharge(Origin::NONE, BOB, Some(ALICE)).is_ok(), true);
|
||||||
claim_surcharge(2, || Contract::claim_surcharge(Origin::INHERENT, BOB, Some(ALICE)).is_ok(), true);
|
claim_surcharge(2, || Contract::claim_surcharge(Origin::NONE, BOB, Some(ALICE)).is_ok(), true);
|
||||||
claim_surcharge(1, || Contract::claim_surcharge(Origin::INHERENT, BOB, Some(ALICE)).is_ok(), false);
|
claim_surcharge(1, || Contract::claim_surcharge(Origin::NONE, BOB, Some(ALICE)).is_ok(), false);
|
||||||
|
|
||||||
// Test surcharge malus for signed
|
// Test surcharge malus for signed
|
||||||
claim_surcharge(4, || Contract::claim_surcharge(Origin::signed(ALICE), BOB, None).is_ok(), true);
|
claim_surcharge(4, || Contract::claim_surcharge(Origin::signed(ALICE), BOB, None).is_ok(), true);
|
||||||
|
|||||||
@@ -107,9 +107,9 @@
|
|||||||
//!
|
//!
|
||||||
//! \### Supported Origins
|
//! \### Supported Origins
|
||||||
//!
|
//!
|
||||||
//! // What origins are used and supported in this module (root, signed, inherent)
|
//! // What origins are used and supported in this module (root, signed, none)
|
||||||
//! // i.e. root when <code>\`ensure_root\`</code> used
|
//! // i.e. root when <code>\`ensure_root\`</code> used
|
||||||
//! // i.e. inherent when <code>\`ensure_inherent\`</code> used
|
//! // i.e. none when <code>\`ensure_none\`</code> used
|
||||||
//! // i.e. signed when <code>\`ensure_signed\`</code> used
|
//! // i.e. signed when <code>\`ensure_signed\`</code> used
|
||||||
//!
|
//!
|
||||||
//! <code>\`inherent\`</code> <INSERT_DESCRIPTION>
|
//! <code>\`inherent\`</code> <INSERT_DESCRIPTION>
|
||||||
@@ -322,7 +322,9 @@ decl_event!(
|
|||||||
// Generally you'll want to split these into three groups:
|
// Generally you'll want to split these into three groups:
|
||||||
// - Public calls that are signed by an external account.
|
// - Public calls that are signed by an external account.
|
||||||
// - Root calls that are allowed to be made only by the governance system.
|
// - Root calls that are allowed to be made only by the governance system.
|
||||||
// - Inherent calls that are allowed to be made only by the block authors and validators.
|
// - Unsigned calls that can be of two kinds:
|
||||||
|
// * "Inherent extrinsics" that are opinions generally held by the block authors that build child blocks.
|
||||||
|
// * Unsigned Transactions that are of intrinsic recognisable utility to the network, and are validated by the runtime.
|
||||||
//
|
//
|
||||||
// Information about where this dispatch initiated from is provided as the first argument
|
// Information about where this dispatch initiated from is provided as the first argument
|
||||||
// "origin". As such functions must always look like:
|
// "origin". As such functions must always look like:
|
||||||
@@ -337,10 +339,10 @@ decl_event!(
|
|||||||
// `fn foo(origin: T::Origin, bar: Bar, baz: Baz) { ... }`
|
// `fn foo(origin: T::Origin, bar: Bar, baz: Baz) { ... }`
|
||||||
//
|
//
|
||||||
// There are three entries in the `system::Origin` enum that correspond
|
// There are three entries in the `system::Origin` enum that correspond
|
||||||
// to the above bullets: `::Signed(AccountId)`, `::Root` and `::Inherent`. You should always match
|
// to the above bullets: `::Signed(AccountId)`, `::Root` and `::None`. You should always match
|
||||||
// against them as the first thing you do in your function. There are three convenience calls
|
// against them as the first thing you do in your function. There are three convenience calls
|
||||||
// in system that do the matching for you and return a convenient result: `ensure_signed`,
|
// in system that do the matching for you and return a convenient result: `ensure_signed`,
|
||||||
// `ensure_root` and `ensure_inherent`.
|
// `ensure_root` and `ensure_none`.
|
||||||
decl_module! {
|
decl_module! {
|
||||||
// Simple declaration of the `Module` type. Lets the macro know what its working on.
|
// Simple declaration of the `Module` type. Lets the macro know what its working on.
|
||||||
pub struct Module<T: Trait> for enum Call where origin: T::Origin {
|
pub struct Module<T: Trait> for enum Call where origin: T::Origin {
|
||||||
@@ -448,7 +450,7 @@ decl_module! {
|
|||||||
// For instance you can generate extrinsics for the upcoming produced block.
|
// For instance you can generate extrinsics for the upcoming produced block.
|
||||||
fn offchain_worker(_n: T::BlockNumber) {
|
fn offchain_worker(_n: T::BlockNumber) {
|
||||||
// We don't do anything here.
|
// We don't do anything here.
|
||||||
// but we could dispatch extrinsic (transaction/inherent) using
|
// but we could dispatch extrinsic (transaction/unsigned/inherent) using
|
||||||
// runtime_io::submit_extrinsic
|
// runtime_io::submit_extrinsic
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -59,8 +59,17 @@
|
|||||||
//! # pub type Balances = u64;
|
//! # pub type Balances = u64;
|
||||||
//! # pub type AllModules = u64;
|
//! # pub type AllModules = u64;
|
||||||
//! # pub enum Runtime {};
|
//! # pub enum Runtime {};
|
||||||
|
//! # use primitives::transaction_validity::TransactionValidity;
|
||||||
|
//! # use primitives::traits::ValidateUnsigned;
|
||||||
|
//! # impl ValidateUnsigned for Runtime {
|
||||||
|
//! # type Call = ();
|
||||||
|
//! #
|
||||||
|
//! # fn validate_unsigned(_call: &Self::Call) -> TransactionValidity {
|
||||||
|
//! # TransactionValidity::Invalid(0)
|
||||||
|
//! # }
|
||||||
|
//! # }
|
||||||
//! /// Executive: handles dispatch to the various modules.
|
//! /// Executive: handles dispatch to the various modules.
|
||||||
//! pub type Executive = executive::Executive<Runtime, Block, Context, Balances, AllModules>;
|
//! pub type Executive = executive::Executive<Runtime, Block, Context, Balances, Runtime, AllModules>;
|
||||||
//! ```
|
//! ```
|
||||||
|
|
||||||
#![cfg_attr(not(feature = "std"), no_std)]
|
#![cfg_attr(not(feature = "std"), no_std)]
|
||||||
@@ -70,7 +79,8 @@ use rstd::marker::PhantomData;
|
|||||||
use rstd::result;
|
use rstd::result;
|
||||||
use primitives::traits::{
|
use primitives::traits::{
|
||||||
self, Header, Zero, One, Checkable, Applyable, CheckEqual, OnFinalize,
|
self, Header, Zero, One, Checkable, Applyable, CheckEqual, OnFinalize,
|
||||||
OnInitialize, Digest, NumberFor, Block as BlockT, OffchainWorker
|
OnInitialize, Digest, NumberFor, Block as BlockT, OffchainWorker,
|
||||||
|
ValidateUnsigned,
|
||||||
};
|
};
|
||||||
use srml_support::{Dispatchable, traits::MakePayment};
|
use srml_support::{Dispatchable, traits::MakePayment};
|
||||||
use parity_codec::{Codec, Encode};
|
use parity_codec::{Codec, Encode};
|
||||||
@@ -101,8 +111,8 @@ pub trait ExecuteBlock<Block: BlockT> {
|
|||||||
fn execute_block(block: Block);
|
fn execute_block(block: Block);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Executive<System, Block, Context, Payment, AllModules>(
|
pub struct Executive<System, Block, Context, Payment, UnsignedValidator, AllModules>(
|
||||||
PhantomData<(System, Block, Context, Payment, AllModules)>
|
PhantomData<(System, Block, Context, Payment, UnsignedValidator, AllModules)>
|
||||||
);
|
);
|
||||||
|
|
||||||
impl<
|
impl<
|
||||||
@@ -110,15 +120,18 @@ impl<
|
|||||||
Block: traits::Block<Header=System::Header, Hash=System::Hash>,
|
Block: traits::Block<Header=System::Header, Hash=System::Hash>,
|
||||||
Context: Default,
|
Context: Default,
|
||||||
Payment: MakePayment<System::AccountId>,
|
Payment: MakePayment<System::AccountId>,
|
||||||
|
UnsignedValidator,
|
||||||
AllModules: OnInitialize<System::BlockNumber> + OnFinalize<System::BlockNumber> + OffchainWorker<System::BlockNumber>,
|
AllModules: OnInitialize<System::BlockNumber> + OnFinalize<System::BlockNumber> + OffchainWorker<System::BlockNumber>,
|
||||||
> ExecuteBlock<Block> for Executive<System, Block, Context, Payment, AllModules> where
|
> ExecuteBlock<Block> for Executive<System, Block, Context, Payment, UnsignedValidator, AllModules>
|
||||||
|
where
|
||||||
Block::Extrinsic: Checkable<Context> + Codec,
|
Block::Extrinsic: Checkable<Context> + Codec,
|
||||||
<Block::Extrinsic as Checkable<Context>>::Checked: Applyable<Index=System::Index, AccountId=System::AccountId>,
|
<Block::Extrinsic as Checkable<Context>>::Checked: Applyable<Index=System::Index, AccountId=System::AccountId>,
|
||||||
<<Block::Extrinsic as Checkable<Context>>::Checked as Applyable>::Call: Dispatchable,
|
<<Block::Extrinsic as Checkable<Context>>::Checked as Applyable>::Call: Dispatchable,
|
||||||
<<<Block::Extrinsic as Checkable<Context>>::Checked as Applyable>::Call as Dispatchable>::Origin: From<Option<System::AccountId>>
|
<<<Block::Extrinsic as Checkable<Context>>::Checked as Applyable>::Call as Dispatchable>::Origin: From<Option<System::AccountId>>,
|
||||||
|
UnsignedValidator: ValidateUnsigned<Call=<<Block::Extrinsic as Checkable<Context>>::Checked as Applyable>::Call>
|
||||||
{
|
{
|
||||||
fn execute_block(block: Block) {
|
fn execute_block(block: Block) {
|
||||||
Executive::<System, Block, Context, Payment, AllModules>::execute_block(block);
|
Executive::<System, Block, Context, Payment, UnsignedValidator, AllModules>::execute_block(block);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -127,12 +140,15 @@ impl<
|
|||||||
Block: traits::Block<Header=System::Header, Hash=System::Hash>,
|
Block: traits::Block<Header=System::Header, Hash=System::Hash>,
|
||||||
Context: Default,
|
Context: Default,
|
||||||
Payment: MakePayment<System::AccountId>,
|
Payment: MakePayment<System::AccountId>,
|
||||||
|
UnsignedValidator,
|
||||||
AllModules: OnInitialize<System::BlockNumber> + OnFinalize<System::BlockNumber> + OffchainWorker<System::BlockNumber>,
|
AllModules: OnInitialize<System::BlockNumber> + OnFinalize<System::BlockNumber> + OffchainWorker<System::BlockNumber>,
|
||||||
> Executive<System, Block, Context, Payment, AllModules> where
|
> Executive<System, Block, Context, Payment, UnsignedValidator, AllModules>
|
||||||
|
where
|
||||||
Block::Extrinsic: Checkable<Context> + Codec,
|
Block::Extrinsic: Checkable<Context> + Codec,
|
||||||
<Block::Extrinsic as Checkable<Context>>::Checked: Applyable<Index=System::Index, AccountId=System::AccountId>,
|
<Block::Extrinsic as Checkable<Context>>::Checked: Applyable<Index=System::Index, AccountId=System::AccountId>,
|
||||||
<<Block::Extrinsic as Checkable<Context>>::Checked as Applyable>::Call: Dispatchable,
|
<<Block::Extrinsic as Checkable<Context>>::Checked as Applyable>::Call: Dispatchable,
|
||||||
<<<Block::Extrinsic as Checkable<Context>>::Checked as Applyable>::Call as Dispatchable>::Origin: From<Option<System::AccountId>>
|
<<<Block::Extrinsic as Checkable<Context>>::Checked as Applyable>::Call as Dispatchable>::Origin: From<Option<System::AccountId>>,
|
||||||
|
UnsignedValidator: ValidateUnsigned<Call=<<Block::Extrinsic as Checkable<Context>>::Checked as Applyable>::Call>
|
||||||
{
|
{
|
||||||
/// Start the execution of a particular block.
|
/// Start the execution of a particular block.
|
||||||
pub fn initialize_block(header: &System::Header) {
|
pub fn initialize_block(header: &System::Header) {
|
||||||
@@ -290,7 +306,7 @@ impl<
|
|||||||
assert!(header.state_root() == storage_root, "Storage root must match that calculated.");
|
assert!(header.state_root() == storage_root, "Storage root must match that calculated.");
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Check a given transaction for validity. This doesn't execute any
|
/// Check a given signed transaction for validity. This doesn't execute any
|
||||||
/// side-effects; it merely checks whether the transaction would panic if it were included or not.
|
/// side-effects; it merely checks whether the transaction would panic if it were included or not.
|
||||||
///
|
///
|
||||||
/// Changes made to storage should be discarded.
|
/// Changes made to storage should be discarded.
|
||||||
@@ -313,38 +329,37 @@ impl<
|
|||||||
Err(_) => return TransactionValidity::Invalid(UNKNOWN_ERROR),
|
Err(_) => return TransactionValidity::Invalid(UNKNOWN_ERROR),
|
||||||
};
|
};
|
||||||
|
|
||||||
if let (Some(sender), Some(index)) = (xt.sender(), xt.index()) {
|
match (xt.sender(), xt.index()) {
|
||||||
// pay any fees
|
(Some(sender), Some(index)) => {
|
||||||
if Payment::make_payment(sender, encoded_len).is_err() {
|
// pay any fees
|
||||||
return TransactionValidity::Invalid(ApplyError::CantPay as i8)
|
if Payment::make_payment(sender, encoded_len).is_err() {
|
||||||
}
|
return TransactionValidity::Invalid(ApplyError::CantPay as i8)
|
||||||
|
}
|
||||||
|
|
||||||
// check index
|
// check index
|
||||||
let expected_index = <system::Module<System>>::account_nonce(sender);
|
let expected_index = <system::Module<System>>::account_nonce(sender);
|
||||||
if index < &expected_index {
|
if index < &expected_index {
|
||||||
return TransactionValidity::Invalid(ApplyError::Stale as i8)
|
return TransactionValidity::Invalid(ApplyError::Stale as i8)
|
||||||
}
|
}
|
||||||
|
|
||||||
let index = *index;
|
let index = *index;
|
||||||
let provides = vec![(sender, index).encode()];
|
let provides = vec![(sender, index).encode()];
|
||||||
let requires = if expected_index < index {
|
let requires = if expected_index < index {
|
||||||
vec![(sender, index - One::one()).encode()]
|
vec![(sender, index - One::one()).encode()]
|
||||||
} else {
|
} else {
|
||||||
vec![]
|
vec![]
|
||||||
};
|
};
|
||||||
|
|
||||||
TransactionValidity::Valid {
|
TransactionValidity::Valid {
|
||||||
priority: encoded_len as TransactionPriority,
|
priority: encoded_len as TransactionPriority,
|
||||||
requires,
|
requires,
|
||||||
provides,
|
provides,
|
||||||
longevity: TransactionLongevity::max_value(),
|
longevity: TransactionLongevity::max_value(),
|
||||||
}
|
}
|
||||||
} else {
|
},
|
||||||
return TransactionValidity::Invalid(if xt.sender().is_none() {
|
(None, None) => UnsignedValidator::validate_unsigned(&xt.deconstruct().0),
|
||||||
MISSING_SENDER
|
(Some(_), None) => TransactionValidity::Invalid(INVALID_INDEX),
|
||||||
} else {
|
(None, Some(_)) => TransactionValidity::Invalid(MISSING_SENDER),
|
||||||
INVALID_INDEX
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -404,8 +419,24 @@ mod tests {
|
|||||||
type TransferPayment = ();
|
type TransferPayment = ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl ValidateUnsigned for Runtime {
|
||||||
|
type Call = Call<Runtime>;
|
||||||
|
|
||||||
|
fn validate_unsigned(call: &Self::Call) -> TransactionValidity {
|
||||||
|
match call {
|
||||||
|
Call::set_balance(_, _, _) => TransactionValidity::Valid {
|
||||||
|
priority: 0,
|
||||||
|
requires: vec![],
|
||||||
|
provides: vec![],
|
||||||
|
longevity: std::u64::MAX,
|
||||||
|
},
|
||||||
|
_ => TransactionValidity::Invalid(0),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
type TestXt = primitives::testing::TestXt<Call<Runtime>>;
|
type TestXt = primitives::testing::TestXt<Call<Runtime>>;
|
||||||
type Executive = super::Executive<Runtime, Block<TestXt>, system::ChainContext<Runtime>, balances::Module<Runtime>, ()>;
|
type Executive = super::Executive<Runtime, Block<TestXt>, system::ChainContext<Runtime>, balances::Module<Runtime>, Runtime, ()>;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn balance_transfer_dispatch_works() {
|
fn balance_transfer_dispatch_works() {
|
||||||
@@ -527,4 +558,21 @@ mod tests {
|
|||||||
run_test(false);
|
run_test(false);
|
||||||
run_test(true);
|
run_test(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn validate_unsigned() {
|
||||||
|
let xt = primitives::testing::TestXt(None, 0, Call::set_balance(33, 69, 69));
|
||||||
|
let valid = TransactionValidity::Valid {
|
||||||
|
priority: 0,
|
||||||
|
requires: vec![],
|
||||||
|
provides: vec![],
|
||||||
|
longevity: 18446744073709551615
|
||||||
|
};
|
||||||
|
let mut t = new_test_ext();
|
||||||
|
|
||||||
|
with_externalities(&mut t, || {
|
||||||
|
assert_eq!(Executive::validate_transaction(xt.clone()), valid);
|
||||||
|
assert_eq!(Executive::apply_extrinsic(xt), Ok(ApplyOutcome::Fail));
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ use srml_support::StorageValue;
|
|||||||
use primitives::traits::{As, One, Zero};
|
use primitives::traits::{As, One, Zero};
|
||||||
use rstd::{prelude::*, result, cmp, vec};
|
use rstd::{prelude::*, result, cmp, vec};
|
||||||
use parity_codec::Decode;
|
use parity_codec::Decode;
|
||||||
use srml_system::{ensure_inherent, Trait as SystemTrait};
|
use srml_system::{ensure_none, Trait as SystemTrait};
|
||||||
|
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
use parity_codec::Encode;
|
use parity_codec::Encode;
|
||||||
@@ -117,7 +117,7 @@ decl_module! {
|
|||||||
/// Hint that the author of this block thinks the best finalized
|
/// Hint that the author of this block thinks the best finalized
|
||||||
/// block is the given number.
|
/// block is the given number.
|
||||||
fn final_hint(origin, #[compact] hint: T::BlockNumber) {
|
fn final_hint(origin, #[compact] hint: T::BlockNumber) {
|
||||||
ensure_inherent(origin)?;
|
ensure_none(origin)?;
|
||||||
assert!(!<Self as Store>::Update::exists(), "Final hint must be updated only once in the block");
|
assert!(!<Self as Store>::Update::exists(), "Final hint must be updated only once in the block");
|
||||||
assert!(
|
assert!(
|
||||||
srml_system::Module::<T>::block_number() >= hint,
|
srml_system::Module::<T>::block_number() >= hint,
|
||||||
@@ -372,7 +372,7 @@ mod tests {
|
|||||||
System::initialize(&i, &parent_hash, &Default::default());
|
System::initialize(&i, &parent_hash, &Default::default());
|
||||||
assert_ok!(FinalityTracker::dispatch(
|
assert_ok!(FinalityTracker::dispatch(
|
||||||
Call::final_hint(i-1),
|
Call::final_hint(i-1),
|
||||||
Origin::INHERENT,
|
Origin::NONE,
|
||||||
));
|
));
|
||||||
FinalityTracker::on_finalize(i);
|
FinalityTracker::on_finalize(i);
|
||||||
let hdr = System::finalize();
|
let hdr = System::finalize();
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ pub use inherents::{InherentData, ProvideInherent, CheckInherentsResult, IsFatal
|
|||||||
///
|
///
|
||||||
/// ```nocompile
|
/// ```nocompile
|
||||||
/// impl_outer_inherent! {
|
/// impl_outer_inherent! {
|
||||||
/// pub struct InherentData where Block = Block, UncheckedExtrinsic = UncheckedExtrinsic {
|
/// impl Inherents where Block = Block, UncheckedExtrinsic = UncheckedExtrinsic {
|
||||||
/// timestamp: Timestamp,
|
/// timestamp: Timestamp,
|
||||||
/// consensus: Consensus,
|
/// consensus: Consensus,
|
||||||
/// /// Aura module using the `Timestamp` call.
|
/// /// Aura module using the `Timestamp` call.
|
||||||
|
|||||||
@@ -52,6 +52,8 @@ pub mod metadata;
|
|||||||
mod runtime;
|
mod runtime;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
pub mod inherent;
|
pub mod inherent;
|
||||||
|
#[macro_use]
|
||||||
|
pub mod unsigned;
|
||||||
mod double_map;
|
mod double_map;
|
||||||
pub mod traits;
|
pub mod traits;
|
||||||
|
|
||||||
|
|||||||
@@ -265,14 +265,14 @@ mod tests {
|
|||||||
pub enum RawOrigin<AccountId> {
|
pub enum RawOrigin<AccountId> {
|
||||||
Root,
|
Root,
|
||||||
Signed(AccountId),
|
Signed(AccountId),
|
||||||
Inherent,
|
None,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<AccountId> From<Option<AccountId>> for RawOrigin<AccountId> {
|
impl<AccountId> From<Option<AccountId>> for RawOrigin<AccountId> {
|
||||||
fn from(s: Option<AccountId>) -> RawOrigin<AccountId> {
|
fn from(s: Option<AccountId>) -> RawOrigin<AccountId> {
|
||||||
match s {
|
match s {
|
||||||
Some(who) => RawOrigin::Signed(who),
|
Some(who) => RawOrigin::Signed(who),
|
||||||
None => RawOrigin::Inherent,
|
None => RawOrigin::None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -101,7 +101,7 @@ macro_rules! impl_outer_origin {
|
|||||||
}
|
}
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
impl $name {
|
impl $name {
|
||||||
pub const INHERENT: Self = $name::system($system::RawOrigin::Inherent);
|
pub const NONE: Self = $name::system($system::RawOrigin::None);
|
||||||
pub const ROOT: Self = $name::system($system::RawOrigin::Root);
|
pub const ROOT: Self = $name::system($system::RawOrigin::Root);
|
||||||
pub fn signed(by: <$runtime as $system::Trait>::AccountId) -> Self {
|
pub fn signed(by: <$runtime as $system::Trait>::AccountId) -> Self {
|
||||||
$name::system($system::RawOrigin::Signed(by))
|
$name::system($system::RawOrigin::Signed(by))
|
||||||
@@ -156,14 +156,14 @@ mod tests {
|
|||||||
pub enum RawOrigin<AccountId> {
|
pub enum RawOrigin<AccountId> {
|
||||||
Root,
|
Root,
|
||||||
Signed(AccountId),
|
Signed(AccountId),
|
||||||
Inherent,
|
None,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<AccountId> From<Option<AccountId>> for RawOrigin<AccountId> {
|
impl<AccountId> From<Option<AccountId>> for RawOrigin<AccountId> {
|
||||||
fn from(s: Option<AccountId>) -> RawOrigin<AccountId> {
|
fn from(s: Option<AccountId>) -> RawOrigin<AccountId> {
|
||||||
match s {
|
match s {
|
||||||
Some(who) => RawOrigin::Signed(who),
|
Some(who) => RawOrigin::Signed(who),
|
||||||
None => RawOrigin::Inherent,
|
None => RawOrigin::None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -66,6 +66,7 @@
|
|||||||
/// - `Inherent $( (CALL) )*` - If the module provides/can check inherents. The optional parameter
|
/// - `Inherent $( (CALL) )*` - If the module provides/can check inherents. The optional parameter
|
||||||
/// is for modules that use a `Call` from a different module as
|
/// is for modules that use a `Call` from a different module as
|
||||||
/// inherent.
|
/// inherent.
|
||||||
|
/// - `ValidateUnsigned` - If the module validates unsigned extrinsics.
|
||||||
///
|
///
|
||||||
/// # Note
|
/// # Note
|
||||||
///
|
///
|
||||||
@@ -286,6 +287,13 @@ macro_rules! construct_runtime {
|
|||||||
$name: $module::{ $( $modules $( ( $( $modules_args ),* ) )* ),* }
|
$name: $module::{ $( $modules $( ( $( $modules_args ),* ) )* ),* }
|
||||||
),*;
|
),*;
|
||||||
);
|
);
|
||||||
|
$crate::__impl_outer_validate_unsigned!(
|
||||||
|
$runtime;
|
||||||
|
{};
|
||||||
|
$(
|
||||||
|
$name: $module::{ $( $modules $( ( $( $modules_args )* ) )* )* }
|
||||||
|
)*
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -947,3 +955,65 @@ macro_rules! __decl_instance_import {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A private macro that calls impl_outer_validate_unsigned for Call.
|
||||||
|
#[macro_export]
|
||||||
|
#[doc(hidden)]
|
||||||
|
macro_rules! __impl_outer_validate_unsigned {
|
||||||
|
(
|
||||||
|
$runtime:ident;
|
||||||
|
{ $( $parsed:tt )* };
|
||||||
|
$name:ident: $module:ident:: $(<$module_instance:ident>::)? {
|
||||||
|
ValidateUnsigned $( $modules:ident $( ( $( $modules_args:ident )* ) )* )*
|
||||||
|
}
|
||||||
|
$( $rest:tt )*
|
||||||
|
) => {
|
||||||
|
$crate::__impl_outer_validate_unsigned!(
|
||||||
|
$runtime;
|
||||||
|
{ $( $parsed )* $name };
|
||||||
|
$( $rest )*
|
||||||
|
);
|
||||||
|
};
|
||||||
|
(
|
||||||
|
$runtime:ident;
|
||||||
|
{ $( $parsed:tt )* };
|
||||||
|
$name:ident: $module:ident:: $(<$module_instance:ident>::)? {
|
||||||
|
$ignore:ident $( ( $( $args_ignore:ident )* ) )*
|
||||||
|
$( $modules:ident $( ( $( $modules_args:ident )* ) )* )*
|
||||||
|
}
|
||||||
|
$( $rest:tt )*
|
||||||
|
) => {
|
||||||
|
$crate::__impl_outer_validate_unsigned!(
|
||||||
|
$runtime;
|
||||||
|
{ $( $parsed )* };
|
||||||
|
$name: $module:: $(<$module_instance>::)? {
|
||||||
|
$( $modules $( ( $( $modules_args )* ) )* )*
|
||||||
|
}
|
||||||
|
$( $rest )*
|
||||||
|
);
|
||||||
|
};
|
||||||
|
(
|
||||||
|
$runtime:ident;
|
||||||
|
{ $( $parsed:tt )* };
|
||||||
|
$name:ident: $module:ident:: $(<$module_instance:ident>::)? {}
|
||||||
|
$( $rest:tt )*
|
||||||
|
) => {
|
||||||
|
$crate::__impl_outer_validate_unsigned!(
|
||||||
|
$runtime;
|
||||||
|
{ $( $parsed )* };
|
||||||
|
$( $rest )*
|
||||||
|
);
|
||||||
|
};
|
||||||
|
(
|
||||||
|
$runtime:ident;
|
||||||
|
{ $(
|
||||||
|
$parsed_modules:ident
|
||||||
|
)* };
|
||||||
|
) => {
|
||||||
|
$crate::impl_outer_validate_unsigned!(
|
||||||
|
impl ValidateUnsigned for $runtime {
|
||||||
|
$( $parsed_modules )*
|
||||||
|
}
|
||||||
|
);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|||||||
@@ -0,0 +1,153 @@
|
|||||||
|
// 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/>.
|
||||||
|
|
||||||
|
#[doc(hidden)]
|
||||||
|
pub use crate::runtime_primitives::traits::ValidateUnsigned;
|
||||||
|
#[doc(hidden)]
|
||||||
|
pub use crate::runtime_primitives::transaction_validity::TransactionValidity;
|
||||||
|
#[doc(hidden)]
|
||||||
|
pub use crate::runtime_primitives::ApplyError;
|
||||||
|
|
||||||
|
|
||||||
|
/// Implement `ValidateUnsigned` for `Runtime`.
|
||||||
|
/// All given modules need to implement `ValidateUnsigned`.
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// # mod timestamp {
|
||||||
|
/// # pub struct Module;
|
||||||
|
/// #
|
||||||
|
/// # impl srml_support::unsigned::ValidateUnsigned for Module {
|
||||||
|
/// # type Call = Call;
|
||||||
|
/// #
|
||||||
|
/// # fn validate_unsigned(call: &Self::Call) -> srml_support::unsigned::TransactionValidity {
|
||||||
|
/// # unimplemented!();
|
||||||
|
/// # }
|
||||||
|
/// # }
|
||||||
|
/// #
|
||||||
|
/// # pub enum Call {
|
||||||
|
/// # }
|
||||||
|
/// # }
|
||||||
|
/// #
|
||||||
|
/// # pub type Timestamp = timestamp::Module;
|
||||||
|
/// #
|
||||||
|
/// #
|
||||||
|
/// # pub enum Call {
|
||||||
|
/// # Timestamp(timestamp::Call),
|
||||||
|
/// # }
|
||||||
|
/// # #[allow(unused)]
|
||||||
|
/// pub struct Runtime;
|
||||||
|
///
|
||||||
|
/// srml_support::impl_outer_validate_unsigned! {
|
||||||
|
/// impl ValidateUnsigned for Runtime {
|
||||||
|
/// Timestamp
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! impl_outer_validate_unsigned {
|
||||||
|
(
|
||||||
|
impl ValidateUnsigned for $runtime:ident {
|
||||||
|
$( $module:ident )*
|
||||||
|
}
|
||||||
|
) => {
|
||||||
|
impl $crate::unsigned::ValidateUnsigned for $runtime {
|
||||||
|
type Call = Call;
|
||||||
|
|
||||||
|
fn validate_unsigned(call: &Self::Call) -> $crate::unsigned::TransactionValidity {
|
||||||
|
#[allow(unreachable_patterns)]
|
||||||
|
match call {
|
||||||
|
$( Call::$module(inner_call) => $module::validate_unsigned(inner_call), )*
|
||||||
|
_ => $crate::unsigned::TransactionValidity::Invalid($crate::unsigned::ApplyError::BadSignature as i8),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test_empty_call {
|
||||||
|
pub enum Call {
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Runtime;
|
||||||
|
|
||||||
|
impl_outer_validate_unsigned! {
|
||||||
|
impl ValidateUnsigned for Runtime {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test_partial_and_full_call {
|
||||||
|
pub mod timestamp {
|
||||||
|
pub struct Module;
|
||||||
|
|
||||||
|
impl super::super::ValidateUnsigned for Module {
|
||||||
|
type Call = Call;
|
||||||
|
|
||||||
|
fn validate_unsigned(_call: &Self::Call) -> super::super::TransactionValidity {
|
||||||
|
unimplemented!();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum Call {
|
||||||
|
Foo,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mod test_full_unsigned {
|
||||||
|
pub type Timestamp = super::timestamp::Module;
|
||||||
|
|
||||||
|
pub enum Call {
|
||||||
|
Timestamp(super::timestamp::Call),
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Runtime;
|
||||||
|
|
||||||
|
impl_outer_validate_unsigned! {
|
||||||
|
impl ValidateUnsigned for Runtime {
|
||||||
|
Timestamp
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn used() {
|
||||||
|
let _ = Call::Timestamp(super::timestamp::Call::Foo);
|
||||||
|
let _ = Runtime;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mod test_not_full_unsigned {
|
||||||
|
pub enum Call {
|
||||||
|
Timestamp(super::timestamp::Call),
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Runtime;
|
||||||
|
|
||||||
|
impl_outer_validate_unsigned! {
|
||||||
|
impl ValidateUnsigned for Runtime {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn used() {
|
||||||
|
let _ = Call::Timestamp(super::timestamp::Call::Foo);
|
||||||
|
let _ = Runtime;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
// 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/>.
|
||||||
|
|
||||||
|
//! Test crate for srml_support. Allow to make use of `srml_support::decl_storage`.
|
||||||
|
//! See tests directory.
|
||||||
|
|||||||
@@ -1,3 +1,19 @@
|
|||||||
|
// 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/>.
|
||||||
|
|
||||||
use runtime_io::{with_externalities, Blake2Hasher};
|
use runtime_io::{with_externalities, Blake2Hasher};
|
||||||
use srml_support::{StorageValue, StorageMap, StorageDoubleMap};
|
use srml_support::{StorageValue, StorageMap, StorageDoubleMap};
|
||||||
use srml_support::storage::unhashed;
|
use srml_support::storage::unhashed;
|
||||||
|
|||||||
@@ -75,14 +75,14 @@ mod system {
|
|||||||
pub enum RawOrigin<AccountId> {
|
pub enum RawOrigin<AccountId> {
|
||||||
Root,
|
Root,
|
||||||
Signed(AccountId),
|
Signed(AccountId),
|
||||||
Inherent,
|
None,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<AccountId> From<Option<AccountId>> for RawOrigin<AccountId> {
|
impl<AccountId> From<Option<AccountId>> for RawOrigin<AccountId> {
|
||||||
fn from(s: Option<AccountId>) -> RawOrigin<AccountId> {
|
fn from(s: Option<AccountId>) -> RawOrigin<AccountId> {
|
||||||
match s {
|
match s {
|
||||||
Some(who) => RawOrigin::Signed(who),
|
Some(who) => RawOrigin::Signed(who),
|
||||||
None => RawOrigin::Inherent,
|
None => RawOrigin::None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -233,15 +233,17 @@ pub enum RawOrigin<AccountId> {
|
|||||||
Root,
|
Root,
|
||||||
/// It is signed by some public key and we provide the `AccountId`.
|
/// It is signed by some public key and we provide the `AccountId`.
|
||||||
Signed(AccountId),
|
Signed(AccountId),
|
||||||
/// It is signed by nobody but included and agreed upon by the validators anyway: it's "inherently" true.
|
/// It is signed by nobody, can be either:
|
||||||
Inherent,
|
/// * included and agreed upon by the validators anyway,
|
||||||
|
/// * or unsigned transaction validated by a module.
|
||||||
|
None,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<AccountId> From<Option<AccountId>> for RawOrigin<AccountId> {
|
impl<AccountId> From<Option<AccountId>> for RawOrigin<AccountId> {
|
||||||
fn from(s: Option<AccountId>) -> RawOrigin<AccountId> {
|
fn from(s: Option<AccountId>) -> RawOrigin<AccountId> {
|
||||||
match s {
|
match s {
|
||||||
Some(who) => RawOrigin::Signed(who),
|
Some(who) => RawOrigin::Signed(who),
|
||||||
None => RawOrigin::Inherent,
|
None => RawOrigin::None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -363,12 +365,12 @@ pub fn ensure_root<OuterOrigin, AccountId>(o: OuterOrigin) -> Result<(), &'stati
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Ensure that the origin `o` represents an unsigned extrinsic. Returns `Ok` or an `Err` otherwise.
|
/// Ensure that the origin `o` represents an unsigned extrinsic. Returns `Ok` or an `Err` otherwise.
|
||||||
pub fn ensure_inherent<OuterOrigin, AccountId>(o: OuterOrigin) -> Result<(), &'static str>
|
pub fn ensure_none<OuterOrigin, AccountId>(o: OuterOrigin) -> Result<(), &'static str>
|
||||||
where OuterOrigin: Into<Option<RawOrigin<AccountId>>>
|
where OuterOrigin: Into<Option<RawOrigin<AccountId>>>
|
||||||
{
|
{
|
||||||
match o.into() {
|
match o.into() {
|
||||||
Some(RawOrigin::Inherent) => Ok(()),
|
Some(RawOrigin::None) => Ok(()),
|
||||||
_ => Err("bad origin: expected to be an inherent origin"),
|
_ => Err("bad origin: expected to be no origin"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -95,7 +95,7 @@ use inherents::ProvideInherentData;
|
|||||||
use srml_support::{StorageValue, Parameter, decl_storage, decl_module};
|
use srml_support::{StorageValue, Parameter, decl_storage, decl_module};
|
||||||
use srml_support::for_each_tuple;
|
use srml_support::for_each_tuple;
|
||||||
use runtime_primitives::traits::{As, SimpleArithmetic, Zero};
|
use runtime_primitives::traits::{As, SimpleArithmetic, Zero};
|
||||||
use system::ensure_inherent;
|
use system::ensure_none;
|
||||||
use rstd::{result, ops::{Mul, Div}, cmp};
|
use rstd::{result, ops::{Mul, Div}, cmp};
|
||||||
use inherents::{RuntimeString, InherentIdentifier, ProvideInherent, IsFatalError, InherentData};
|
use inherents::{RuntimeString, InherentIdentifier, ProvideInherent, IsFatalError, InherentData};
|
||||||
|
|
||||||
@@ -221,7 +221,7 @@ decl_module! {
|
|||||||
///
|
///
|
||||||
/// The dispatch origin for this call must be `Inherent`.
|
/// The dispatch origin for this call must be `Inherent`.
|
||||||
fn set(origin, #[compact] now: T::Moment) {
|
fn set(origin, #[compact] now: T::Moment) {
|
||||||
ensure_inherent(origin)?;
|
ensure_none(origin)?;
|
||||||
assert!(!<Self as Store>::DidUpdate::exists(), "Timestamp must be updated only once in the block");
|
assert!(!<Self as Store>::DidUpdate::exists(), "Timestamp must be updated only once in the block");
|
||||||
assert!(
|
assert!(
|
||||||
Self::now().is_zero() || now >= Self::now() + <MinimumPeriod<T>>::get(),
|
Self::now().is_zero() || now >= Self::now() + <MinimumPeriod<T>>::get(),
|
||||||
@@ -369,7 +369,7 @@ mod tests {
|
|||||||
|
|
||||||
with_externalities(&mut TestExternalities::new(t), || {
|
with_externalities(&mut TestExternalities::new(t), || {
|
||||||
Timestamp::set_timestamp(42);
|
Timestamp::set_timestamp(42);
|
||||||
assert_ok!(Timestamp::dispatch(Call::set(69), Origin::INHERENT));
|
assert_ok!(Timestamp::dispatch(Call::set(69), Origin::NONE));
|
||||||
assert_eq!(Timestamp::now(), 69);
|
assert_eq!(Timestamp::now(), 69);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -384,8 +384,8 @@ mod tests {
|
|||||||
|
|
||||||
with_externalities(&mut TestExternalities::new(t), || {
|
with_externalities(&mut TestExternalities::new(t), || {
|
||||||
Timestamp::set_timestamp(42);
|
Timestamp::set_timestamp(42);
|
||||||
assert_ok!(Timestamp::dispatch(Call::set(69), Origin::INHERENT));
|
assert_ok!(Timestamp::dispatch(Call::set(69), Origin::NONE));
|
||||||
let _ = Timestamp::dispatch(Call::set(70), Origin::INHERENT);
|
let _ = Timestamp::dispatch(Call::set(70), Origin::NONE);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -399,7 +399,7 @@ mod tests {
|
|||||||
|
|
||||||
with_externalities(&mut TestExternalities::new(t), || {
|
with_externalities(&mut TestExternalities::new(t), || {
|
||||||
Timestamp::set_timestamp(42);
|
Timestamp::set_timestamp(42);
|
||||||
let _ = Timestamp::dispatch(Call::set(46), Origin::INHERENT);
|
let _ = Timestamp::dispatch(Call::set(46), Origin::NONE);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user