Newer
Older
}
/// Get the basic externalities for this module, useful for tests.
#[cfg(any(feature = "std", test))]
pub fn externalities() -> TestExternalities {
TestExternalities::new(sp_core::storage::Storage {
top: map![
<BlockHash<T>>::hashed_key_for(T::BlockNumber::zero()) => [69u8; 32].encode(),
<Number<T>>::hashed_key().to_vec() => T::BlockNumber::one().encode(),
<ParentHash<T>>::hashed_key().to_vec() => [69u8; 32].encode()
],
}
/// Set the block number to something in particular. Can be used as an alternative to
/// `initialize` for tests that don't need to bother with the other environment entries.
#[cfg(any(feature = "std", feature = "runtime-benchmarks", test))]
pub fn set_block_number(n: T::BlockNumber) {
<Number<T>>::put(n);
}
/// Sets the index of extrinsic that is currently executing.
Svyatoslav Nikolsky
committed
#[cfg(any(feature = "std", test))]
pub fn set_extrinsic_index(extrinsic_index: u32) {
storage::unhashed::put(well_known_keys::EXTRINSIC_INDEX, &extrinsic_index)
Svyatoslav Nikolsky
committed
}
/// Set the parent hash number to something in particular. Can be used as an alternative to
/// `initialize` for tests that don't need to bother with the other environment entries.
#[cfg(any(feature = "std", test))]
pub fn set_parent_hash(n: T::Hash) {
<ParentHash<T>>::put(n);
}
/// Set the current block weight. This should only be used in some integration tests.
#[cfg(any(feature = "std", test))]
pub fn set_block_limits(weight: Weight, len: usize) {
AllExtrinsicsWeight::put(weight);
AllExtrinsicsLen::put(len as u32);
}
/// Return the chain's current runtime version.
pub fn runtime_version() -> RuntimeVersion { T::Version::get() }
/// Retrieve the account transaction counter from storage.
pub fn account_nonce(who: impl EncodeLike<T::AccountId>) -> T::Index {
pub fn inc_account_nonce(who: impl EncodeLike<T::AccountId>) {
Account::<T>::mutate(who, |a| a.nonce += T::Index::one());
/// Note what the extrinsic data of the current extrinsic index is. If this
/// is called, then ensure `derive_extrinsics` is also called before
/// block-building is completed.
/// NOTE: This function is called only when the block is being constructed locally.
/// `execute_block` doesn't note any extrinsics.
pub fn note_extrinsic(encoded_xt: Vec<u8>) {
ExtrinsicData::insert(Self::extrinsic_index().unwrap_or_default(), encoded_xt);
}
/// To be called immediately after an extrinsic has been applied.
Sergey Pepyakin
committed
pub fn note_applied_extrinsic(r: &DispatchOutcome, _encoded_len: u32, info: DispatchInfo) {
Self::deposit_event(
match r {
Err(err) => {
sp_runtime::print(err);
Svyatoslav Nikolsky
committed
let next_extrinsic_index = Self::extrinsic_index().unwrap_or_default() + 1u32;
storage::unhashed::put(well_known_keys::EXTRINSIC_INDEX, &next_extrinsic_index);
ExecutionPhase::put(Phase::ApplyExtrinsic(next_extrinsic_index));
}
/// To be called immediately after `note_applied_extrinsic` of the last extrinsic of the block
/// has been called.
pub fn note_finished_extrinsics() {
let extrinsic_index: u32 = storage::unhashed::take(well_known_keys::EXTRINSIC_INDEX)
.unwrap_or_default();
ExtrinsicCount::put(extrinsic_index);
ExecutionPhase::put(Phase::Finalization);
}
/// To be called immediately after finishing the initialization of the block
/// (e.g., called `on_initialize` for all modules).
pub fn note_finished_initialize() {
ExecutionPhase::put(Phase::ApplyExtrinsic(0))
/// Remove all extrinsic data and save the extrinsics trie root.
pub fn derive_extrinsics() {
let extrinsics = (0..ExtrinsicCount::get().unwrap_or_default())
.map(ExtrinsicData::take).collect();
let xts_root = extrinsics_data_root::<T::Hashing>(extrinsics);
<ExtrinsicsRoot<T>>::put(xts_root);
}
/// An account is being created.
pub fn on_created_account(who: T::AccountId) {
T::OnNewAccount::on_new_account(&who);
Self::deposit_event(RawEvent::NewAccount(who));
}
/// Do anything that needs to be done after an account has been killed.
fn on_killed_account(who: T::AccountId) {
T::OnKilledAccount::on_killed_account(&who);
Self::deposit_event(RawEvent::KilledAccount(who));
}
/// Remove an account from storage. This should only be done when its refs are zero or you'll
/// get storage leaks in other modules. Nonetheless we assume that the calling logic knows best.
///
/// This is a no-op if the account doesn't already exist. If it does then it will ensure
/// cleanups (those in `on_killed_account`) take place.
fn kill_account(who: &T::AccountId) {
if Account::<T>::contains_key(who) {
let account = Account::<T>::take(who);
if account.refcount > 0 {
debug::debug!(
target: "system",
"WARNING: Referenced account deleted. This is probably a bug."
);
}
Module::<T>::on_killed_account(who.clone());
}
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
/// Determine whether or not it is possible to update the code.
///
/// This function has no side effects and is idempotent, but is fairly
/// heavy. It is automatically called by `set_code`; in most cases,
/// a direct call to `set_code` is preferable. It is useful to call
/// `can_set_code` when it is desirable to perform the appropriate
/// runtime checks without actually changing the code yet.
pub fn can_set_code(origin: T::Origin, code: &[u8]) -> Result<(), sp_runtime::DispatchError> {
ensure_root(origin)?;
let current_version = T::Version::get();
let new_version = sp_io::misc::runtime_version(&code)
.and_then(|v| RuntimeVersion::decode(&mut &v[..]).ok())
.ok_or_else(|| Error::<T>::FailedToExtractRuntimeVersion)?;
if new_version.spec_name != current_version.spec_name {
Err(Error::<T>::InvalidSpecName)?
}
if new_version.spec_version <= current_version.spec_version {
Err(Error::<T>::SpecVersionNeedsToIncrease)?
}
Ok(())
}
}
/// Event handler which calls on_created_account when it happens.
pub struct CallOnCreatedAccount<T>(PhantomData<T>);
impl<T: Trait> Happened<T::AccountId> for CallOnCreatedAccount<T> {
fn happened(who: &T::AccountId) {
Module::<T>::on_created_account(who.clone());
}
}
/// Event handler which calls kill_account when it happens.
pub struct CallKillAccount<T>(PhantomData<T>);
impl<T: Trait> Happened<T::AccountId> for CallKillAccount<T> {
fn happened(who: &T::AccountId) {
}
}
// Implement StoredMap for a simple single-item, kill-account-on-remove system. This works fine for
// storing a single item which is required to not be empty/default for the account to exist.
// Anything more complex will need more sophisticated logic.
impl<T: Trait> StoredMap<T::AccountId, T::AccountData> for Module<T> {
fn get(k: &T::AccountId) -> T::AccountData {
}
fn is_explicit(k: &T::AccountId) -> bool {
Account::<T>::contains_key(k)
}
if !existed {
Self::on_created_account(k.clone());
}
}
fn remove(k: &T::AccountId) {
}
fn mutate<R>(k: &T::AccountId, f: impl FnOnce(&mut T::AccountData) -> R) -> R {
let existed = Account::<T>::contains_key(k);
if !existed {
Self::on_created_account(k.clone());
}
r
}
fn mutate_exists<R>(k: &T::AccountId, f: impl FnOnce(&mut Option<T::AccountData>) -> R) -> R {
Self::try_mutate_exists(k, |x| -> Result<R, Infallible> { Ok(f(x)) }).expect("Infallible; qed")
}
fn try_mutate_exists<R, E>(k: &T::AccountId, f: impl FnOnce(&mut Option<T::AccountData>) -> Result<R, E>) -> Result<R, E> {
Account::<T>::try_mutate_exists(k, |maybe_value| {
let existed = maybe_value.is_some();
let (maybe_prefix, mut maybe_data) = split_inner(
maybe_value.take(),
|account| ((account.nonce, account.refcount), account.data)
);
f(&mut maybe_data).map(|result| {
*maybe_value = maybe_data.map(|data| {
let (nonce, refcount) = maybe_prefix.unwrap_or_default();
AccountInfo { nonce, refcount, data }
});
(existed, maybe_value.is_some(), result)
})
}).map(|(existed, exists, v)| {
if !existed && exists {
Self::on_created_account(k.clone());
} else if existed && !exists {
Self::on_killed_account(k.clone());
}
v
})
}
/// Split an `option` into two constituent options, as defined by a `splitter` function.
pub fn split_inner<T, R, S>(option: Option<T>, splitter: impl FnOnce(T) -> (R, S))
-> (Option<R>, Option<S>)
{
match option {
Some(inner) => {
let (r, s) = splitter(inner);
(Some(r), Some(s))
}
None => (None, None),
/// resource limit check.
#[derive(Encode, Decode, Clone, Eq, PartialEq)]
pub struct CheckWeight<T: Trait + Send + Sync>(PhantomData<T>);
impl<T: Trait + Send + Sync> CheckWeight<T> where
T::Call: Dispatchable<Info=DispatchInfo, PostInfo=PostDispatchInfo>
/// Get the quota ratio of each dispatch class type. This indicates that all operational and mandatory
/// dispatches can use the full capacity of any resource, while user-triggered ones can consume
/// a portion.
fn get_dispatch_limit_ratio(class: DispatchClass) -> Perbill {
Module::<T>::get_dispatch_limit_ratio(class)
/// 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(
) -> 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;
if info.class == DispatchClass::Mandatory {
// If we have a dispatch that must be included in the block, it ignores all the limits.
let extrinsic_weight = info.weight.saturating_add(T::ExtrinsicBaseWeight::get());
let next_weight = current_weight.saturating_add(extrinsic_weight);
} else {
let extrinsic_weight = info.weight.checked_add(T::ExtrinsicBaseWeight::get())
.ok_or(InvalidTransaction::ExhaustsResources)?;
let next_weight = current_weight.checked_add(extrinsic_weight)
.ok_or(InvalidTransaction::ExhaustsResources)?;
if next_weight > limit {
Err(InvalidTransaction::ExhaustsResources.into())
} else {
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(
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 {
Err(InvalidTransaction::ExhaustsResources.into())
} else {
Ok(next_len)
}
}
/// get the priority of an extrinsic denoted by `info`.
fn get_priority(info: &DispatchInfoOf<T::Call>) -> TransactionPriority {
match info.class {
DispatchClass::Normal => info.weight.into(),
DispatchClass::Operational => Bounded::max_value(),
// Mandatory extrinsics are only for inherents; never transactions.
DispatchClass::Mandatory => Bounded::min_value(),
/// Creates new `SignedExtension` to check weight of the extrinsic.
pub fn new() -> Self {
/// Do the pre-dispatch checks. This can be applied to both signed and unsigned.
///
/// It checks and notes the new weight and length.
fn do_pre_dispatch(
len: usize,
) -> Result<(), TransactionValidityError> {
let next_len = Self::check_block_length(info, len)?;
let next_weight = Self::check_weight(info)?;
AllExtrinsicsLen::put(next_len);
AllExtrinsicsWeight::put(next_weight);
Ok(())
}
/// Do the validate checks. This can be applied to both signed and unsigned.
///
/// It only checks that the block weight and length limit will not exceed.
fn do_validate(
len: usize,
) -> TransactionValidity {
// ignore the next weight and length. If they return `Ok`, then it is below the limit.
let _ = Self::check_block_length(info, len)?;
let _ = Self::check_weight(info)?;
Ok(ValidTransaction { priority: Self::get_priority(info), ..Default::default() })
}
impl<T: Trait + Send + Sync> SignedExtension for CheckWeight<T> where
T::Call: Dispatchable<Info=DispatchInfo, PostInfo=PostDispatchInfo>
const IDENTIFIER: &'static str = "CheckWeight";
fn additional_signed(&self) -> sp_std::result::Result<(), TransactionValidityError> { Ok(()) }
fn pre_dispatch(
self,
_who: &Self::AccountId,
info: &DispatchInfoOf<Self::Call>,
Sergey Pepyakin
committed
) -> Result<(), TransactionValidityError> {
if info.class == DispatchClass::Mandatory {
Err(InvalidTransaction::MandatoryDispatch)?
}
Self::do_pre_dispatch(info, len)
}
fn validate(
&self,
_who: &Self::AccountId,
info: &DispatchInfoOf<Self::Call>,
if info.class == DispatchClass::Mandatory {
Err(InvalidTransaction::MandatoryDispatch)?
}
Self::do_validate(info, len)
}
fn pre_dispatch_unsigned(
_call: &Self::Call,
info: &DispatchInfoOf<Self::Call>,
len: usize,
) -> Result<(), TransactionValidityError> {
Self::do_pre_dispatch(info, len)
}
fn validate_unsigned(
_call: &Self::Call,
info: &DispatchInfoOf<Self::Call>,
len: usize,
) -> TransactionValidity {
Self::do_validate(info, len)
fn post_dispatch(
_pre: Self::Pre,
info: &DispatchInfoOf<Self::Call>,
post_info: &PostDispatchInfoOf<Self::Call>,
_len: usize,
result: &DispatchResult,
) -> Result<(), TransactionValidityError> {
// Since mandatory dispatched do not get validated for being overweight, we are sensitive
// to them actually being useful. Block producers are thus not allowed to include mandatory
// extrinsics that result in error.
if info.class == DispatchClass::Mandatory && result.is_err() {
Err(InvalidTransaction::BadMandatory)?
}
let unspent = post_info.calc_unspent(info);
if unspent > 0 {
AllExtrinsicsWeight::mutate(|weight| {
*weight = weight.map(|w| w.saturating_sub(unspent));
})
}
impl<T: Trait + Send + Sync> Debug for CheckWeight<T> {
#[cfg(feature = "std")]
fn fmt(&self, f: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result {
write!(f, "CheckWeight")
}
#[cfg(not(feature = "std"))]
fn fmt(&self, _: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result {
}
}
/// Nonce check and increment to give replay protection for transactions.
#[derive(Encode, Decode, Clone, Eq, PartialEq)]
pub struct CheckNonce<T: Trait>(#[codec(compact)] T::Index);
impl<T: Trait> CheckNonce<T> {
/// utility constructor. Used only in client/factory code.
pub fn from(nonce: T::Index) -> Self {
Self(nonce)
}
}
impl<T: Trait> Debug for CheckNonce<T> {
#[cfg(feature = "std")]
fn fmt(&self, f: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result {
write!(f, "CheckNonce({})", self.0)
fn fmt(&self, _: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result {
impl<T: Trait> SignedExtension for CheckNonce<T> where
T::Call: Dispatchable<Info=DispatchInfo>
{
const IDENTIFIER: &'static str = "CheckNonce";
fn additional_signed(&self) -> sp_std::result::Result<(), TransactionValidityError> { Ok(()) }
fn pre_dispatch(
self,
who: &Self::AccountId,
_info: &DispatchInfoOf<Self::Call>,
Sergey Pepyakin
committed
) -> Result<(), TransactionValidityError> {
let mut account = Account::<T>::get(who);
if self.0 != account.nonce {
InvalidTransaction::Stale
} else {
InvalidTransaction::Future
}.into()
account.nonce += T::Index::one();
Account::<T>::insert(who, account);
Ok(())
}
fn validate(
&self,
who: &Self::AccountId,
info: &DispatchInfoOf<Self::Call>,
let account = Account::<T>::get(who);
if self.0 < account.nonce {
return InvalidTransaction::Stale.into()
}
let provides = vec![Encode::encode(&(who, self.0))];
vec![Encode::encode(&(who, self.0 - One::one()))]
} else {
vec![]
};
Ok(ValidTransaction {
priority: info.weight as TransactionPriority,
requires,
provides,
longevity: TransactionLongevity::max_value(),
propagate: true,
})
}
}
impl<T: Trait> IsDeadAccount<T::AccountId> for Module<T> {
fn is_dead_account(who: &T::AccountId) -> bool {
!Account::<T>::contains_key(who)
}
}
/// Check for transaction mortality.
#[derive(Encode, Decode, Clone, Eq, PartialEq)]
pub struct CheckEra<T: Trait + Send + Sync>(Era, sp_std::marker::PhantomData<T>);
impl<T: Trait + Send + Sync> CheckEra<T> {
/// utility constructor. Used only in client/factory code.
pub fn from(era: Era) -> Self {
Self(era, sp_std::marker::PhantomData)
impl<T: Trait + Send + Sync> Debug for CheckEra<T> {
#[cfg(feature = "std")]
fn fmt(&self, f: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result {
write!(f, "CheckEra({:?})", self.0)
fn fmt(&self, _: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result {
}
impl<T: Trait + Send + Sync> SignedExtension for CheckEra<T> {
type AccountId = T::AccountId;
type AdditionalSigned = T::Hash;
const IDENTIFIER: &'static str = "CheckEra";
fn validate(
&self,
_who: &Self::AccountId,
_call: &Self::Call,
_info: &DispatchInfoOf<Self::Call>,
let current_u64 = <Module<T>>::block_number().saturated_into::<u64>();
let valid_till = self.0.death(current_u64);
Ok(ValidTransaction {
longevity: valid_till.saturating_sub(current_u64),
..Default::default()
})
}
fn additional_signed(&self) -> Result<Self::AdditionalSigned, TransactionValidityError> {
let current_u64 = <Module<T>>::block_number().saturated_into::<u64>();
let n = self.0.birth(current_u64).saturated_into::<T::BlockNumber>();
if !<BlockHash<T>>::contains_key(n) {
Err(InvalidTransaction::AncientBirthBlock.into())
} else {
Ok(<Module<T>>::block_hash(n))
}
/// Nonce check and increment to give replay protection for transactions.
#[derive(Encode, Decode, Clone, Eq, PartialEq)]
pub struct CheckGenesis<T: Trait + Send + Sync>(sp_std::marker::PhantomData<T>);
impl<T: Trait + Send + Sync> Debug for CheckGenesis<T> {
#[cfg(feature = "std")]
fn fmt(&self, f: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result {
write!(f, "CheckGenesis")
}
#[cfg(not(feature = "std"))]
fn fmt(&self, _: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result {
Ok(())
}
}
impl<T: Trait + Send + Sync> CheckGenesis<T> {
/// Creates new `SignedExtension` to check genesis hash.
pub fn new() -> Self {
Self(sp_std::marker::PhantomData)
}
}
impl<T: Trait + Send + Sync> SignedExtension for CheckGenesis<T> {
type AccountId = T::AccountId;
type AdditionalSigned = T::Hash;
const IDENTIFIER: &'static str = "CheckGenesis";
fn additional_signed(&self) -> Result<Self::AdditionalSigned, TransactionValidityError> {
Ok(<Module<T>>::block_hash(T::BlockNumber::zero()))
}
}
/// Ensure the runtime version registered in the transaction is the same as at present.
#[derive(Encode, Decode, Clone, Eq, PartialEq)]
pub struct CheckVersion<T: Trait + Send + Sync>(sp_std::marker::PhantomData<T>);
impl<T: Trait + Send + Sync> Debug for CheckVersion<T> {
#[cfg(feature = "std")]
fn fmt(&self, f: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result {
write!(f, "CheckVersion")
}
#[cfg(not(feature = "std"))]
fn fmt(&self, _: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result {
Ok(())
}
}
impl<T: Trait + Send + Sync> CheckVersion<T> {
/// Create new `SignedExtension` to check runtime version.
pub fn new() -> Self {
Self(sp_std::marker::PhantomData)
}
}
impl<T: Trait + Send + Sync> SignedExtension for CheckVersion<T> {
type AccountId = T::AccountId;
type Call = <T as Trait>::Call;
type AdditionalSigned = u32;
type Pre = ();
const IDENTIFIER: &'static str = "CheckVersion";
fn additional_signed(&self) -> Result<Self::AdditionalSigned, TransactionValidityError> {
Ok(<Module<T>>::runtime_version().spec_version)
}
}
pub struct ChainContext<T>(sp_std::marker::PhantomData<T>);
impl<T> Default for ChainContext<T> {
fn default() -> Self {
ChainContext(sp_std::marker::PhantomData)
}
}
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) -> Result<Self::Target, LookupError> {
<T::Lookup as StaticLookup>::lookup(s)
use sp_runtime::{traits::{BlakeTwo256, IdentityLookup, SignedExtension}, testing::Header, DispatchError};
use frame_support::{impl_outer_origin, parameter_types, assert_ok, assert_err};
pub enum Origin for Test where system = super {}
}
parameter_types! {
pub const BlockHashCount: u64 = 10;
pub const MaximumBlockWeight: Weight = 1024;
pub const AvailableBlockRatio: Perbill = Perbill::from_percent(75);
pub const MaximumBlockLength: u32 = 1024;
pub const Version: RuntimeVersion = RuntimeVersion {
spec_name: sp_version::create_runtime_str!("test"),
impl_name: sp_version::create_runtime_str!("system-test"),
authoring_version: 1,
spec_version: 1,
impl_version: 1,
apis: sp_version::create_apis_vec!([]),
transaction_version: 1,
pub const BlockExecutionWeight: Weight = 10;
pub const ExtrinsicBaseWeight: Weight = 5;
pub const DbWeight: RuntimeDbWeight = RuntimeDbWeight {
read: 10,
write: 100,
};
thread_local!{
pub static KILLED: RefCell<Vec<u64>> = RefCell::new(vec![]);
}
pub struct RecordKilled;
impl OnKilledAccount<u64> for RecordKilled {
fn on_killed_account(who: &u64) { KILLED.with(|r| r.borrow_mut().push(*who)) }
}
#[derive(Debug, codec::Encode, codec::Decode)]
pub struct Call;
impl Dispatchable for Call {
type Origin = ();
type Trait = ();
type Info = DispatchInfo;
type PostInfo = PostDispatchInfo;
fn dispatch(self, _origin: Self::Origin)
-> sp_runtime::DispatchResultWithInfo<Self::PostInfo> {
panic!("Do not use dummy implementation for dispatch.");
}
}
type Index = u64;
type BlockNumber = u64;
type Hash = H256;
type Hashing = BlakeTwo256;
type AccountId = u64;
type Lookup = IdentityLookup<Self::AccountId>;
type Header = Header;
type Event = u16;
type BlockHashCount = BlockHashCount;
type MaximumBlockWeight = MaximumBlockWeight;
type DbWeight = DbWeight;
type BlockExecutionWeight = BlockExecutionWeight;
type ExtrinsicBaseWeight = ExtrinsicBaseWeight;
type AvailableBlockRatio = AvailableBlockRatio;
type MaximumBlockLength = MaximumBlockLength;
type Version = Version;
impl From<Event<Test>> for u16 {
fn from(e: Event<Test>) -> u16 {
Event::<Test>::ExtrinsicSuccess(..) => 100,
Event::<Test>::ExtrinsicFailed(..) => 101,
Event::<Test>::CodeUpdated => 102,
_ => 103,
fn new_test_ext() -> sp_io::TestExternalities {
let mut ext: sp_io::TestExternalities = GenesisConfig::default().build_storage::<Test>().unwrap().into();
// Add to each test the initial weight of a block
ext.execute_with(|| System::register_extra_weight_unchecked(<Test as Trait>::BlockExecutionWeight::get()));
ext
fn normal_weight_limit() -> Weight {
<Test as Trait>::AvailableBlockRatio::get() * <Test as Trait>::MaximumBlockWeight::get()
}
fn normal_length_limit() -> u32 {
<Test as Trait>::AvailableBlockRatio::get() * <Test as Trait>::MaximumBlockLength::get()
}
#[test]
fn origin_works() {
let o = Origin::from(RawOrigin::<u64>::Signed(1u64));
let x: Result<RawOrigin<u64>, Origin> = o.into();
assert_eq!(x, Ok(RawOrigin::<u64>::Signed(1u64)));
}
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
#[test]
fn stored_map_works() {
new_test_ext().execute_with(|| {
System::insert(&0, 42);
assert!(System::allow_death(&0));
System::inc_ref(&0);
assert!(!System::allow_death(&0));
System::insert(&0, 69);
assert!(!System::allow_death(&0));
System::dec_ref(&0);
assert!(System::allow_death(&0));
assert!(KILLED.with(|r| r.borrow().is_empty()));
System::kill_account(&0);
assert_eq!(KILLED.with(|r| r.borrow().clone()), vec![0u64]);
});
}
#[test]
fn deposit_event_should_work() {
new_test_ext().execute_with(|| {
Tomasz Drwięga
committed
System::initialize(
&1,
&[0u8; 32].into(),
&[0u8; 32].into(),
&Default::default(),
InitKind::Full,
);
System::note_finished_extrinsics();
System::deposit_event(1u16);
assert_eq!(
System::events(),
vec![
EventRecord {
phase: Phase::Finalization,
event: 1u16,
topics: vec![],
}
]
Tomasz Drwięga
committed
System::initialize(
&2,
&[0u8; 32].into(),
&[0u8; 32].into(),
&Default::default(),
InitKind::Full,
);
System::deposit_event(32u16);
System::note_finished_initialize();
System::note_applied_extrinsic(&Ok(()), 0, Default::default());
System::note_applied_extrinsic(&Err(DispatchError::BadOrigin), 0, Default::default());
System::note_finished_extrinsics();
System::deposit_event(3u16);
assert_eq!(
System::events(),
vec![
EventRecord { phase: Phase::Initialization, event: 32u16, topics: 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![] }
]
);
#[test]
fn deposit_event_topics() {
new_test_ext().execute_with(|| {
const BLOCK_NUMBER: u64 = 1;
System::initialize(
&BLOCK_NUMBER,
&[0u8; 32].into(),
&[0u8; 32].into(),
&Default::default(),
Tomasz Drwięga
committed
InitKind::Full,
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901
1902
1903
1904
1905
1906
1907
1908
1909
1910
1911
1912
1913
1914
1915
1916
1917
1918
1919
1920
1921
1922
1923
System::note_finished_extrinsics();
let topics = vec![
H256::repeat_byte(1),
H256::repeat_byte(2),
H256::repeat_byte(3),
];
// We deposit a few events with different sets of topics.
System::deposit_event_indexed(&topics[0..3], 1u16);
System::deposit_event_indexed(&topics[0..1], 2u16);
System::deposit_event_indexed(&topics[1..2], 3u16);
System::finalize();
// Check that topics are reflected in the event record.
assert_eq!(
System::events(),
vec![
EventRecord {
phase: Phase::Finalization,
event: 1u16,
topics: topics[0..3].to_vec(),
},
EventRecord {
phase: Phase::Finalization,
event: 2u16,
topics: topics[0..1].to_vec(),
},
EventRecord {
phase: Phase::Finalization,
event: 3u16,
topics: topics[1..2].to_vec(),
}
]
);
// Check that the topic-events mapping reflects the deposited topics.
// Note that these are indexes of the events.
assert_eq!(
System::event_topics(&topics[0]),
vec![(BLOCK_NUMBER, 0), (BLOCK_NUMBER, 1)],
);
assert_eq!(
System::event_topics(&topics[1]),
vec![(BLOCK_NUMBER, 0), (BLOCK_NUMBER, 2)],
);
assert_eq!(
System::event_topics(&topics[2]),
vec![(BLOCK_NUMBER, 0)],
);
});
}
#[test]
fn prunes_block_hash_mappings() {
new_test_ext().execute_with(|| {
// simulate import of 15 blocks
for n in 1..=15 {
System::initialize(
&n,
&[n as u8 - 1; 32].into(),
&[0u8; 32].into(),
&Default::default(),
Tomasz Drwięga
committed
InitKind::Full,
1949
1950
1951
1952
1953
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
1965
1966
1967
1968
1969
1970
);
System::finalize();
}
// first 5 block hashes are pruned
for n in 0..5 {
assert_eq!(
System::block_hash(n),
H256::zero(),
);
}
// the remaining 10 are kept
for n in 5..15 {
assert_eq!(
System::block_hash(n),
[n as u8; 32].into(),
);
}
})
}
#[test]
fn signed_ext_check_nonce_works() {
new_test_ext().execute_with(|| {
Account::<Test>::insert(1, AccountInfo { nonce: 1, refcount: 0, data: 0 });
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>(1).validate(&1, CALL, &info, len).is_ok());
assert!(CheckNonce::<Test>(1).pre_dispatch(&1, CALL, &info, len).is_ok());
assert!(CheckNonce::<Test>(5).validate(&1, CALL, &info, len).is_ok());
assert!(CheckNonce::<Test>(5).pre_dispatch(&1, CALL, &info, len).is_err());
fn signed_ext_check_weight_works_normal_tx() {
new_test_ext().execute_with(|| {
let small = DispatchInfo { weight: 100, ..Default::default() };
let medium = DispatchInfo {
weight: normal_limit - <Test as Trait>::ExtrinsicBaseWeight::get(),
..Default::default()
};
let big = DispatchInfo {
weight: normal_limit - <Test as Trait>::ExtrinsicBaseWeight::get() + 1,