Newer
Older
/// Some resultant status relevant to decrementing a provider/self-sufficient reference.
#[derive(Eq, PartialEq, RuntimeDebug)]
pub enum DecRefStatus {
/// Account was destroyed.
Reaped,
/// Account still exists.
Exists,
}
/// Some resultant status relevant to decrementing a provider reference.
#[derive(Eq, PartialEq, RuntimeDebug)]
pub enum DecRefError {
/// Account cannot have the last provider reference removed while there is a consumer.
ConsumerRemaining,
}
/// Some resultant status relevant to incrementing a consumer reference.
#[derive(Eq, PartialEq, RuntimeDebug)]
pub enum IncRefError {
/// Account cannot introduce a consumer while there are no providers.
NoProviders,
}
impl<T: Config> Module<T> {
pub fn account_exists(who: &T::AccountId) -> bool {
Account::<T>::contains_key(who)
}
#[deprecated = "Use `inc_consumers` instead"]
let _ = Self::inc_consumers(who);
}
/// Decrement the reference counter on an account. This *MUST* only be done once for every time
/// you called `inc_consumers` on `who`.
#[deprecated = "Use `dec_consumers` instead"]
let _ = Self::dec_consumers(who);
}
/// The number of outstanding references for the account `who`.
#[deprecated = "Use `consumers` instead"]
Self::consumers(who)
}
/// True if the account has no outstanding references.
#[deprecated = "Use `!is_provider_required` instead"]
!Self::is_provider_required(who)
}
/// Increment the provider reference counter on an account.
pub fn inc_providers(who: &T::AccountId) -> IncRefStatus {
Account::<T>::mutate(who, |a| if a.providers == 0 && a.sufficients == 0 {
// Account is being created.
a.providers = 1;
Self::on_created_account(who.clone(), a);
IncRefStatus::Created
} else {
a.providers = a.providers.saturating_add(1);
IncRefStatus::Existed
})
}
/// Decrement the provider reference counter on an account.
///
/// This *MUST* only be done once for every time you called `inc_providers` on `who`.
pub fn dec_providers(who: &T::AccountId) -> Result<DecRefStatus, DecRefError> {
Account::<T>::try_mutate_exists(who, |maybe_account| {
if let Some(mut account) = maybe_account.take() {
if account.providers == 0 {
// Logic error - cannot decrement beyond zero.
log::error!(
target: "runtime::system",
"Logic error: Unexpected underflow in reducing provider",
);
account.providers = 1;
}
match (account.providers, account.consumers, account.sufficients) {
(1, 0, 0) => {
// No providers left (and no consumers) and no sufficients. Account dead.
Module::<T>::on_killed_account(who.clone());
Ok(DecRefStatus::Reaped)
}
// Cannot remove last provider if there are consumers.
Err(DecRefError::ConsumerRemaining)
}
(x, _, _) => {
// Account will continue to exist as there is either > 1 provider or
// > 0 sufficients.
account.providers = x - 1;
*maybe_account = Some(account);
Ok(DecRefStatus::Exists)
}
}
} else {
log::error!(
target: "runtime::system",
"Logic error: Account already dead when reducing provider",
);
Ok(DecRefStatus::Reaped)
}
})
}
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
/// Increment the self-sufficient reference counter on an account.
pub fn inc_sufficients(who: &T::AccountId) -> IncRefStatus {
Account::<T>::mutate(who, |a| if a.providers + a.sufficients == 0 {
// Account is being created.
a.sufficients = 1;
Self::on_created_account(who.clone(), a);
IncRefStatus::Created
} else {
a.sufficients = a.sufficients.saturating_add(1);
IncRefStatus::Existed
})
}
/// Decrement the sufficients reference counter on an account.
///
/// This *MUST* only be done once for every time you called `inc_sufficients` on `who`.
pub fn dec_sufficients(who: &T::AccountId) -> DecRefStatus {
Account::<T>::mutate_exists(who, |maybe_account| {
if let Some(mut account) = maybe_account.take() {
if account.sufficients == 0 {
// Logic error - cannot decrement beyond zero.
log::error!(
target: "runtime::system",
"Logic error: Unexpected underflow in reducing sufficients",
);
}
match (account.sufficients, account.providers) {
(0, 0) | (1, 0) => {
Module::<T>::on_killed_account(who.clone());
DecRefStatus::Reaped
}
(x, _) => {
account.sufficients = x - 1;
*maybe_account = Some(account);
DecRefStatus::Exists
}
}
} else {
log::error!(
target: "runtime::system",
"Logic error: Account already dead when reducing provider",
);
DecRefStatus::Reaped
}
})
}
/// The number of outstanding provider references for the account `who`.
pub fn providers(who: &T::AccountId) -> RefCount {
Account::<T>::get(who).providers
}
/// The number of outstanding sufficient references for the account `who`.
pub fn sufficients(who: &T::AccountId) -> RefCount {
Account::<T>::get(who).sufficients
}
/// The number of outstanding provider and sufficient references for the account `who`.
pub fn reference_count(who: &T::AccountId) -> RefCount {
let a = Account::<T>::get(who);
a.providers + a.sufficients
}
/// Increment the reference counter on an account.
///
/// The account `who`'s `providers` must be non-zero or this will return an error.
pub fn inc_consumers(who: &T::AccountId) -> Result<(), IncRefError> {
Account::<T>::try_mutate(who, |a| if a.providers > 0 {
a.consumers = a.consumers.saturating_add(1);
Ok(())
} else {
Err(IncRefError::NoProviders)
})
}
/// Decrement the reference counter on an account. This *MUST* only be done once for every time
/// you called `inc_consumers` on `who`.
pub fn dec_consumers(who: &T::AccountId) {
Account::<T>::mutate(who, |a| if a.consumers > 0 {
a.consumers -= 1;
} else {
log::error!(
target: "runtime::system",
"Logic error: Unexpected underflow in reducing consumer",
);
})
}
/// The number of outstanding references for the account `who`.
pub fn consumers(who: &T::AccountId) -> RefCount {
Account::<T>::get(who).consumers
}
/// True if the account has some outstanding references.
pub fn is_provider_required(who: &T::AccountId) -> bool {
Account::<T>::get(who).consumers != 0
}
/// Deposits an event into this block's event record.
pub fn deposit_event(event: impl Into<T::Event>) {
Self::deposit_event_indexed(&[], event.into());
}
/// Deposits an event into this block's event record adding this event
/// to the corresponding topic indexes.
///
/// This will update storage entries that correspond to the specified topics.
/// It is expected that light-clients could subscribe to this topics.
pub fn deposit_event_indexed(topics: &[T::Hash], event: T::Event) {
let block_number = Self::block_number();
// Don't populate events on genesis.
if block_number.is_zero() { return }
let phase = ExecutionPhase::<T>::get().unwrap_or_default();
let event = EventRecord {
phase,
event,
topics: topics.iter().cloned().collect::<Vec<_>>(),
};
// Index of the to be added event.
let event_idx = {
let old_event_count = EventCount::<T>::get();
let new_event_count = match old_event_count.checked_add(1) {
// We've reached the maximum number of events at this block, just
// don't do anything and leave the event_count unaltered.
None => return,
Some(nc) => nc,
};
EventCount::<T>::put(new_event_count);
Events::<T>::append(&event);
<EventTopics<T>>::append(topic, &(block_number, event_idx));
/// Gets the index of extrinsic that is currently executing.
Svyatoslav Nikolsky
committed
pub fn extrinsic_index() -> Option<u32> {
storage::unhashed::get(well_known_keys::EXTRINSIC_INDEX)
Svyatoslav Nikolsky
committed
}
/// Gets extrinsics count.
pub fn extrinsic_count() -> u32 {
ExtrinsicCount::<T>::get().unwrap_or_default()
pub fn all_extrinsics_len() -> u32 {
AllExtrinsicsLen::<T>::get().unwrap_or_default()
/// Inform the system pallet of some additional weight that should be accounted for, in the
/// NOTE: use with extra care; this function is made public only be used for certain pallets
/// that need it. A runtime that does not have dynamic calls should never need this and should
/// stick to static weights. A typical use case for this is inner calls or smart contract calls.
/// Furthermore, it only makes sense to use this when it is presumably _cheap_ to provide the
/// argument `weight`; In other words, if this function is to be used to account for some
/// unknown, user provided call's weight, it would only make sense to use it if you are sure you
/// can rapidly compute the weight of the inner call.
///
/// Even more dangerous is to note that this function does NOT take any action, if the new sum
/// of block weight is more than the block weight limit. This is what the _unchecked_.
///
/// Another potential use-case could be for the `on_initialize` and `on_finalize` hooks.
pub fn register_extra_weight_unchecked(weight: Weight, class: DispatchClass) {
BlockWeight::<T>::mutate(|current_weight| {
current_weight.add(weight, class);
});
pub fn initialize(
number: &T::BlockNumber,
parent_hash: &T::Hash,
Tomasz Drwięga
committed
kind: InitKind,
ExecutionPhase::<T>::put(Phase::Initialization);
storage::unhashed::put(well_known_keys::EXTRINSIC_INDEX, &0u32);
<BlockHash<T>>::insert(*number - One::one(), parent_hash);
Tomasz Drwięga
committed
// Remove previous block data from storage
BlockWeight::<T>::kill();
// Kill inspectable storage entries in state when `InitKind::Full`.
Tomasz Drwięga
committed
if let InitKind::Full = kind {
<Events<T>>::kill();
EventCount::<T>::kill();
Tomasz Drwięga
committed
<EventTopics<T>>::remove_all();
}
/// Remove temporary "environment" entries in storage, compute the storage root and return the
/// resulting header for this block.
ExecutionPhase::<T>::kill();
AllExtrinsicsLen::<T>::kill();
// The following fields
//
// - <Events<T>>
// - <EventCount<T>>
// - <EventTopics<T>>
// - <Number<T>>
// - <ParentHash<T>>
// - <Digest<T>>
//
// stay to be inspected by the client and will be cleared by `Self::initialize`.
let number = <Number<T>>::get();
let parent_hash = <ParentHash<T>>::get();
let mut digest = <Digest<T>>::get();
let extrinsics = (0..ExtrinsicCount::<T>::take().unwrap_or_default())
.map(ExtrinsicData::<T>::take)
Bastian Köcher
committed
.collect();
let extrinsics_root = extrinsics_data_root::<T::Hashing>(extrinsics);
// move block hash pruning window by one block
Bastian Köcher
committed
let block_hash_count = T::BlockHashCount::get();
let to_remove = number.saturating_sub(block_hash_count).saturating_sub(One::one());
Bastian Köcher
committed
// keep genesis hash
if !to_remove.is_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);
}
<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 pallet, useful for tests.
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_consumed_resources(weight: Weight, len: usize) {
BlockWeight::<T>::mutate(|current_weight| {
current_weight.set(weight, DispatchClass::Normal)
AllExtrinsicsLen::<T>::put(len as u32);
/// Reset events. 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 reset_events() {
<Events<T>>::kill();
EventCount::<T>::kill();
<EventTopics<T>>::remove_all();
}
/// 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());
Bastian Köcher
committed
/// Note what the extrinsic data of the current extrinsic index is.
Bastian Köcher
committed
/// This is required to be called before applying an extrinsic. The data will used
/// in [`Self::finalize`] to calculate the correct extrinsics root.
pub fn note_extrinsic(encoded_xt: Vec<u8>) {
ExtrinsicData::<T>::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(_) => Event::ExtrinsicSuccess(info),
Err(err) => {
sp_runtime::print(err);
Event::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::<T>::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::<T>::put(extrinsic_index);
ExecutionPhase::<T>::put(Phase::Finalization);
}
/// To be called immediately after finishing the initialization of the block
/// (e.g., called `on_initialize` for all pallets).
pub fn note_finished_initialize() {
ExecutionPhase::<T>::put(Phase::ApplyExtrinsic(0))
pub fn on_created_account(who: T::AccountId, _a: &mut AccountInfo<T::Index, T::AccountData>) {
Self::deposit_event(Event::NewAccount(who));
}
/// Do anything that needs to be done after an account has been killed.
fn on_killed_account(who: T::AccountId) {
Self::deposit_event(Event::KilledAccount(who));
/// Determine whether or not it is possible to update the code.
///
/// Checks the given code if it is a valid runtime wasm blob by instantianting
/// it and extracting the runtime version of it. It checks that the runtime version
/// of the old and new runtime has the same spec name and that the spec version is increasing.
pub fn can_set_code(code: &[u8]) -> Result<(), sp_runtime::DispatchError> {
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 registers a provider when created.
pub struct Provider<T>(PhantomData<T>);
impl<T: Config> HandleLifetime<T::AccountId> for Provider<T> {
fn created(t: &T::AccountId) -> Result<(), StoredMapError> {
Module::<T>::inc_providers(t);
Ok(())
}
fn killed(t: &T::AccountId) -> Result<(), StoredMapError> {
Module::<T>::dec_providers(t)
.map(|_| ())
.or_else(|e| match e {
DecRefError::ConsumerRemaining => Err(StoredMapError::ConsumerRemaining),
})
/// Event handler which registers a self-sufficient when created.
pub struct SelfSufficient<T>(PhantomData<T>);
impl<T: Config> HandleLifetime<T::AccountId> for SelfSufficient<T> {
fn created(t: &T::AccountId) -> Result<(), StoredMapError> {
Module::<T>::inc_sufficients(t);
Ok(())
}
fn killed(t: &T::AccountId) -> Result<(), StoredMapError> {
Module::<T>::dec_sufficients(t);
Ok(())
}
}
/// Event handler which registers a consumer when created.
pub struct Consumer<T>(PhantomData<T>);
impl<T: Config> HandleLifetime<T::AccountId> for Consumer<T> {
fn created(t: &T::AccountId) -> Result<(), StoredMapError> {
Module::<T>::inc_consumers(t)
.map_err(|e| match e {
IncRefError::NoProviders => StoredMapError::NoProviders
})
}
fn killed(t: &T::AccountId) -> Result<(), StoredMapError> {
Module::<T>::dec_consumers(t);
Ok(())
impl<T: Config> BlockNumberProvider for Pallet<T>
type BlockNumber = <T as Config>::BlockNumber;
fn current_block_number() -> Self::BlockNumber {
Pallet::<T>::block_number()
fn is_providing<T: Default + Eq>(d: &T) -> bool {
d != &T::default()
}
/// Implement StoredMap for a simple single-item, provide-when-not-default system. This works fine
/// for storing a single item which allows the account to continue existing as long as it's not
/// empty/default.
///
/// Anything more complex will need more sophisticated logic.
impl<T: Config> StoredMap<T::AccountId, T::AccountData> for Pallet<T> {
fn try_mutate_exists<R, E: From<StoredMapError>>(
k: &T::AccountId,
f: impl FnOnce(&mut Option<T::AccountData>) -> Result<R, E>,
) -> Result<R, E> {
let account = Account::<T>::get(k);
let was_providing = is_providing(&account.data);
let mut some_data = if was_providing { Some(account.data) } else { None };
let result = f(&mut some_data)?;
let is_providing = some_data.is_some();
if !was_providing && is_providing {
Self::inc_providers(k);
} else if was_providing && !is_providing {
match Self::dec_providers(k) {
Err(DecRefError::ConsumerRemaining) => Err(StoredMapError::ConsumerRemaining)?,
Ok(DecRefStatus::Reaped) => return Ok(result),
Ok(DecRefStatus::Exists) => {
// Update value as normal...
}
} else if !was_providing && !is_providing {
return Ok(result)
}
Account::<T>::mutate(k, |a| a.data = some_data.unwrap_or_default());
Ok(result)
/// 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),
pub struct ChainContext<T>(PhantomData<T>);
impl<T> Default for ChainContext<T> {
fn default() -> Self {
ChainContext(PhantomData)
impl<T: Config> 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)
/// Prelude to be used alongside pallet macro, for ease of use.
pub mod pallet_prelude {
pub use crate::{ensure_signed, ensure_none, ensure_root};
/// Type alias for the `Origin` associated type of system config.
pub type OriginFor<T> = <T as crate::Config>::Origin;
/// Type alias for the `BlockNumber` associated type of system config.
pub type BlockNumberFor<T> = <T as crate::Config>::BlockNumber;
}