Refactor SignedExtension (#5540)

* Refactor SignedExtension

* Move DispatchInfo Associated type to Dispatchable
* Bound Call: Dispatchable
* Pass PostDispatchInfo to post_dispatch
* Pass DispatchInfo by reference to avoid clones

* Whitespace fix

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

* Style changes from code review

Co-Authored-By: Kian Paimani <5588131+kianenigma@users.noreply.github.com>

* Only decalre in test mod to remove warning

* Deduplicate Call definition

* Bound frame_system::trait::Call by Dispatchable

* Introduce DispatchInfoOf type alias

* Whitespace fix from review

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

Co-authored-by: Tomasz Drwięga <tomusdrw@users.noreply.github.com>
Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com>
Co-authored-by: Bastian Köcher <bkchr@users.noreply.github.com>
This commit is contained in:
Alexander Theißen
2020-04-08 11:12:09 +02:00
committed by GitHub
parent f8c8355ac7
commit 30ae26074c
18 changed files with 235 additions and 167 deletions
+65 -49
View File
@@ -109,6 +109,7 @@ use sp_runtime::{
self, CheckEqual, AtLeast32Bit, Zero, SignedExtension, Lookup, LookupError,
SimpleBitOps, Hash, Member, MaybeDisplay, BadOrigin, SaturatedConversion,
MaybeSerialize, MaybeSerializeDeserialize, MaybeMallocSizeOf, StaticLookup, One, Bounded,
Dispatchable, DispatchInfoOf, PostDispatchInfoOf,
},
};
@@ -146,7 +147,7 @@ pub trait Trait: 'static + Eq + Clone {
+ Clone;
/// The aggregated `Call` type.
type Call: Debug;
type Call: Dispatchable + Debug;
/// Account index (aka nonce) type. This stores the number of previous transactions associated
/// with a sender account.
@@ -1167,7 +1168,9 @@ pub fn split_inner<T, R, S>(option: Option<T>, splitter: impl FnOnce(T) -> (R, S
#[derive(Encode, Decode, Clone, Eq, PartialEq)]
pub struct CheckWeight<T: Trait + Send + Sync>(PhantomData<T>);
impl<T: Trait + Send + Sync> CheckWeight<T> {
impl<T: Trait + Send + Sync> CheckWeight<T> where
T::Call: Dispatchable<Info=DispatchInfo>
{
/// 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.
@@ -1183,7 +1186,7 @@ impl<T: Trait + Send + Sync> CheckWeight<T> {
///
/// Upon successes, it returns the new block weight as a `Result`.
fn check_weight(
info: <Self as SignedExtension>::DispatchInfo,
info: &DispatchInfoOf<T::Call>,
) -> Result<Weight, TransactionValidityError> {
let current_weight = Module::<T>::all_extrinsics_weight();
let maximum_weight = T::MaximumBlockWeight::get();
@@ -1201,7 +1204,7 @@ impl<T: Trait + Send + Sync> CheckWeight<T> {
///
/// Upon successes, it returns the new block length as a `Result`.
fn check_block_length(
info: <Self as SignedExtension>::DispatchInfo,
info: &DispatchInfoOf<T::Call>,
len: usize,
) -> Result<u32, TransactionValidityError> {
let current_len = Module::<T>::all_extrinsics_len();
@@ -1217,7 +1220,7 @@ impl<T: Trait + Send + Sync> CheckWeight<T> {
}
/// get the priority of an extrinsic denoted by `info`.
fn get_priority(info: <Self as SignedExtension>::DispatchInfo) -> TransactionPriority {
fn get_priority(info: &DispatchInfoOf<T::Call>) -> TransactionPriority {
match info.class {
DispatchClass::Normal => info.weight.into(),
DispatchClass::Operational => Bounded::max_value(),
@@ -1235,7 +1238,7 @@ impl<T: Trait + Send + Sync> CheckWeight<T> {
///
/// It checks and notes the new weight and length.
fn do_pre_dispatch(
info: <Self as SignedExtension>::DispatchInfo,
info: &DispatchInfoOf<T::Call>,
len: usize,
) -> Result<(), TransactionValidityError> {
let next_len = Self::check_block_length(info, len)?;
@@ -1249,7 +1252,7 @@ impl<T: Trait + Send + Sync> CheckWeight<T> {
///
/// It only checks that the block weight and length limit will not exceed.
fn do_validate(
info: <Self as SignedExtension>::DispatchInfo,
info: &DispatchInfoOf<T::Call>,
len: usize,
) -> TransactionValidity {
// ignore the next weight and length. If they return `Ok`, then it is below the limit.
@@ -1260,11 +1263,12 @@ impl<T: Trait + Send + Sync> CheckWeight<T> {
}
}
impl<T: Trait + Send + Sync> SignedExtension for CheckWeight<T> {
impl<T: Trait + Send + Sync> SignedExtension for CheckWeight<T> where
T::Call: Dispatchable<Info=DispatchInfo>
{
type AccountId = T::AccountId;
type Call = T::Call;
type AdditionalSigned = ();
type DispatchInfo = DispatchInfo;
type Pre = ();
const IDENTIFIER: &'static str = "CheckWeight";
@@ -1274,7 +1278,7 @@ impl<T: Trait + Send + Sync> SignedExtension for CheckWeight<T> {
self,
_who: &Self::AccountId,
_call: &Self::Call,
info: Self::DispatchInfo,
info: &DispatchInfoOf<Self::Call>,
len: usize,
) -> Result<(), TransactionValidityError> {
if info.class == DispatchClass::Mandatory {
@@ -1287,7 +1291,7 @@ impl<T: Trait + Send + Sync> SignedExtension for CheckWeight<T> {
&self,
_who: &Self::AccountId,
_call: &Self::Call,
info: Self::DispatchInfo,
info: &DispatchInfoOf<Self::Call>,
len: usize,
) -> TransactionValidity {
if info.class == DispatchClass::Mandatory {
@@ -1298,7 +1302,7 @@ impl<T: Trait + Send + Sync> SignedExtension for CheckWeight<T> {
fn pre_dispatch_unsigned(
_call: &Self::Call,
info: Self::DispatchInfo,
info: &DispatchInfoOf<Self::Call>,
len: usize,
) -> Result<(), TransactionValidityError> {
Self::do_pre_dispatch(info, len)
@@ -1306,7 +1310,7 @@ impl<T: Trait + Send + Sync> SignedExtension for CheckWeight<T> {
fn validate_unsigned(
_call: &Self::Call,
info: Self::DispatchInfo,
info: &DispatchInfoOf<Self::Call>,
len: usize,
) -> TransactionValidity {
Self::do_validate(info, len)
@@ -1314,7 +1318,8 @@ impl<T: Trait + Send + Sync> SignedExtension for CheckWeight<T> {
fn post_dispatch(
_pre: Self::Pre,
info: Self::DispatchInfo,
info: &DispatchInfoOf<Self::Call>,
_post_info: &PostDispatchInfoOf<Self::Call>,
_len: usize,
result: &DispatchResult,
) -> Result<(), TransactionValidityError> {
@@ -1363,11 +1368,12 @@ impl<T: Trait> Debug for CheckNonce<T> {
}
}
impl<T: Trait> SignedExtension for CheckNonce<T> {
impl<T: Trait> SignedExtension for CheckNonce<T> where
T::Call: Dispatchable<Info=DispatchInfo>
{
type AccountId = T::AccountId;
type Call = T::Call;
type AdditionalSigned = ();
type DispatchInfo = DispatchInfo;
type Pre = ();
const IDENTIFIER: &'static str = "CheckNonce";
@@ -1377,7 +1383,7 @@ impl<T: Trait> SignedExtension for CheckNonce<T> {
self,
who: &Self::AccountId,
_call: &Self::Call,
_info: Self::DispatchInfo,
_info: &DispatchInfoOf<Self::Call>,
_len: usize,
) -> Result<(), TransactionValidityError> {
let mut account = Account::<T>::get(who);
@@ -1399,7 +1405,7 @@ impl<T: Trait> SignedExtension for CheckNonce<T> {
&self,
who: &Self::AccountId,
_call: &Self::Call,
info: Self::DispatchInfo,
info: &DispatchInfoOf<Self::Call>,
_len: usize,
) -> TransactionValidity {
// check index
@@ -1458,7 +1464,6 @@ impl<T: Trait + Send + Sync> SignedExtension for CheckEra<T> {
type AccountId = T::AccountId;
type Call = T::Call;
type AdditionalSigned = T::Hash;
type DispatchInfo = DispatchInfo;
type Pre = ();
const IDENTIFIER: &'static str = "CheckEra";
@@ -1466,7 +1471,7 @@ impl<T: Trait + Send + Sync> SignedExtension for CheckEra<T> {
&self,
_who: &Self::AccountId,
_call: &Self::Call,
_info: Self::DispatchInfo,
_info: &DispatchInfoOf<Self::Call>,
_len: usize,
) -> TransactionValidity {
let current_u64 = <Module<T>>::block_number().saturated_into::<u64>();
@@ -1515,7 +1520,6 @@ impl<T: Trait + Send + Sync> SignedExtension for CheckGenesis<T> {
type AccountId = T::AccountId;
type Call = <T as Trait>::Call;
type AdditionalSigned = T::Hash;
type DispatchInfo = DispatchInfo;
type Pre = ();
const IDENTIFIER: &'static str = "CheckGenesis";
@@ -1551,7 +1555,6 @@ impl<T: Trait + Send + Sync> SignedExtension for CheckVersion<T> {
type AccountId = T::AccountId;
type Call = <T as Trait>::Call;
type AdditionalSigned = u32;
type DispatchInfo = DispatchInfo;
type Pre = ();
const IDENTIFIER: &'static str = "CheckVersion";
@@ -1615,9 +1618,22 @@ mod tests {
fn on_killed_account(who: &u64) { KILLED.with(|r| r.borrow_mut().push(*who)) }
}
#[derive(Debug)]
pub struct Call {}
impl Dispatchable for Call {
type Origin = ();
type Trait = ();
type Info = DispatchInfo;
type PostInfo = ();
fn dispatch(self, _origin: Self::Origin)
-> sp_runtime::DispatchResultWithInfo<Self::PostInfo> {
panic!("Do not use dummy implementation for dispatch.");
}
}
impl Trait for Test {
type Origin = Origin;
type Call = ();
type Call = Call;
type Index = u64;
type BlockNumber = u64;
type Hash = H256;
@@ -1650,7 +1666,7 @@ mod tests {
type System = Module<Test>;
const CALL: &<Test as Trait>::Call = &();
const CALL: &<Test as Trait>::Call = &Call {};
fn new_test_ext() -> sp_io::TestExternalities {
GenesisConfig::default().build_storage::<Test>().unwrap().into()
@@ -1851,14 +1867,14 @@ mod tests {
let info = DispatchInfo::default();
let len = 0_usize;
// stale
assert!(CheckNonce::<Test>(0).validate(&1, CALL, info, len).is_err());
assert!(CheckNonce::<Test>(0).pre_dispatch(&1, CALL, info, len).is_err());
assert!(CheckNonce::<Test>(0).validate(&1, CALL, &info, len).is_err());
assert!(CheckNonce::<Test>(0).pre_dispatch(&1, CALL, &info, len).is_err());
// correct
assert!(CheckNonce::<Test>(1).validate(&1, CALL, info, len).is_ok());
assert!(CheckNonce::<Test>(1).pre_dispatch(&1, CALL, info, len).is_ok());
assert!(CheckNonce::<Test>(1).validate(&1, CALL, &info, len).is_ok());
assert!(CheckNonce::<Test>(1).pre_dispatch(&1, CALL, &info, len).is_ok());
// future
assert!(CheckNonce::<Test>(5).validate(&1, CALL, info, len).is_ok());
assert!(CheckNonce::<Test>(5).pre_dispatch(&1, CALL, info, len).is_err());
assert!(CheckNonce::<Test>(5).validate(&1, CALL, &info, len).is_ok());
assert!(CheckNonce::<Test>(5).pre_dispatch(&1, CALL, &info, len).is_err());
})
}
@@ -1883,9 +1899,9 @@ mod tests {
if f { assert!(r.is_err()) } else { assert!(r.is_ok()) }
};
reset_check_weight(small, false, 0);
reset_check_weight(medium, false, 0);
reset_check_weight(big, true, 1);
reset_check_weight(&small, false, 0);
reset_check_weight(&medium, false, 0);
reset_check_weight(&big, true, 1);
})
}
@@ -1896,7 +1912,7 @@ mod tests {
let len = 0_usize;
assert_eq!(System::all_extrinsics_weight(), 0);
let r = CheckWeight::<Test>(PhantomData).pre_dispatch(&1, CALL, free, len);
let r = CheckWeight::<Test>(PhantomData).pre_dispatch(&1, CALL, &free, len);
assert!(r.is_ok());
assert_eq!(System::all_extrinsics_weight(), 0);
})
@@ -1910,7 +1926,7 @@ mod tests {
let normal_limit = normal_weight_limit();
assert_eq!(System::all_extrinsics_weight(), 0);
let r = CheckWeight::<Test>(PhantomData).pre_dispatch(&1, CALL, max, len);
let r = CheckWeight::<Test>(PhantomData).pre_dispatch(&1, CALL, &max, len);
assert!(r.is_ok());
assert_eq!(System::all_extrinsics_weight(), normal_limit);
})
@@ -1927,15 +1943,15 @@ mod tests {
// given almost full block
AllExtrinsicsWeight::put(normal_limit);
// will not fit.
assert!(CheckWeight::<Test>(PhantomData).pre_dispatch(&1, CALL, normal, len).is_err());
assert!(CheckWeight::<Test>(PhantomData).pre_dispatch(&1, CALL, &normal, len).is_err());
// will fit.
assert!(CheckWeight::<Test>(PhantomData).pre_dispatch(&1, CALL, op, len).is_ok());
assert!(CheckWeight::<Test>(PhantomData).pre_dispatch(&1, CALL, &op, len).is_ok());
// likewise for length limit.
let len = 100_usize;
AllExtrinsicsLen::put(normal_length_limit());
assert!(CheckWeight::<Test>(PhantomData).pre_dispatch(&1, CALL, normal, len).is_err());
assert!(CheckWeight::<Test>(PhantomData).pre_dispatch(&1, CALL, op, len).is_ok());
assert!(CheckWeight::<Test>(PhantomData).pre_dispatch(&1, CALL, &normal, len).is_err());
assert!(CheckWeight::<Test>(PhantomData).pre_dispatch(&1, CALL, &op, len).is_ok());
})
}
@@ -1947,13 +1963,13 @@ mod tests {
let len = 0_usize;
let priority = CheckWeight::<Test>(PhantomData)
.validate(&1, CALL, normal, len)
.validate(&1, CALL, &normal, len)
.unwrap()
.priority;
assert_eq!(priority, 100);
let priority = CheckWeight::<Test>(PhantomData)
.validate(&1, CALL, op, len)
.validate(&1, CALL, &op, len)
.unwrap()
.priority;
assert_eq!(priority, u64::max_value());
@@ -1971,16 +1987,16 @@ mod tests {
if f { assert!(r.is_err()) } else { assert!(r.is_ok()) }
};
reset_check_weight(normal, normal_limit - 1, false);
reset_check_weight(normal, normal_limit, false);
reset_check_weight(normal, normal_limit + 1, true);
reset_check_weight(&normal, normal_limit - 1, false);
reset_check_weight(&normal, normal_limit, false);
reset_check_weight(&normal, normal_limit + 1, true);
// Operational ones don't have this limit.
let op = DispatchInfo { weight: 0, class: DispatchClass::Operational, pays_fee: true };
reset_check_weight(op, normal_limit, false);
reset_check_weight(op, normal_limit + 100, false);
reset_check_weight(op, 1024, false);
reset_check_weight(op, 1025, true);
reset_check_weight(&op, normal_limit, false);
reset_check_weight(&op, normal_limit + 100, false);
reset_check_weight(&op, 1024, false);
reset_check_weight(&op, 1025, true);
})
}
@@ -2012,7 +2028,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);
})
}