mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-13 05:51:02 +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:
@@ -59,8 +59,17 @@
|
||||
//! # pub type Balances = u64;
|
||||
//! # pub type AllModules = u64;
|
||||
//! # 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.
|
||||
//! 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)]
|
||||
@@ -70,7 +79,8 @@ use rstd::marker::PhantomData;
|
||||
use rstd::result;
|
||||
use primitives::traits::{
|
||||
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 parity_codec::{Codec, Encode};
|
||||
@@ -101,8 +111,8 @@ pub trait ExecuteBlock<Block: BlockT> {
|
||||
fn execute_block(block: Block);
|
||||
}
|
||||
|
||||
pub struct Executive<System, Block, Context, Payment, AllModules>(
|
||||
PhantomData<(System, Block, Context, Payment, AllModules)>
|
||||
pub struct Executive<System, Block, Context, Payment, UnsignedValidator, AllModules>(
|
||||
PhantomData<(System, Block, Context, Payment, UnsignedValidator, AllModules)>
|
||||
);
|
||||
|
||||
impl<
|
||||
@@ -110,15 +120,18 @@ impl<
|
||||
Block: traits::Block<Header=System::Header, Hash=System::Hash>,
|
||||
Context: Default,
|
||||
Payment: MakePayment<System::AccountId>,
|
||||
UnsignedValidator,
|
||||
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 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 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) {
|
||||
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>,
|
||||
Context: Default,
|
||||
Payment: MakePayment<System::AccountId>,
|
||||
UnsignedValidator,
|
||||
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 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 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.
|
||||
pub fn initialize_block(header: &System::Header) {
|
||||
@@ -290,7 +306,7 @@ impl<
|
||||
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.
|
||||
///
|
||||
/// Changes made to storage should be discarded.
|
||||
@@ -313,38 +329,37 @@ impl<
|
||||
Err(_) => return TransactionValidity::Invalid(UNKNOWN_ERROR),
|
||||
};
|
||||
|
||||
if let (Some(sender), Some(index)) = (xt.sender(), xt.index()) {
|
||||
// pay any fees
|
||||
if Payment::make_payment(sender, encoded_len).is_err() {
|
||||
return TransactionValidity::Invalid(ApplyError::CantPay as i8)
|
||||
}
|
||||
match (xt.sender(), xt.index()) {
|
||||
(Some(sender), Some(index)) => {
|
||||
// pay any fees
|
||||
if Payment::make_payment(sender, encoded_len).is_err() {
|
||||
return TransactionValidity::Invalid(ApplyError::CantPay as i8)
|
||||
}
|
||||
|
||||
// check index
|
||||
let expected_index = <system::Module<System>>::account_nonce(sender);
|
||||
if index < &expected_index {
|
||||
return TransactionValidity::Invalid(ApplyError::Stale as i8)
|
||||
}
|
||||
// check index
|
||||
let expected_index = <system::Module<System>>::account_nonce(sender);
|
||||
if index < &expected_index {
|
||||
return TransactionValidity::Invalid(ApplyError::Stale as i8)
|
||||
}
|
||||
|
||||
let index = *index;
|
||||
let provides = vec![(sender, index).encode()];
|
||||
let requires = if expected_index < index {
|
||||
vec![(sender, index - One::one()).encode()]
|
||||
} else {
|
||||
vec![]
|
||||
};
|
||||
let index = *index;
|
||||
let provides = vec![(sender, index).encode()];
|
||||
let requires = if expected_index < index {
|
||||
vec![(sender, index - One::one()).encode()]
|
||||
} else {
|
||||
vec![]
|
||||
};
|
||||
|
||||
TransactionValidity::Valid {
|
||||
priority: encoded_len as TransactionPriority,
|
||||
requires,
|
||||
provides,
|
||||
longevity: TransactionLongevity::max_value(),
|
||||
}
|
||||
} else {
|
||||
return TransactionValidity::Invalid(if xt.sender().is_none() {
|
||||
MISSING_SENDER
|
||||
} else {
|
||||
INVALID_INDEX
|
||||
})
|
||||
TransactionValidity::Valid {
|
||||
priority: encoded_len as TransactionPriority,
|
||||
requires,
|
||||
provides,
|
||||
longevity: TransactionLongevity::max_value(),
|
||||
}
|
||||
},
|
||||
(None, None) => UnsignedValidator::validate_unsigned(&xt.deconstruct().0),
|
||||
(Some(_), None) => TransactionValidity::Invalid(INVALID_INDEX),
|
||||
(None, Some(_)) => TransactionValidity::Invalid(MISSING_SENDER),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -404,8 +419,24 @@ mod tests {
|
||||
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 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]
|
||||
fn balance_transfer_dispatch_works() {
|
||||
@@ -527,4 +558,21 @@ mod tests {
|
||||
run_test(false);
|
||||
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));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user