Fix key collision for child trie (#4162)

* In progress, runtime io must switch to future proof root +
child_specific (unique id) + u32 type.

* Switch interface, sr-io seems ok, rpc could use similar interface to
sr-io, genesis json broken if there is child trie in existing encoding
genesis.

* test from previous implementation.

* fix proving test.

* Restore Keyspacedb from other branch, only apply to child trie.

* Removing unneeded child_info from child root (child info are stored
if things changed, otherwhise the root does not change).

* Switch rpc to use same format as ext: more future proof.

* use root from child info for trie backend essence.

* Breaking long lines.

* Update doc and clean pr a bit.

* fix error type

* Restore removed doc on merge and update sr-io doc.

* Switch child storage api to use directly unique id, if managed id
where to be put in place, the api will change at this time.

* Clean deprecated host interface from child.

* Removing assertion on child info (can fail depending on root
memoization).

* merging child info in the overlay when possible.

* child iteration by prefix using child_info.

* Using ChainInfo in frame support. ChainInfo gets redesign to avoid
buffers allocation on every calls.

* Add length of root to the data of child info.

* comments

* Encode compact.

* Remove child info with root.

* Fix try_update condition.

* Comment Ext child root caching.

* Replace tuples by struct with field

* remove StorageTuple alias.

* Fix doc tests, and remove StorageOverlay and ChildStorageOverlay
aliases.
This commit is contained in:
cheme
2019-12-14 03:11:19 +01:00
committed by Gavin Wood
parent 7121837f84
commit 0ece5d9e17
53 changed files with 2121 additions and 918 deletions
+58 -25
View File
@@ -22,8 +22,8 @@ use std::fs::File;
use std::path::PathBuf;
use std::rc::Rc;
use serde::{Serialize, Deserialize};
use primitives::storage::{StorageKey, StorageData};
use sp_runtime::{BuildStorage, StorageOverlay, ChildrenStorageOverlay};
use primitives::storage::{StorageKey, StorageData, ChildInfo, Storage, StorageChild};
use sp_runtime::BuildStorage;
use serde_json as json;
use crate::RuntimeGenesis;
use network::Multiaddr;
@@ -71,36 +71,62 @@ impl<G: RuntimeGenesis> GenesisSource<G> {
}
impl<'a, G: RuntimeGenesis, E> BuildStorage for &'a ChainSpec<G, E> {
fn build_storage(&self) -> Result<(StorageOverlay, ChildrenStorageOverlay), String> {
fn build_storage(&self) -> Result<Storage, String> {
match self.genesis.resolve()? {
Genesis::Runtime(gc) => gc.build_storage(),
Genesis::Raw(map, children_map) => Ok((
map.into_iter().map(|(k, v)| (k.0, v.0)).collect(),
children_map.into_iter().map(|(sk, map)| (
sk.0,
map.into_iter().map(|(k, v)| (k.0, v.0)).collect(),
)).collect(),
)),
Genesis::Raw(RawGenesis { top: map, children: children_map }) => Ok(Storage {
top: map.into_iter().map(|(k, v)| (k.0, v.0)).collect(),
children: children_map.into_iter().map(|(sk, child_content)| {
let child_info = ChildInfo::resolve_child_info(
child_content.child_type,
child_content.child_info.as_slice(),
).expect("chainspec contains correct content").to_owned();
(
sk.0,
StorageChild {
data: child_content.data.into_iter().map(|(k, v)| (k.0, v.0)).collect(),
child_info,
},
)
}).collect(),
}),
}
}
fn assimilate_storage(
&self,
_: &mut (StorageOverlay, ChildrenStorageOverlay)
_: &mut Storage,
) -> Result<(), String> {
Err("`assimilate_storage` not implemented for `ChainSpec`.".into())
}
}
type GenesisStorage = HashMap<StorageKey, StorageData>;
#[derive(Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
#[serde(deny_unknown_fields)]
struct ChildRawStorage {
data: GenesisStorage,
child_info: Vec<u8>,
child_type: u32,
}
#[derive(Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
#[serde(deny_unknown_fields)]
/// Storage content for genesis block.
struct RawGenesis {
pub top: GenesisStorage,
pub children: HashMap<StorageKey, ChildRawStorage>,
}
#[derive(Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
#[serde(deny_unknown_fields)]
enum Genesis<G> {
Runtime(G),
Raw(
HashMap<StorageKey, StorageData>,
HashMap<StorageKey, HashMap<StorageKey, StorageData>>,
),
Raw(RawGenesis),
}
#[derive(Serialize, Deserialize, Clone, Debug)]
@@ -255,19 +281,26 @@ impl<G: RuntimeGenesis, E: serde::Serialize> ChainSpec<G, E> {
let genesis = match (raw, self.genesis.resolve()?) {
(true, Genesis::Runtime(g)) => {
let storage = g.build_storage()?;
let top = storage.0.into_iter()
let top = storage.top.into_iter()
.map(|(k, v)| (StorageKey(k), StorageData(v)))
.collect();
let children = storage.1.into_iter()
.map(|(sk, child)| (
let children = storage.children.into_iter()
.map(|(sk, child)| {
let info = child.child_info.as_ref();
let (info, ci_type) = info.info();
(
StorageKey(sk),
child.into_iter()
.map(|(k, v)| (StorageKey(k), StorageData(v)))
.collect(),
))
ChildRawStorage {
data: child.data.into_iter()
.map(|(k, v)| (StorageKey(k), StorageData(v)))
.collect(),
child_info: info.to_vec(),
child_type: ci_type,
},
)})
.collect();
Genesis::Raw(top, children)
Genesis::Raw(RawGenesis { top, children })
},
(_, genesis) => genesis,
};
@@ -290,9 +323,9 @@ mod tests {
impl BuildStorage for Genesis {
fn assimilate_storage(
&self,
storage: &mut (StorageOverlay, ChildrenStorageOverlay),
storage: &mut Storage,
) -> Result<(), String> {
storage.0.extend(
storage.top.extend(
self.0.iter().map(|(a, b)| (a.clone().into_bytes(), b.clone().into_bytes()))
);
Ok(())