Newer
Older
AllExtrinsicsWeight::mutate(|current_weight| {
current_weight.add(weight, class);
});
pub fn initialize(
number: &T::BlockNumber,
parent_hash: &T::Hash,
txs_root: &T::Hash,
Tomasz Drwięga
committed
kind: InitKind,
ExecutionPhase::put(Phase::Initialization);
storage::unhashed::put(well_known_keys::EXTRINSIC_INDEX, &0u32);
<BlockHash<T>>::insert(*number - One::one(), parent_hash);
Tomasz Drwięga
committed
if let InitKind::Full = kind {
<Events<T>>::kill();
EventCount::kill();
<EventTopics<T>>::remove_all();
}
}
/// Remove temporary "environment" entries in storage.
ExtrinsicCount::kill();
AllExtrinsicsWeight::kill();
let number = <Number<T>>::take();
let parent_hash = <ParentHash<T>>::take();
Svyatoslav Nikolsky
committed
let mut digest = <Digest<T>>::take();
// move block hash pruning window by one block
let block_hash_count = <T::BlockHashCount>::get();
if number > block_hash_count {
let to_remove = number - block_hash_count - One::one();
// keep genesis hash
if to_remove != Zero::zero() {
<BlockHash<T>>::remove(to_remove);
}
}
let storage_root = T::Hash::decode(&mut &sp_io::storage::root()[..])
.expect("Node is configured to use the same hash; qed");
let storage_changes_root = sp_io::storage::changes_root(&parent_hash.encode());
Svyatoslav Nikolsky
committed
// we can't compute changes trie root earlier && put it to the Digest
// because it will include all currently existing temporaries.
Svyatoslav Nikolsky
committed
if let Some(storage_changes_root) = storage_changes_root {
let item = generic::DigestItem::ChangesTrieRoot(
T::Hash::decode(&mut &storage_changes_root[..])
.expect("Node is configured to use the same hash; qed")
);
Svyatoslav Nikolsky
committed
digest.push(item);
}
// The following fields
//
// - <Events<T>>
// - <EventCount<T>>
// - <EventTopics<T>>
//
// stay to be inspected by the client and will be cleared by `Self::initialize`.
<T::Header as traits::Header>::new(number, extrinsics_root, storage_root, parent_hash, digest)
/// Deposits a log and ensures it matches the block's log data.
/// # <weight>
/// - `O(1)`
/// - 1 storage write (codec `O(1)`)
/// # </weight>
pub fn deposit_log(item: DigestItemOf<T>) {
<Digest<T>>::append(item);
}
/// 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::mutate(|current_weight| {
current_weight.put(weight, DispatchClass::Normal)
});
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.
pub fn note_applied_extrinsic(r: &DispatchResultWithPostInfo, mut info: DispatchInfo) {
info.weight = extract_actual_weight(r, &info);
Self::deposit_event(
match r {
Ok(_) => RawEvent::ExtrinsicSuccess(info),
Err(err) => {
sp_runtime::print(err);
RawEvent::ExtrinsicFailed(err.error, info)
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());
}
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
/// 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 {
match class {
DispatchClass::Operational | DispatchClass::Mandatory
=> <Perbill as sp_runtime::PerThing>::one(),
DispatchClass::Normal => T::AvailableBlockRatio::get(),
}
/// 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<ExtrinsicsWeight, TransactionValidityError> {
let maximum_weight = T::MaximumBlockWeight::get();
let mut all_weight = Module::<T>::all_extrinsics_weight();
match info.class {
// If we have a dispatch that must be included in the block, it ignores all the limits.
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
DispatchClass::Mandatory => {
let extrinsic_weight = info.weight.saturating_add(T::ExtrinsicBaseWeight::get());
all_weight.add(extrinsic_weight, DispatchClass::Mandatory);
Ok(all_weight)
},
// If we have a normal dispatch, we follow all the normal rules and limits.
DispatchClass::Normal => {
let normal_limit = Self::get_dispatch_limit_ratio(DispatchClass::Normal) * maximum_weight;
let extrinsic_weight = info.weight.checked_add(T::ExtrinsicBaseWeight::get())
.ok_or(InvalidTransaction::ExhaustsResources)?;
all_weight.checked_add(extrinsic_weight, DispatchClass::Normal)
.map_err(|_| InvalidTransaction::ExhaustsResources)?;
if all_weight.get(DispatchClass::Normal) > normal_limit {
Err(InvalidTransaction::ExhaustsResources.into())
} else {
Ok(all_weight)
}
},
// If we have an operational dispatch, allow it if we have not used our full
// "operational space" (independent of existing fullness).
DispatchClass::Operational => {
let operational_limit = Self::get_dispatch_limit_ratio(DispatchClass::Operational) * maximum_weight;
let normal_limit = Self::get_dispatch_limit_ratio(DispatchClass::Normal) * maximum_weight;
let operational_space = operational_limit.saturating_sub(normal_limit);
let extrinsic_weight = info.weight.checked_add(T::ExtrinsicBaseWeight::get())
.ok_or(InvalidTransaction::ExhaustsResources)?;
all_weight.checked_add(extrinsic_weight, DispatchClass::Operational)
.map_err(|_| InvalidTransaction::ExhaustsResources)?;
// If it would fit in normally, its okay
if all_weight.total() <= maximum_weight ||
// If we have not used our operational space
all_weight.get(DispatchClass::Operational) <= operational_space {
Ok(all_weight)
} else {
Err(InvalidTransaction::ExhaustsResources.into())
}
}
}
/// 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(|current_weight| {
current_weight.sub(unspent, info.class);
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()))
}
}
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
/// Ensure the transaction version registered in the transaction is the same as at present.
#[derive(Encode, Decode, Clone, Eq, PartialEq)]
pub struct CheckTxVersion<T: Trait + Send + Sync>(sp_std::marker::PhantomData<T>);
impl<T: Trait + Send + Sync> Debug for CheckTxVersion<T> {
#[cfg(feature = "std")]
fn fmt(&self, f: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result {
write!(f, "CheckTxVersion")
}
#[cfg(not(feature = "std"))]
fn fmt(&self, _: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result {
Ok(())
}
}
impl<T: Trait + Send + Sync> CheckTxVersion<T> {
/// Create new `SignedExtension` to check transaction version.
pub fn new() -> Self {
Self(sp_std::marker::PhantomData)
}
}
impl<T: Trait + Send + Sync> SignedExtension for CheckTxVersion<T> {
type AccountId = T::AccountId;
type Call = <T as Trait>::Call;
type AdditionalSigned = u32;
type Pre = ();
const IDENTIFIER: &'static str = "CheckTxVersion";
fn additional_signed(&self) -> Result<Self::AdditionalSigned, TransactionValidityError> {
Ok(<Module<T>>::runtime_version().transaction_version)
}
}
/// Ensure the runtime version registered in the transaction is the same as at present.
#[derive(Encode, Decode, Clone, Eq, PartialEq)]
pub struct CheckSpecVersion<T: Trait + Send + Sync>(sp_std::marker::PhantomData<T>);
impl<T: Trait + Send + Sync> Debug for CheckSpecVersion<T> {
fn fmt(&self, f: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result {
write!(f, "CheckSpecVersion")
fn fmt(&self, _: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result {
Ok(())
}
}
impl<T: Trait + Send + Sync> CheckSpecVersion<T> {
/// Create new `SignedExtension` to check runtime version.
pub fn new() -> Self {
Self(sp_std::marker::PhantomData)
}
}
impl<T: Trait + Send + Sync> SignedExtension for CheckSpecVersion<T> {
type AccountId = T::AccountId;
type Call = <T as Trait>::Call;
type AdditionalSigned = u32;
type Pre = ();
const IDENTIFIER: &'static str = "CheckSpecVersion";
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_noop,
weights::WithPostDispatchInfo,
};
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 Event = Event<Self>;
type BlockHashCount = BlockHashCount;
type MaximumBlockWeight = MaximumBlockWeight;
type DbWeight = DbWeight;
type BlockExecutionWeight = BlockExecutionWeight;
type ExtrinsicBaseWeight = ExtrinsicBaseWeight;
type AvailableBlockRatio = AvailableBlockRatio;
type MaximumBlockLength = MaximumBlockLength;
type Version = Version;
type SysEvent = <Test as Trait>::Event;
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(), DispatchClass::Mandatory));
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)));
}
1944
1945
1946
1947
1948
1949
1950
1951
1952
1953
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
#[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::deposit_event(SysEvent::CodeUpdated);
assert_eq!(
System::events(),
vec![
EventRecord {
phase: Phase::Finalization,
event: SysEvent::CodeUpdated,
Tomasz Drwięga
committed
System::initialize(
&2,
&[0u8; 32].into(),
&[0u8; 32].into(),
&Default::default(),
InitKind::Full,
);
System::deposit_event(SysEvent::NewAccount(32));
System::note_finished_initialize();
System::deposit_event(SysEvent::KilledAccount(42));
System::note_applied_extrinsic(&Ok(().into()), Default::default());
System::note_applied_extrinsic(