mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-12 03:01:07 +00:00
Child trie api changes BREAKING (#4857)
Co-Authored-By: thiolliere <gui.thiolliere@gmail.com>
This commit is contained in:
@@ -128,7 +128,7 @@ impl<T: Trait> AccountDb<T> for DirectAccountDb {
|
||||
trie_id: Option<&TrieId>,
|
||||
location: &StorageKey
|
||||
) -> Option<Vec<u8>> {
|
||||
trie_id.and_then(|id| child::get_raw(id, crate::trie_unique_id(&id[..]), &blake2_256(location)))
|
||||
trie_id.and_then(|id| child::get_raw(&crate::child_trie_info(&id[..]), &blake2_256(location)))
|
||||
}
|
||||
fn get_code_hash(&self, account: &T::AccountId) -> Option<CodeHash<T>> {
|
||||
<ContractInfoOf<T>>::get(account).and_then(|i| i.as_alive().map(|i| i.code_hash))
|
||||
@@ -167,13 +167,13 @@ impl<T: Trait> AccountDb<T> for DirectAccountDb {
|
||||
(false, Some(info), _) => info,
|
||||
// Existing contract is being removed.
|
||||
(true, Some(info), None) => {
|
||||
child::kill_storage(&info.trie_id, info.child_trie_unique_id());
|
||||
child::kill_storage(&info.child_trie_info());
|
||||
<ContractInfoOf<T>>::remove(&address);
|
||||
continue;
|
||||
}
|
||||
// Existing contract is being replaced by a new one.
|
||||
(true, Some(info), Some(code_hash)) => {
|
||||
child::kill_storage(&info.trie_id, info.child_trie_unique_id());
|
||||
child::kill_storage(&info.child_trie_info());
|
||||
AliveContractInfo::<T> {
|
||||
code_hash,
|
||||
storage_size: T::StorageSizeOffset::get(),
|
||||
@@ -212,17 +212,16 @@ impl<T: Trait> AccountDb<T> for DirectAccountDb {
|
||||
|
||||
for (k, v) in changed.storage.into_iter() {
|
||||
if let Some(value) = child::get_raw(
|
||||
&new_info.trie_id[..],
|
||||
new_info.child_trie_unique_id(),
|
||||
&new_info.child_trie_info(),
|
||||
&blake2_256(&k),
|
||||
) {
|
||||
new_info.storage_size -= value.len() as u32;
|
||||
}
|
||||
if let Some(value) = v {
|
||||
new_info.storage_size += value.len() as u32;
|
||||
child::put_raw(&new_info.trie_id[..], new_info.child_trie_unique_id(), &blake2_256(&k), &value[..]);
|
||||
child::put_raw(&new_info.child_trie_info(), &blake2_256(&k), &value[..]);
|
||||
} else {
|
||||
child::kill(&new_info.trie_id[..], new_info.child_trie_unique_id(), &blake2_256(&k));
|
||||
child::kill(&new_info.child_trie_info(), &blake2_256(&k));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -125,12 +125,11 @@ use sp_runtime::{
|
||||
use frame_support::dispatch::{DispatchResult, Dispatchable};
|
||||
use frame_support::weights::{SimpleDispatchInfo, MINIMUM_WEIGHT};
|
||||
use frame_support::{
|
||||
Parameter, decl_module, decl_event, decl_storage, decl_error, storage::child,
|
||||
parameter_types, IsSubType,
|
||||
Parameter, decl_module, decl_event, decl_storage, decl_error,
|
||||
parameter_types, IsSubType, storage::child::{self, ChildInfo},
|
||||
};
|
||||
use frame_support::traits::{OnUnbalanced, Currency, Get, Time, Randomness};
|
||||
use frame_system::{self as system, ensure_signed, RawOrigin, ensure_root};
|
||||
use sp_core::storage::well_known_keys::CHILD_STORAGE_KEY_PREFIX;
|
||||
use pallet_contracts_primitives::{RentProjection, ContractAccessError};
|
||||
|
||||
pub type CodeHash<T> = <T as frame_system::Trait>::Hash;
|
||||
@@ -229,15 +228,14 @@ pub struct RawAliveContractInfo<CodeHash, Balance, BlockNumber> {
|
||||
|
||||
impl<CodeHash, Balance, BlockNumber> RawAliveContractInfo<CodeHash, Balance, BlockNumber> {
|
||||
/// Associated child trie unique id is built from the hash part of the trie id.
|
||||
pub fn child_trie_unique_id(&self) -> child::ChildInfo {
|
||||
trie_unique_id(&self.trie_id[..])
|
||||
pub fn child_trie_info(&self) -> ChildInfo {
|
||||
child_trie_info(&self.trie_id[..])
|
||||
}
|
||||
}
|
||||
|
||||
/// Associated child trie unique id is built from the hash part of the trie id.
|
||||
pub(crate) fn trie_unique_id(trie_id: &[u8]) -> child::ChildInfo {
|
||||
let start = CHILD_STORAGE_KEY_PREFIX.len() + b"default:".len();
|
||||
child::ChildInfo::new_default(&trie_id[start ..])
|
||||
pub(crate) fn child_trie_info(trie_id: &[u8]) -> ChildInfo {
|
||||
ChildInfo::new_default(trie_id)
|
||||
}
|
||||
|
||||
pub type TombstoneContractInfo<T> =
|
||||
@@ -270,10 +268,6 @@ pub trait TrieIdGenerator<AccountId> {
|
||||
///
|
||||
/// The implementation must ensure every new trie id is unique: two consecutive calls with the
|
||||
/// same parameter needs to return different trie id values.
|
||||
///
|
||||
/// Also, the implementation is responsible for ensuring that `TrieId` starts with
|
||||
/// `:child_storage:`.
|
||||
/// TODO: We want to change this, see https://github.com/paritytech/substrate/issues/2325
|
||||
fn trie_id(account_id: &AccountId) -> TrieId;
|
||||
}
|
||||
|
||||
@@ -297,13 +291,7 @@ where
|
||||
let mut buf = Vec::new();
|
||||
buf.extend_from_slice(account_id.as_ref());
|
||||
buf.extend_from_slice(&new_seed.to_le_bytes()[..]);
|
||||
|
||||
// TODO: see https://github.com/paritytech/substrate/issues/2325
|
||||
CHILD_STORAGE_KEY_PREFIX.iter()
|
||||
.chain(b"default:")
|
||||
.chain(T::Hashing::hash(&buf[..]).as_ref().iter())
|
||||
.cloned()
|
||||
.collect()
|
||||
T::Hashing::hash(&buf[..]).as_ref().into()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -824,13 +812,11 @@ impl<T: Trait> Module<T> {
|
||||
let key_values_taken = delta.iter()
|
||||
.filter_map(|key| {
|
||||
child::get_raw(
|
||||
&origin_contract.trie_id,
|
||||
origin_contract.child_trie_unique_id(),
|
||||
&origin_contract.child_trie_info(),
|
||||
&blake2_256(key),
|
||||
).map(|value| {
|
||||
child::kill(
|
||||
&origin_contract.trie_id,
|
||||
origin_contract.child_trie_unique_id(),
|
||||
&origin_contract.child_trie_info(),
|
||||
&blake2_256(key),
|
||||
);
|
||||
|
||||
@@ -842,8 +828,8 @@ impl<T: Trait> Module<T> {
|
||||
let tombstone = <TombstoneContractInfo<T>>::new(
|
||||
// This operation is cheap enough because last_write (delta not included)
|
||||
// is not this block as it has been checked earlier.
|
||||
&child::child_root(
|
||||
&origin_contract.trie_id,
|
||||
&child::root(
|
||||
&origin_contract.child_trie_info(),
|
||||
)[..],
|
||||
code_hash,
|
||||
);
|
||||
@@ -851,8 +837,7 @@ impl<T: Trait> Module<T> {
|
||||
if tombstone != dest_tombstone {
|
||||
for (key, value) in key_values_taken {
|
||||
child::put_raw(
|
||||
&origin_contract.trie_id,
|
||||
origin_contract.child_trie_unique_id(),
|
||||
&origin_contract.child_trie_info(),
|
||||
&blake2_256(key),
|
||||
&value,
|
||||
);
|
||||
|
||||
@@ -223,8 +223,7 @@ fn enact_verdict<T: Trait>(
|
||||
Verdict::Kill => {
|
||||
<ContractInfoOf<T>>::remove(account);
|
||||
child::kill_storage(
|
||||
&alive_contract_info.trie_id,
|
||||
alive_contract_info.child_trie_unique_id(),
|
||||
&alive_contract_info.child_trie_info(),
|
||||
);
|
||||
<Module<T>>::deposit_event(RawEvent::Evicted(account.clone(), false));
|
||||
None
|
||||
@@ -235,7 +234,9 @@ fn enact_verdict<T: Trait>(
|
||||
}
|
||||
|
||||
// Note: this operation is heavy.
|
||||
let child_storage_root = child::child_root(&alive_contract_info.trie_id);
|
||||
let child_storage_root = child::root(
|
||||
&alive_contract_info.child_trie_info(),
|
||||
);
|
||||
|
||||
let tombstone = <TombstoneContractInfo<T>>::new(
|
||||
&child_storage_root[..],
|
||||
@@ -245,8 +246,7 @@ fn enact_verdict<T: Trait>(
|
||||
<ContractInfoOf<T>>::insert(account, &tombstone_info);
|
||||
|
||||
child::kill_storage(
|
||||
&alive_contract_info.trie_id,
|
||||
alive_contract_info.child_trie_unique_id(),
|
||||
&alive_contract_info.child_trie_info(),
|
||||
);
|
||||
|
||||
<Module<T>>::deposit_event(RawEvent::Evicted(account.clone(), true));
|
||||
|
||||
@@ -200,10 +200,7 @@ impl TrieIdGenerator<u64> for DummyTrieIdGenerator {
|
||||
*v
|
||||
});
|
||||
|
||||
// TODO: see https://github.com/paritytech/substrate/issues/2325
|
||||
let mut res = vec![];
|
||||
res.extend_from_slice(well_known_keys::CHILD_STORAGE_KEY_PREFIX);
|
||||
res.extend_from_slice(b"default:");
|
||||
res.extend_from_slice(&new_seed.to_le_bytes());
|
||||
res.extend_from_slice(&account_id.to_le_bytes());
|
||||
res
|
||||
|
||||
@@ -16,100 +16,90 @@
|
||||
|
||||
//! Operation on runtime child storages.
|
||||
//!
|
||||
//! This module is a currently only a variant of unhashed with additional `storage_key`.
|
||||
//! Note that `storage_key` must be unique and strong (strong in the sense of being long enough to
|
||||
//! avoid collision from a resistant hash function (which unique implies)).
|
||||
//!
|
||||
//! A **key collision free** unique id is required as parameter to avoid key collision
|
||||
//! between child tries.
|
||||
//! This unique id management and generation responsibility is delegated to pallet module.
|
||||
// NOTE: could replace unhashed by having only one kind of storage (root being null storage key (storage_key can become Option<&[u8]>).
|
||||
//! This module is a currently only a variant of unhashed with additional `child_info`.
|
||||
// NOTE: could replace unhashed by having only one kind of storage (top trie being the child info
|
||||
// of null length parent storage key).
|
||||
|
||||
use crate::sp_std::prelude::*;
|
||||
use codec::{Codec, Encode, Decode};
|
||||
pub use sp_core::storage::ChildInfo;
|
||||
pub use sp_core::storage::{ChildInfo, ChildType};
|
||||
|
||||
/// Return the value of the item in storage under `key`, or `None` if there is no explicit entry.
|
||||
pub fn get<T: Decode + Sized>(
|
||||
storage_key: &[u8],
|
||||
child_info: ChildInfo,
|
||||
child_info: &ChildInfo,
|
||||
key: &[u8],
|
||||
) -> Option<T> {
|
||||
let (data, child_type) = child_info.info();
|
||||
sp_io::storage::child_get(
|
||||
storage_key,
|
||||
data,
|
||||
child_type,
|
||||
key,
|
||||
).and_then(|v| {
|
||||
Decode::decode(&mut &v[..]).map(Some).unwrap_or_else(|_| {
|
||||
// TODO #3700: error should be handleable.
|
||||
runtime_print!("ERROR: Corrupted state in child trie at {:?}/{:?}", storage_key, key);
|
||||
None
|
||||
})
|
||||
})
|
||||
match child_info.child_type() {
|
||||
ChildType::ParentKeyId => {
|
||||
let storage_key = child_info.storage_key();
|
||||
sp_io::default_child_storage::get(
|
||||
storage_key,
|
||||
key,
|
||||
).and_then(|v| {
|
||||
Decode::decode(&mut &v[..]).map(Some).unwrap_or_else(|_| {
|
||||
// TODO #3700: error should be handleable.
|
||||
runtime_print!("ERROR: Corrupted state in child trie at {:?}/{:?}", storage_key, key);
|
||||
None
|
||||
})
|
||||
})
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
/// Return the value of the item in storage under `key`, or the type's default if there is no
|
||||
/// explicit entry.
|
||||
pub fn get_or_default<T: Decode + Sized + Default>(
|
||||
storage_key: &[u8],
|
||||
child_info: ChildInfo,
|
||||
child_info: &ChildInfo,
|
||||
key: &[u8],
|
||||
) -> T {
|
||||
get(storage_key, child_info, key).unwrap_or_else(Default::default)
|
||||
get(child_info, key).unwrap_or_else(Default::default)
|
||||
}
|
||||
|
||||
/// Return the value of the item in storage under `key`, or `default_value` if there is no
|
||||
/// explicit entry.
|
||||
pub fn get_or<T: Decode + Sized>(
|
||||
storage_key: &[u8],
|
||||
child_info: ChildInfo,
|
||||
child_info: &ChildInfo,
|
||||
key: &[u8],
|
||||
default_value: T,
|
||||
) -> T {
|
||||
get(storage_key, child_info, key).unwrap_or(default_value)
|
||||
get(child_info, key).unwrap_or(default_value)
|
||||
}
|
||||
|
||||
/// Return the value of the item in storage under `key`, or `default_value()` if there is no
|
||||
/// explicit entry.
|
||||
pub fn get_or_else<T: Decode + Sized, F: FnOnce() -> T>(
|
||||
storage_key: &[u8],
|
||||
child_info: ChildInfo,
|
||||
child_info: &ChildInfo,
|
||||
key: &[u8],
|
||||
default_value: F,
|
||||
) -> T {
|
||||
get(storage_key, child_info, key).unwrap_or_else(default_value)
|
||||
get(child_info, key).unwrap_or_else(default_value)
|
||||
}
|
||||
|
||||
/// Put `value` in storage under `key`.
|
||||
pub fn put<T: Encode>(
|
||||
storage_key: &[u8],
|
||||
child_info: ChildInfo,
|
||||
child_info: &ChildInfo,
|
||||
key: &[u8],
|
||||
value: &T,
|
||||
) {
|
||||
let (data, child_type) = child_info.info();
|
||||
value.using_encoded(|slice|
|
||||
sp_io::storage::child_set(
|
||||
storage_key,
|
||||
data,
|
||||
child_type,
|
||||
key,
|
||||
slice,
|
||||
)
|
||||
);
|
||||
match child_info.child_type() {
|
||||
ChildType::ParentKeyId => value.using_encoded(|slice|
|
||||
sp_io::default_child_storage::set(
|
||||
child_info.storage_key(),
|
||||
key,
|
||||
slice,
|
||||
)
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
/// Remove `key` from storage, returning its value if it had an explicit entry or `None` otherwise.
|
||||
pub fn take<T: Decode + Sized>(
|
||||
storage_key: &[u8],
|
||||
child_info: ChildInfo,
|
||||
child_info: &ChildInfo,
|
||||
key: &[u8],
|
||||
) -> Option<T> {
|
||||
let r = get(storage_key, child_info, key);
|
||||
let r = get(child_info, key);
|
||||
if r.is_some() {
|
||||
kill(storage_key, child_info, key);
|
||||
kill(child_info, key);
|
||||
}
|
||||
r
|
||||
}
|
||||
@@ -117,113 +107,106 @@ pub fn take<T: Decode + Sized>(
|
||||
/// Remove `key` from storage, returning its value, or, if there was no explicit entry in storage,
|
||||
/// the default for its type.
|
||||
pub fn take_or_default<T: Codec + Sized + Default>(
|
||||
storage_key: &[u8],
|
||||
child_info: ChildInfo,
|
||||
child_info: &ChildInfo,
|
||||
key: &[u8],
|
||||
) -> T {
|
||||
take(storage_key, child_info, key).unwrap_or_else(Default::default)
|
||||
take(child_info, key).unwrap_or_else(Default::default)
|
||||
}
|
||||
|
||||
/// Return the value of the item in storage under `key`, or `default_value` if there is no
|
||||
/// explicit entry. Ensure there is no explicit entry on return.
|
||||
pub fn take_or<T: Codec + Sized>(
|
||||
storage_key: &[u8],
|
||||
child_info: ChildInfo,
|
||||
child_info: &ChildInfo,
|
||||
key: &[u8],
|
||||
default_value: T,
|
||||
) -> T {
|
||||
take(storage_key, child_info, key).unwrap_or(default_value)
|
||||
take(child_info, key).unwrap_or(default_value)
|
||||
}
|
||||
|
||||
/// Return the value of the item in storage under `key`, or `default_value()` if there is no
|
||||
/// explicit entry. Ensure there is no explicit entry on return.
|
||||
pub fn take_or_else<T: Codec + Sized, F: FnOnce() -> T>(
|
||||
storage_key: &[u8],
|
||||
child_info: ChildInfo,
|
||||
child_info: &ChildInfo,
|
||||
key: &[u8],
|
||||
default_value: F,
|
||||
) -> T {
|
||||
take(storage_key, child_info, key).unwrap_or_else(default_value)
|
||||
take(child_info, key).unwrap_or_else(default_value)
|
||||
}
|
||||
|
||||
/// Check to see if `key` has an explicit entry in storage.
|
||||
pub fn exists(
|
||||
storage_key: &[u8],
|
||||
child_info: ChildInfo,
|
||||
child_info: &ChildInfo,
|
||||
key: &[u8],
|
||||
) -> bool {
|
||||
let (data, child_type) = child_info.info();
|
||||
sp_io::storage::child_read(
|
||||
storage_key, data, child_type,
|
||||
key, &mut [0;0][..], 0,
|
||||
).is_some()
|
||||
match child_info.child_type() {
|
||||
ChildType::ParentKeyId => sp_io::default_child_storage::read(
|
||||
child_info.storage_key(),
|
||||
key, &mut [0;0][..], 0,
|
||||
).is_some(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Remove all `storage_key` key/values
|
||||
pub fn kill_storage(
|
||||
storage_key: &[u8],
|
||||
child_info: ChildInfo,
|
||||
child_info: &ChildInfo,
|
||||
) {
|
||||
let (data, child_type) = child_info.info();
|
||||
sp_io::storage::child_storage_kill(
|
||||
storage_key,
|
||||
data,
|
||||
child_type,
|
||||
)
|
||||
match child_info.child_type() {
|
||||
ChildType::ParentKeyId => sp_io::default_child_storage::storage_kill(
|
||||
child_info.storage_key(),
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
/// Ensure `key` has no explicit entry in storage.
|
||||
pub fn kill(
|
||||
storage_key: &[u8],
|
||||
child_info: ChildInfo,
|
||||
child_info: &ChildInfo,
|
||||
key: &[u8],
|
||||
) {
|
||||
let (data, child_type) = child_info.info();
|
||||
sp_io::storage::child_clear(
|
||||
storage_key,
|
||||
data,
|
||||
child_type,
|
||||
key,
|
||||
);
|
||||
match child_info.child_type() {
|
||||
ChildType::ParentKeyId => {
|
||||
sp_io::default_child_storage::clear(
|
||||
child_info.storage_key(),
|
||||
key,
|
||||
);
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
/// Get a Vec of bytes from storage.
|
||||
pub fn get_raw(
|
||||
storage_key: &[u8],
|
||||
child_info: ChildInfo,
|
||||
child_info: &ChildInfo,
|
||||
key: &[u8],
|
||||
) -> Option<Vec<u8>> {
|
||||
let (data, child_type) = child_info.info();
|
||||
sp_io::storage::child_get(
|
||||
storage_key,
|
||||
data,
|
||||
child_type,
|
||||
key,
|
||||
)
|
||||
match child_info.child_type() {
|
||||
ChildType::ParentKeyId => sp_io::default_child_storage::get(
|
||||
child_info.storage_key(),
|
||||
key,
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
/// Put a raw byte slice into storage.
|
||||
pub fn put_raw(
|
||||
storage_key: &[u8],
|
||||
child_info: ChildInfo,
|
||||
child_info: &ChildInfo,
|
||||
key: &[u8],
|
||||
value: &[u8],
|
||||
) {
|
||||
let (data, child_type) = child_info.info();
|
||||
sp_io::storage::child_set(
|
||||
storage_key,
|
||||
data,
|
||||
child_type,
|
||||
key,
|
||||
value,
|
||||
)
|
||||
match child_info.child_type() {
|
||||
ChildType::ParentKeyId => sp_io::default_child_storage::set(
|
||||
child_info.storage_key(),
|
||||
key,
|
||||
value,
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
/// Calculate current child root value.
|
||||
pub fn child_root(
|
||||
storage_key: &[u8],
|
||||
pub fn root(
|
||||
child_info: &ChildInfo,
|
||||
) -> Vec<u8> {
|
||||
sp_io::storage::child_root(
|
||||
storage_key,
|
||||
)
|
||||
match child_info.child_type() {
|
||||
ChildType::ParentKeyId => sp_io::default_child_storage::root(
|
||||
child_info.storage_key(),
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -301,7 +301,7 @@ fn new_test_ext() -> sp_io::TestExternalities {
|
||||
fn storage_instance_independence() {
|
||||
let mut storage = sp_core::storage::Storage {
|
||||
top: std::collections::BTreeMap::new(),
|
||||
children: std::collections::HashMap::new()
|
||||
children_default: std::collections::HashMap::new()
|
||||
};
|
||||
sp_state_machine::BasicExternalities::execute_with_storage(&mut storage, || {
|
||||
module2::Value::<Runtime>::put(0);
|
||||
|
||||
@@ -930,7 +930,7 @@ impl<T: Trait> Module<T> {
|
||||
<Number<T>>::hashed_key().to_vec() => T::BlockNumber::one().encode(),
|
||||
<ParentHash<T>>::hashed_key().to_vec() => [69u8; 32].encode()
|
||||
],
|
||||
children: map![],
|
||||
children_default: map![],
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user