Skip to content
This repository was archived by the owner on Nov 15, 2023. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
9ccf26e
In progress, runtime io must switch to future proof root +
cheme Nov 18, 2019
a0f3818
Switch interface, sr-io seems ok, rpc could use similar interface to
cheme Nov 19, 2019
41c5020
test from previous implementation.
cheme Nov 20, 2019
6eb0414
fix proving test.
cheme Nov 20, 2019
e8e72fc
Restore Keyspacedb from other branch, only apply to child trie.
cheme Nov 20, 2019
88ffbc4
Removing unneeded child_info from child root (child info are stored
cheme Nov 20, 2019
435fcb2
Switch rpc to use same format as ext: more future proof.
cheme Nov 20, 2019
b8c7e37
use root from child info for trie backend essence.
cheme Nov 20, 2019
ee43955
Breaking long lines.
cheme Nov 20, 2019
fe285ae
Merge branch 'master' into child_uuid_step1
cheme Nov 21, 2019
a8818d9
Update doc and clean pr a bit.
cheme Nov 21, 2019
9873dcb
Merge branch 'master' into child_uuid_step1
cheme Nov 23, 2019
609a847
Merge branch 'master' into child_uuid_step1
cheme Nov 25, 2019
7254f6c
Merge branch 'master' into child_uuid_step1
cheme Nov 27, 2019
cac9330
fix error type
cheme Nov 27, 2019
c3b943c
Merge branch 'master' into child_uuid_step1
cheme Nov 28, 2019
c05bc80
Restore removed doc on merge and update sr-io doc.
cheme Nov 28, 2019
cd1e343
Merge branch 'master' into child_uuid_step1
cheme Nov 29, 2019
bdff843
Switch child storage api to use directly unique id, if managed id
cheme Nov 29, 2019
9ce77bb
Clean deprecated host interface from child.
cheme Nov 29, 2019
92c7864
Removing assertion on child info (can fail depending on root
cheme Nov 29, 2019
fc91068
merging child info in the overlay when possible.
cheme Nov 29, 2019
cdabca3
child iteration by prefix using child_info.
cheme Nov 29, 2019
783f389
Merge branch 'master' into child_uuid_step1
cheme Dec 2, 2019
d4c7334
Using ChainInfo in frame support. ChainInfo gets redesign to avoid
cheme Dec 2, 2019
64f4084
Add length of root to the data of child info.
cheme Dec 2, 2019
a87bd48
comments
cheme Dec 2, 2019
68712f9
Encode compact.
cheme Dec 2, 2019
3db467e
Remove child info with root.
cheme Dec 3, 2019
a7425cc
Merge branch 'master' into child_uuid_step1
cheme Dec 3, 2019
8e2b8b9
Fix try_update condition.
cheme Dec 3, 2019
5d74151
Comment Ext child root caching.
cheme Dec 3, 2019
0ba3da5
Replace tuples by struct with field
cheme Dec 5, 2019
d924187
remove StorageTuple alias.
cheme Dec 5, 2019
43da346
Merge branch 'master' into child_uuid_step1
cheme Dec 5, 2019
ead5856
Fix doc tests, and remove StorageOverlay and ChildStorageOverlay
cheme Dec 6, 2019
9e05542
Merge branch 'master' into child_uuid_step1
cheme Dec 8, 2019
6f107d0
Merge branch 'master' into child_uuid_step1
cheme Dec 10, 2019
17dd44d
Merge branch 'master' into child_uuid_step1
cheme Dec 11, 2019
0aaeefa
Merge branch 'master' into child_uuid_step1
cheme Dec 11, 2019
489c9f9
Merge branch 'master' into child_uuid_step1
cheme Dec 11, 2019
c58b539
Merge branch 'master' into child_uuid_step1
cheme Dec 13, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
In progress, runtime io must switch to future proof root +
child_specific (unique id) + u32 type.
  • Loading branch information
cheme committed Nov 18, 2019
commit 9ccf26e4f6bf73cd8261a61d11cb5454471760cd
16 changes: 10 additions & 6 deletions paint/contracts/src/account_db.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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, &blake2_256(location)))
trie_id.and_then(|id| child::get_raw(id, crate::trie_unique_id(&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))
Expand Down Expand Up @@ -173,13 +173,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);
child::kill_storage(&info.trie_id, info.child_trie_unique_id());
<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);
child::kill_storage(&info.trie_id, info.child_trie_unique_id());
AliveContractInfo::<T> {
code_hash,
storage_size: T::StorageSizeOffset::get(),
Expand Down Expand Up @@ -217,14 +217,18 @@ 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[..], &blake2_256(&k)) {
if let Some(value) = child::get_raw(
&new_info.trie_id[..],
new_info.child_trie_unique_id(),
&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[..], &blake2_256(&k), &value[..]);
child::put_raw(&new_info.trie_id[..], new_info.child_trie_unique_id(), &blake2_256(&k), &value[..]);
} else {
child::kill(&new_info.trie_id[..], &blake2_256(&k));
child::kill(&new_info.trie_id[..], new_info.child_trie_unique_id(), &blake2_256(&k));
}
}

Expand Down
42 changes: 36 additions & 6 deletions paint/contracts/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,19 @@ pub struct RawAliveContractInfo<CodeHash, Balance, BlockNumber> {
pub last_write: Option<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) -> Option<&[u8]> {
trie_unique_id(&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]) -> Option<&[u8]> {
let start = CHILD_STORAGE_KEY_PREFIX.len() + b"default:".len();
Some(&trie_id[start ..])
}

pub type TombstoneContractInfo<T> =
RawTombstoneContractInfo<<T as system::Trait>::Hash, <T as system::Trait>::Hashing>;

Expand Down Expand Up @@ -793,8 +806,17 @@ impl<T: Trait> Module<T> {

let key_values_taken = delta.iter()
.filter_map(|key| {
child::get_raw(&origin_contract.trie_id, &blake2_256(key)).map(|value| {
child::kill(&origin_contract.trie_id, &blake2_256(key));
child::get_raw(
&origin_contract.trie_id,
origin_contract.child_trie_unique_id(),
&blake2_256(key),
).map(|value| {
child::kill(
&origin_contract.trie_id,
origin_contract.child_trie_unique_id(),
&blake2_256(key),
);

(key, value)
})
})
Expand All @@ -803,13 +825,21 @@ 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.
&runtime_io::storage::child_root(&origin_contract.trie_id)[..],
code_hash,
&child::child_root(
&origin_contract.trie_id,
origin_contract.child_trie_unique_id(),
)[..],
code_hash,
);

if tombstone != dest_tombstone {
for (key, value) in key_values_taken {
child::put_raw(&origin_contract.trie_id, &blake2_256(key), &value);
child::put_raw(
&origin_contract.trie_id,
origin_contract.child_trie_unique_id(),
&blake2_256(key),
&value,
);
}

return Err("Tombstones don't match");
Expand Down Expand Up @@ -887,7 +917,7 @@ decl_storage! {
impl<T: Trait> OnFreeBalanceZero<T::AccountId> for Module<T> {
fn on_free_balance_zero(who: &T::AccountId) {
if let Some(ContractInfo::Alive(info)) = <ContractInfoOf<T>>::take(who) {
child::kill_storage(&info.trie_id);
child::kill_storage(&info.trie_id, info.child_trie_unique_id());
}
}
}
Expand Down
10 changes: 7 additions & 3 deletions paint/contracts/src/rent.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ use sr_primitives::traits::{Bounded, CheckedDiv, CheckedMul, Saturating, Zero,
SaturatedConversion};
use support::traits::{Currency, ExistenceRequirement, Get, WithdrawReason, OnUnbalanced};
use support::StorageMap;
use support::storage::child;

#[derive(PartialEq, Eq, Copy, Clone)]
#[must_use]
Expand Down Expand Up @@ -99,7 +100,7 @@ fn try_evict_or_and_pay_rent<T: Trait>(
if balance < subsistence_threshold {
// The contract cannot afford to leave a tombstone, so remove the contract info altogether.
<ContractInfoOf<T>>::remove(account);
runtime_io::storage::child_storage_kill(&contract.trie_id);
child::kill_storage(&contract.trie_id, contract.child_trie_unique_id());
return (RentOutcome::Evicted, None);
}

Expand Down Expand Up @@ -146,7 +147,10 @@ fn try_evict_or_and_pay_rent<T: Trait>(
// threshold, so it leaves a tombstone.

// Note: this operation is heavy.
let child_storage_root = runtime_io::storage::child_root(&contract.trie_id);
let child_storage_root = child::child_root(
&contract.trie_id,
contract.child_trie_unique_id(),
);

let tombstone = <TombstoneContractInfo<T>>::new(
&child_storage_root[..],
Expand All @@ -155,7 +159,7 @@ fn try_evict_or_and_pay_rent<T: Trait>(
let tombstone_info = ContractInfo::Tombstone(tombstone);
<ContractInfoOf<T>>::insert(account, &tombstone_info);

runtime_io::storage::child_storage_kill(&contract.trie_id);
child::kill_storage(&contract.trie_id, contract.child_trie_unique_id());

return (RentOutcome::Evicted, Some(tombstone_info));
}
Expand Down
132 changes: 105 additions & 27 deletions paint/support/src/storage/child.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,97 +19,175 @@
//! 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 this is use to avoid key collision between child tries.
//! This unique id management and generation responsability is delegated to paint module.
//! In the future this id could be generated and stored out of chain state, and using None as a parameter will result into this
//! mode of operation.
//!
//! To be able to live with managed unique id it is very important that paint module uses real
//! unique id. If paint use somehow weak id, care should be taken to not conflict to future scheme
//! of managed unique id which will be compact SCALE encoded integer.
//! Empty unique id is also a reserved value (will be use internally for managed unique id as a
//! parameter in runtime io).
// NOTE: could replace unhashed by having only one kind of storage (root being null storage key (storage_key can become Option<&[u8]>).

use crate::rstd::prelude::*;
use codec::{Codec, Encode, Decode};

/// Unique id managed by the system is not implemented yet.
const SOME: &'static str = "Managed child unique ids are not yet implemented";
/// 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], key: &[u8]) -> Option<T> {
runtime_io::storage::child_get(storage_key, key).map(|v| {
pub fn get<T: Decode + Sized>(
storage_key: &[u8],
unique_id: Option<&[u8]>,
key: &[u8],
) -> Option<T> {
runtime_io::storage::child_get(storage_key, unique_id.expect(SOME), key).map(|v| {
Decode::decode(&mut &v[..]).expect("storage is not null, therefore must be a valid type")
})
}

/// 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], key: &[u8]) -> T {
get(storage_key, key).unwrap_or_else(Default::default)
pub fn get_or_default<T: Decode + Sized + Default>(
storage_key: &[u8],
unique_id: Option<&[u8]>,
key: &[u8],
) -> T {
get(storage_key, unique_id, 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], key: &[u8], default_value: T) -> T {
get(storage_key, key).unwrap_or(default_value)
pub fn get_or<T: Decode + Sized>(
storage_key: &[u8],
unique_id: Option<&[u8]>,
key: &[u8],
default_value: T,
) -> T {
get(storage_key, unique_id, 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],
unique_id: Option<&[u8]>,
key: &[u8],
default_value: F,
) -> T {
get(storage_key, key).unwrap_or_else(default_value)
get(storage_key, unique_id, key).unwrap_or_else(default_value)
}

/// Put `value` in storage under `key`.
pub fn put<T: Encode>(storage_key: &[u8], key: &[u8], value: &T) {
value.using_encoded(|slice| runtime_io::storage::child_set(storage_key, key, slice));
pub fn put<T: Encode>(
storage_key: &[u8],
unique_id: Option<&[u8]>,
key: &[u8],
value: &T,
) {
value.using_encoded(|slice|
runtime_io::storage::child_set(storage_key, unique_id.expect(SOME), 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], key: &[u8]) -> Option<T> {
let r = get(storage_key, key);
pub fn take<T: Decode + Sized>(
storage_key: &[u8],
unique_id: Option<&[u8]>,
key: &[u8],
) -> Option<T> {
let r = get(storage_key, unique_id, key);
if r.is_some() {
kill(storage_key, key);
kill(storage_key, unique_id, key);
}
r
}

/// 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], key: &[u8]) -> T {
take(storage_key, key).unwrap_or_else(Default::default)
pub fn take_or_default<T: Codec + Sized + Default>(
storage_key: &[u8],
unique_id: Option<&[u8]>,
key: &[u8],
) -> T {
take(storage_key, unique_id, 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],key: &[u8], default_value: T) -> T {
take(storage_key, key).unwrap_or(default_value)
pub fn take_or<T: Codec + Sized>(
storage_key: &[u8],
unique_id: Option<&[u8]>,
key: &[u8],
default_value: T,
) -> T {
take(storage_key, unique_id, 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],
unique_id: Option<&[u8]>,
key: &[u8],
default_value: F,
) -> T {
take(storage_key, key).unwrap_or_else(default_value)
take(storage_key, unique_id, key).unwrap_or_else(default_value)
}

/// Check to see if `key` has an explicit entry in storage.
pub fn exists(storage_key: &[u8], key: &[u8]) -> bool {
runtime_io::storage::child_read(storage_key, key, &mut [0;0][..], 0).is_some()
pub fn exists(
storage_key: &[u8],
unique_id: Option<&[u8]>,
key: &[u8],
) -> bool {
runtime_io::storage::child_read(
storage_key, unique_id.expect(SOME), key, &mut [0;0][..], 0,
).is_some()
}

/// Remove all `storage_key` key/values
pub fn kill_storage(storage_key: &[u8]) {
runtime_io::storage::child_storage_kill(storage_key)
pub fn kill_storage(
storage_key: &[u8],
unique_id: Option<&[u8]>,
) {
runtime_io::storage::child_storage_kill(storage_key, unique_id.expect(SOME))
}

/// Ensure `key` has no explicit entry in storage.
pub fn kill(storage_key: &[u8], key: &[u8]) {
runtime_io::storage::child_clear(storage_key, key);
pub fn kill(
storage_key: &[u8],
unique_id: Option<&[u8]>,
key: &[u8],
) {
runtime_io::storage::child_clear(storage_key, unique_id.expect(SOME), key);
}

/// Get a Vec of bytes from storage.
pub fn get_raw(storage_key: &[u8], key: &[u8]) -> Option<Vec<u8>> {
runtime_io::storage::child_get(storage_key, key)
pub fn get_raw(
storage_key: &[u8],
unique_id: Option<&[u8]>,
key: &[u8],
) -> Option<Vec<u8>> {
runtime_io::storage::child_get(storage_key, unique_id.expect(SOME), key)
}

/// Put a raw byte slice into storage.
pub fn put_raw(storage_key: &[u8], key: &[u8], value: &[u8]) {
runtime_io::storage::child_set(storage_key, key, value)
pub fn put_raw(
storage_key: &[u8],
unique_id: Option<&[u8]>,
key: &[u8],
value: &[u8],
) {
runtime_io::storage::child_set(storage_key, unique_id.expect(SOME), key, value)
}

/// Calculate current child root value.
pub fn child_root(
storage_key: &[u8],
unique_id: Option<&[u8]>,
) -> Vec<u8> {
runtime_io::storage::child_root(storage_key, unique_id.expect(SOME))
}
Loading