mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-07-19 15:45:41 +00:00
Inner hashing of value in state trie (runtime versioning). (#9732)
* starting * Updated from other branch. * setting flag * flag in storage struct * fix flagging to access and insert. * added todo to fix * also missing serialize meta to storage proof * extract meta. * Isolate old trie layout. * failing test that requires storing in meta when old hash scheme is used. * old hash compatibility * Db migrate. * runing tests with both states when interesting. * fix chain spec test with serde default. * export state (missing trie function). * Pending using new branch, lacking genericity on layout resolution. * extract and set global meta * Update to branch 4 * fix iterator with root flag (no longer insert node). * fix trie root hashing of root * complete basic backend. * Remove old_hash meta from proof that do not use inner_hashing. * fix trie test for empty (force layout on empty deltas). * Root update fix. * debug on meta * Use trie key iteration that do not include value in proofs. * switch default test ext to use inner hash. * small integration test, and fix tx cache mgmt in ext. test failing * Proof scenario at state-machine level. * trace for db upgrade * try different param * act more like iter_from. * Bigger batches. * Update trie dependency. * drafting codec changes and refact * before removing unused branch no value alt hashing. more work todo rename all flag var to alt_hash, and remove extrinsic replace by storage query at every storage_root call. * alt hashing only for branch with value. * fix trie tests * Hash of value include the encoded size. * removing fields(broken) * fix trie_stream to also include value length in inner hash. * triedbmut only using alt type if inner hashing. * trie_stream to also only use alt hashing type when actually alt hashing. * Refactor meta state, logic should work with change of trie treshold. * Remove NoMeta variant. * Remove state_hashed trigger specific functions. * pending switching to using threshold, new storage root api does not make much sense. * refactoring to use state from backend (not possible payload changes). * Applying from previous state * Remove default from storage, genesis need a special build. * rem empty space * Catch problem: when using triedb with default: we should not revert nodes: otherwhise thing as trie codec cannot decode-encode without changing state. * fix compilation * Right logic to avoid switch on reencode when default layout. * Clean up some todos * remove trie meta from root upstream * update upstream and fix benches. * split some long lines. * UPdate trie crate to work with new design. * Finish update to refactored upstream. * update to latest triedb changes. * Clean up. * fix executor test. * rust fmt from master. * rust format. * rustfmt * fix * start host function driven versioning * update state-machine part * still need access to state version from runtime * state hash in mem: wrong * direction likely correct, but passing call to code exec for genesis init seem awkward. * state version serialize in runtime, wrong approach, just initialize it with no threshold for core api < 4 seems more proper. * stateversion from runtime version (core api >= 4). * update trie, fix tests * unused import * clean some TODOs * Require RuntimeVersionOf for executor * use RuntimeVersionOf to resolve genesis state version. * update runtime version test * fix state-machine tests * TODO * Use runtime version from storage wasm with fast sync. * rustfmt * fmt * fix test * revert useless changes. * clean some unused changes * fmt * removing useless trait function. * remove remaining reference to state_hash * fix some imports * Follow chain state version management. * trie update, fix and constant threshold for trie layouts. * update deps * Update to latest trie pr changes. * fix benches * Verify proof requires right layout. * update trie_root * Update trie deps to latest * Update to latest trie versioning * Removing patch * update lock * extrinsic for sc-service-test using layout v0. * Adding RuntimeVersionOf to CallExecutor works. * fmt * error when resolving version and no wasm in storage. * use existing utils to instantiate runtime code. * Patch to delay runtime switch. * Revert "Patch to delay runtime switch." This reverts commit 67e55fee468f1a0cda853f5362b22e0d775786da. * useless closure * remove remaining state_hash variables. * Remove outdated comment * useless inner hash * fmt * fmt and opt-in feature to apply state change. * feature gate core version, use new test feature for node and test node * Use a 'State' api version instead of Core one. * fix merge of test function * use blake macro. * Fix state api (require declaring the api in runtime). * Opt out feature, fix macro for io to select a given version instead of latest. * run test nodes on new state. * fix * Apply review change (docs and error). * fmt * use explicit runtime_interface in doc test * fix ui test * fix doc test * fmt * use default for path and specname when resolving version. * small review related changes. * doc value size requirement. * rename old_state feature * Remove macro changes * feature rename * state version as host function parameter * remove flag for client api * fix tests * switch storage chain proof to V1 * host functions, pass by state version enum * use WrappedRuntimeCode * start * state_version in runtime version * rust fmt * Update storage proof of max size. * fix runtime version rpc test * right intent of convert from compat * fix doc test * fix doc test * split proof * decode without replay, and remove some reexports. * Decode with compatibility by default. * switch state_version to u8. And remove RuntimeVersionBasis. * test * use api when reading embedded version * fix decode with apis * extract core version instead * test fix * unused import * review changes. Co-authored-by: kianenigma <kian@parity.io>
This commit is contained in:
@@ -45,31 +45,43 @@ pub use trie_db::proof::VerifyError;
|
||||
use trie_db::proof::{generate_proof, verify_proof};
|
||||
/// Various re-exports from the `trie-db` crate.
|
||||
pub use trie_db::{
|
||||
nibble_ops, CError, DBValue, Query, Recorder, Trie, TrieConfiguration, TrieDBIterator,
|
||||
nibble_ops,
|
||||
node::{NodePlan, ValuePlan},
|
||||
CError, DBValue, Query, Recorder, Trie, TrieConfiguration, TrieDBIterator, TrieDBKeyIterator,
|
||||
TrieLayout, TrieMut,
|
||||
};
|
||||
/// The Substrate format implementation of `TrieStream`.
|
||||
pub use trie_stream::TrieStream;
|
||||
|
||||
#[derive(Default)]
|
||||
/// substrate trie layout
|
||||
pub struct Layout<H>(sp_std::marker::PhantomData<H>);
|
||||
pub struct LayoutV0<H>(sp_std::marker::PhantomData<H>);
|
||||
|
||||
impl<H: Hasher> TrieLayout for Layout<H> {
|
||||
/// substrate trie layout, with external value nodes.
|
||||
pub struct LayoutV1<H>(sp_std::marker::PhantomData<H>);
|
||||
|
||||
impl<H> TrieLayout for LayoutV0<H>
|
||||
where
|
||||
H: Hasher,
|
||||
{
|
||||
const USE_EXTENSION: bool = false;
|
||||
const ALLOW_EMPTY: bool = true;
|
||||
const MAX_INLINE_VALUE: Option<u32> = None;
|
||||
|
||||
type Hash = H;
|
||||
type Codec = NodeCodec<Self::Hash>;
|
||||
}
|
||||
|
||||
impl<H: Hasher> TrieConfiguration for Layout<H> {
|
||||
impl<H> TrieConfiguration for LayoutV0<H>
|
||||
where
|
||||
H: Hasher,
|
||||
{
|
||||
fn trie_root<I, A, B>(input: I) -> <Self::Hash as Hasher>::Out
|
||||
where
|
||||
I: IntoIterator<Item = (A, B)>,
|
||||
A: AsRef<[u8]> + Ord,
|
||||
B: AsRef<[u8]>,
|
||||
{
|
||||
trie_root::trie_root_no_extension::<H, TrieStream, _, _, _>(input)
|
||||
trie_root::trie_root_no_extension::<H, TrieStream, _, _, _>(input, Self::MAX_INLINE_VALUE)
|
||||
}
|
||||
|
||||
fn trie_root_unhashed<I, A, B>(input: I) -> Vec<u8>
|
||||
@@ -78,7 +90,52 @@ impl<H: Hasher> TrieConfiguration for Layout<H> {
|
||||
A: AsRef<[u8]> + Ord,
|
||||
B: AsRef<[u8]>,
|
||||
{
|
||||
trie_root::unhashed_trie_no_extension::<H, TrieStream, _, _, _>(input)
|
||||
trie_root::unhashed_trie_no_extension::<H, TrieStream, _, _, _>(
|
||||
input,
|
||||
Self::MAX_INLINE_VALUE,
|
||||
)
|
||||
}
|
||||
|
||||
fn encode_index(input: u32) -> Vec<u8> {
|
||||
codec::Encode::encode(&codec::Compact(input))
|
||||
}
|
||||
}
|
||||
|
||||
impl<H> TrieLayout for LayoutV1<H>
|
||||
where
|
||||
H: Hasher,
|
||||
{
|
||||
const USE_EXTENSION: bool = false;
|
||||
const ALLOW_EMPTY: bool = true;
|
||||
const MAX_INLINE_VALUE: Option<u32> = Some(sp_core::storage::TRIE_VALUE_NODE_THRESHOLD);
|
||||
|
||||
type Hash = H;
|
||||
type Codec = NodeCodec<Self::Hash>;
|
||||
}
|
||||
|
||||
impl<H> TrieConfiguration for LayoutV1<H>
|
||||
where
|
||||
H: Hasher,
|
||||
{
|
||||
fn trie_root<I, A, B>(input: I) -> <Self::Hash as Hasher>::Out
|
||||
where
|
||||
I: IntoIterator<Item = (A, B)>,
|
||||
A: AsRef<[u8]> + Ord,
|
||||
B: AsRef<[u8]>,
|
||||
{
|
||||
trie_root::trie_root_no_extension::<H, TrieStream, _, _, _>(input, Self::MAX_INLINE_VALUE)
|
||||
}
|
||||
|
||||
fn trie_root_unhashed<I, A, B>(input: I) -> Vec<u8>
|
||||
where
|
||||
I: IntoIterator<Item = (A, B)>,
|
||||
A: AsRef<[u8]> + Ord,
|
||||
B: AsRef<[u8]>,
|
||||
{
|
||||
trie_root::unhashed_trie_no_extension::<H, TrieStream, _, _, _>(
|
||||
input,
|
||||
Self::MAX_INLINE_VALUE,
|
||||
)
|
||||
}
|
||||
|
||||
fn encode_index(input: u32) -> Vec<u8> {
|
||||
@@ -118,17 +175,22 @@ pub type TrieDBMut<'a, L> = trie_db::TrieDBMut<'a, L>;
|
||||
pub type Lookup<'a, L, Q> = trie_db::Lookup<'a, L, Q>;
|
||||
/// Hash type for a trie layout.
|
||||
pub type TrieHash<L> = <<L as TrieLayout>::Hash as Hasher>::Out;
|
||||
|
||||
/// This module is for non generic definition of trie type.
|
||||
/// Only the `Hasher` trait is generic in this case.
|
||||
pub mod trie_types {
|
||||
pub type Layout<H> = super::Layout<H>;
|
||||
use super::*;
|
||||
|
||||
/// Persistent trie database read-access interface for the a given hasher.
|
||||
pub type TrieDB<'a, H> = super::TrieDB<'a, Layout<H>>;
|
||||
/// Read only V1 and V0 are compatible, thus we always use V1.
|
||||
pub type TrieDB<'a, H> = super::TrieDB<'a, LayoutV1<H>>;
|
||||
/// Persistent trie database write-access interface for the a given hasher.
|
||||
pub type TrieDBMut<'a, H> = super::TrieDBMut<'a, Layout<H>>;
|
||||
pub type TrieDBMutV0<'a, H> = super::TrieDBMut<'a, LayoutV0<H>>;
|
||||
/// Persistent trie database write-access interface for the a given hasher.
|
||||
pub type TrieDBMutV1<'a, H> = super::TrieDBMut<'a, LayoutV1<H>>;
|
||||
/// Querying interface, as in `trie_db` but less generic.
|
||||
pub type Lookup<'a, H, Q> = trie_db::Lookup<'a, Layout<H>, Q>;
|
||||
pub type LookupV0<'a, H, Q> = trie_db::Lookup<'a, LayoutV0<H>, Q>;
|
||||
/// Querying interface, as in `trie_db` but less generic.
|
||||
pub type LookupV1<'a, H, Q> = trie_db::Lookup<'a, LayoutV1<H>, Q>;
|
||||
/// As in `trie_db`, but less generic, error type for the crate.
|
||||
pub type TrieError<H> = trie_db::TrieError<H, super::Error>;
|
||||
}
|
||||
@@ -141,16 +203,18 @@ pub mod trie_types {
|
||||
/// For a key `K` that is included in the `db` a proof of inclusion is generated.
|
||||
/// For a key `K` that is not included in the `db` a proof of non-inclusion is generated.
|
||||
/// These can be later checked in `verify_trie_proof`.
|
||||
pub fn generate_trie_proof<'a, L: TrieConfiguration, I, K, DB>(
|
||||
pub fn generate_trie_proof<'a, L, I, K, DB>(
|
||||
db: &DB,
|
||||
root: TrieHash<L>,
|
||||
keys: I,
|
||||
) -> Result<Vec<Vec<u8>>, Box<TrieError<L>>>
|
||||
where
|
||||
L: TrieConfiguration,
|
||||
I: IntoIterator<Item = &'a K>,
|
||||
K: 'a + AsRef<[u8]>,
|
||||
DB: hash_db::HashDBRef<L::Hash, trie_db::DBValue>,
|
||||
{
|
||||
// Can use default layout (read only).
|
||||
let trie = TrieDB::<L>::new(db, &root)?;
|
||||
generate_proof(&trie, keys)
|
||||
}
|
||||
@@ -163,17 +227,18 @@ where
|
||||
/// checked for inclusion in the proof.
|
||||
/// If the value is omitted (`(key, None)`), this key will be checked for non-inclusion in the
|
||||
/// proof.
|
||||
pub fn verify_trie_proof<'a, L: TrieConfiguration, I, K, V>(
|
||||
pub fn verify_trie_proof<'a, L, I, K, V>(
|
||||
root: &TrieHash<L>,
|
||||
proof: &[Vec<u8>],
|
||||
items: I,
|
||||
) -> Result<(), VerifyError<TrieHash<L>, error::Error>>
|
||||
) -> Result<(), VerifyError<TrieHash<L>, CError<L>>>
|
||||
where
|
||||
L: TrieConfiguration,
|
||||
I: IntoIterator<Item = &'a (K, Option<V>)>,
|
||||
K: 'a + AsRef<[u8]>,
|
||||
V: 'a + AsRef<[u8]>,
|
||||
{
|
||||
verify_proof::<Layout<L::Hash>, _, _, _>(root, proof, items)
|
||||
verify_proof::<L, _, _, _>(root, proof, items)
|
||||
}
|
||||
|
||||
/// Determine a trie root given a hash DB and delta values.
|
||||
@@ -207,28 +272,33 @@ where
|
||||
}
|
||||
|
||||
/// Read a value from the trie.
|
||||
pub fn read_trie_value<L: TrieConfiguration, DB: hash_db::HashDBRef<L::Hash, trie_db::DBValue>>(
|
||||
pub fn read_trie_value<L, DB>(
|
||||
db: &DB,
|
||||
root: &TrieHash<L>,
|
||||
key: &[u8],
|
||||
) -> Result<Option<Vec<u8>>, Box<TrieError<L>>> {
|
||||
TrieDB::<L>::new(&*db, root)?.get(key).map(|x| x.map(|val| val.to_vec()))
|
||||
) -> Result<Option<Vec<u8>>, Box<TrieError<L>>>
|
||||
where
|
||||
L: TrieConfiguration,
|
||||
DB: hash_db::HashDBRef<L::Hash, trie_db::DBValue>,
|
||||
{
|
||||
Ok(TrieDB::<L>::new(&*db, root)?.get(key).map(|x| x.map(|val| val.to_vec()))?)
|
||||
}
|
||||
|
||||
/// Read a value from the trie with given Query.
|
||||
pub fn read_trie_value_with<
|
||||
L: TrieConfiguration,
|
||||
Q: Query<L::Hash, Item = DBValue>,
|
||||
DB: hash_db::HashDBRef<L::Hash, trie_db::DBValue>,
|
||||
>(
|
||||
pub fn read_trie_value_with<L, Q, DB>(
|
||||
db: &DB,
|
||||
root: &TrieHash<L>,
|
||||
key: &[u8],
|
||||
query: Q,
|
||||
) -> Result<Option<Vec<u8>>, Box<TrieError<L>>> {
|
||||
TrieDB::<L>::new(&*db, root)?
|
||||
) -> Result<Option<Vec<u8>>, Box<TrieError<L>>>
|
||||
where
|
||||
L: TrieConfiguration,
|
||||
Q: Query<L::Hash, Item = DBValue>,
|
||||
DB: hash_db::HashDBRef<L::Hash, trie_db::DBValue>,
|
||||
{
|
||||
Ok(TrieDB::<L>::new(&*db, root)?
|
||||
.get_with(key, query)
|
||||
.map(|x| x.map(|val| val.to_vec()))
|
||||
.map(|x| x.map(|val| val.to_vec()))?)
|
||||
}
|
||||
|
||||
/// Determine the empty trie root.
|
||||
@@ -319,7 +389,7 @@ where
|
||||
}
|
||||
|
||||
/// Read a value from the child trie with given query.
|
||||
pub fn read_child_trie_value_with<L: TrieConfiguration, Q: Query<L::Hash, Item = DBValue>, DB>(
|
||||
pub fn read_child_trie_value_with<L, Q, DB>(
|
||||
keyspace: &[u8],
|
||||
db: &DB,
|
||||
root_slice: &[u8],
|
||||
@@ -327,6 +397,8 @@ pub fn read_child_trie_value_with<L: TrieConfiguration, Q: Query<L::Hash, Item =
|
||||
query: Q,
|
||||
) -> Result<Option<Vec<u8>>, Box<TrieError<L>>>
|
||||
where
|
||||
L: TrieConfiguration,
|
||||
Q: Query<L::Hash, Item = DBValue>,
|
||||
DB: hash_db::HashDBRef<L::Hash, trie_db::DBValue>,
|
||||
{
|
||||
let mut root = TrieHash::<L>::default();
|
||||
@@ -444,11 +516,15 @@ where
|
||||
|
||||
/// Constants used into trie simplification codec.
|
||||
mod trie_constants {
|
||||
pub const EMPTY_TRIE: u8 = 0;
|
||||
pub const NIBBLE_SIZE_BOUND: usize = u16::MAX as usize;
|
||||
const FIRST_PREFIX: u8 = 0b_00 << 6;
|
||||
pub const NIBBLE_SIZE_BOUND: usize = u16::max_value() as usize;
|
||||
pub const LEAF_PREFIX_MASK: u8 = 0b_01 << 6;
|
||||
pub const BRANCH_WITHOUT_MASK: u8 = 0b_10 << 6;
|
||||
pub const BRANCH_WITH_MASK: u8 = 0b_11 << 6;
|
||||
pub const EMPTY_TRIE: u8 = FIRST_PREFIX | (0b_00 << 4);
|
||||
pub const ALT_HASHING_LEAF_PREFIX_MASK: u8 = FIRST_PREFIX | (0b_1 << 5);
|
||||
pub const ALT_HASHING_BRANCH_WITH_MASK: u8 = FIRST_PREFIX | (0b_01 << 4);
|
||||
pub const ESCAPE_COMPACT_HEADER: u8 = EMPTY_TRIE | 0b_00_01;
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
@@ -461,7 +537,11 @@ mod tests {
|
||||
use trie_db::{DBValue, NodeCodec as NodeCodecT, Trie, TrieMut};
|
||||
use trie_standardmap::{Alphabet, StandardMap, ValueMode};
|
||||
|
||||
type Layout = super::Layout<Blake2Hasher>;
|
||||
type LayoutV0 = super::LayoutV0<Blake2Hasher>;
|
||||
type LayoutV1 = super::LayoutV1<Blake2Hasher>;
|
||||
|
||||
type MemoryDBMeta<H> =
|
||||
memory_db::MemoryDB<H, memory_db::HashKey<H>, trie_db::DBValue, MemTracker>;
|
||||
|
||||
fn hashed_null_node<T: TrieConfiguration>() -> TrieHash<T> {
|
||||
<T::Codec as NodeCodecT>::hashed_null_node()
|
||||
@@ -473,7 +553,7 @@ mod tests {
|
||||
let d = T::trie_root_unhashed(input.clone());
|
||||
println!("Data: {:#x?}, {:#x?}", d, Blake2Hasher::hash(&d[..]));
|
||||
let persistent = {
|
||||
let mut memdb = MemoryDB::default();
|
||||
let mut memdb = MemoryDBMeta::default();
|
||||
let mut root = Default::default();
|
||||
let mut t = TrieDBMut::<T>::new(&mut memdb, &mut root);
|
||||
for (x, y) in input.iter().rev() {
|
||||
@@ -486,7 +566,7 @@ mod tests {
|
||||
}
|
||||
|
||||
fn check_iteration<T: TrieConfiguration>(input: &Vec<(&[u8], &[u8])>) {
|
||||
let mut memdb = MemoryDB::default();
|
||||
let mut memdb = MemoryDBMeta::default();
|
||||
let mut root = Default::default();
|
||||
{
|
||||
let mut t = TrieDBMut::<T>::new(&mut memdb, &mut root);
|
||||
@@ -506,14 +586,21 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
fn check_input(input: &Vec<(&[u8], &[u8])>) {
|
||||
check_equivalent::<LayoutV0>(input);
|
||||
check_iteration::<LayoutV0>(input);
|
||||
check_equivalent::<LayoutV1>(input);
|
||||
check_iteration::<LayoutV1>(input);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn default_trie_root() {
|
||||
let mut db = MemoryDB::default();
|
||||
let mut root = TrieHash::<Layout>::default();
|
||||
let mut empty = TrieDBMut::<Layout>::new(&mut db, &mut root);
|
||||
let mut root = TrieHash::<LayoutV1>::default();
|
||||
let mut empty = TrieDBMut::<LayoutV1>::new(&mut db, &mut root);
|
||||
empty.commit();
|
||||
let root1 = empty.root().as_ref().to_vec();
|
||||
let root2: Vec<u8> = Layout::trie_root::<_, Vec<u8>, Vec<u8>>(std::iter::empty())
|
||||
let root2: Vec<u8> = LayoutV1::trie_root::<_, Vec<u8>, Vec<u8>>(std::iter::empty())
|
||||
.as_ref()
|
||||
.iter()
|
||||
.cloned()
|
||||
@@ -525,31 +612,27 @@ mod tests {
|
||||
#[test]
|
||||
fn empty_is_equivalent() {
|
||||
let input: Vec<(&[u8], &[u8])> = vec![];
|
||||
check_equivalent::<Layout>(&input);
|
||||
check_iteration::<Layout>(&input);
|
||||
check_input(&input);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn leaf_is_equivalent() {
|
||||
let input: Vec<(&[u8], &[u8])> = vec![(&[0xaa][..], &[0xbb][..])];
|
||||
check_equivalent::<Layout>(&input);
|
||||
check_iteration::<Layout>(&input);
|
||||
check_input(&input);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn branch_is_equivalent() {
|
||||
let input: Vec<(&[u8], &[u8])> =
|
||||
vec![(&[0xaa][..], &[0x10][..]), (&[0xba][..], &[0x11][..])];
|
||||
check_equivalent::<Layout>(&input);
|
||||
check_iteration::<Layout>(&input);
|
||||
check_input(&input);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn extension_and_branch_is_equivalent() {
|
||||
let input: Vec<(&[u8], &[u8])> =
|
||||
vec![(&[0xaa][..], &[0x10][..]), (&[0xab][..], &[0x11][..])];
|
||||
check_equivalent::<Layout>(&input);
|
||||
check_iteration::<Layout>(&input);
|
||||
check_input(&input);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -564,8 +647,7 @@ mod tests {
|
||||
let mut d = st.make();
|
||||
d.sort_by(|&(ref a, _), &(ref b, _)| a.cmp(b));
|
||||
let dr = d.iter().map(|v| (&v.0[..], &v.1[..])).collect();
|
||||
check_equivalent::<Layout>(&dr);
|
||||
check_iteration::<Layout>(&dr);
|
||||
check_input(&dr);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -575,8 +657,7 @@ mod tests {
|
||||
(&[0xaa, 0xaa][..], &[0xaa][..]),
|
||||
(&[0xaa, 0xbb][..], &[0xab][..]),
|
||||
];
|
||||
check_equivalent::<Layout>(&input);
|
||||
check_iteration::<Layout>(&input);
|
||||
check_input(&input);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -589,8 +670,7 @@ mod tests {
|
||||
(&[0xbb, 0xbb][..], &[0xbb][..]),
|
||||
(&[0xbb, 0xcc][..], &[0xbc][..]),
|
||||
];
|
||||
check_equivalent::<Layout>(&input);
|
||||
check_iteration::<Layout>(&input);
|
||||
check_input(&input);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -602,8 +682,7 @@ mod tests {
|
||||
),
|
||||
(&[0xba][..], &[0x11][..]),
|
||||
];
|
||||
check_equivalent::<Layout>(&input);
|
||||
check_iteration::<Layout>(&input);
|
||||
check_input(&input);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -618,15 +697,17 @@ mod tests {
|
||||
&b"ABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABC"[..],
|
||||
),
|
||||
];
|
||||
check_equivalent::<Layout>(&input);
|
||||
check_iteration::<Layout>(&input);
|
||||
check_input(&input);
|
||||
}
|
||||
|
||||
fn populate_trie<'db, T: TrieConfiguration>(
|
||||
fn populate_trie<'db, T>(
|
||||
db: &'db mut dyn HashDB<T::Hash, DBValue>,
|
||||
root: &'db mut TrieHash<T>,
|
||||
v: &[(Vec<u8>, Vec<u8>)],
|
||||
) -> TrieDBMut<'db, T> {
|
||||
) -> TrieDBMut<'db, T>
|
||||
where
|
||||
T: TrieConfiguration,
|
||||
{
|
||||
let mut t = TrieDBMut::<T>::new(db, root);
|
||||
for i in 0..v.len() {
|
||||
let key: &[u8] = &v[i].0;
|
||||
@@ -648,8 +729,12 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn random_should_work() {
|
||||
random_should_work_inner::<LayoutV1>();
|
||||
random_should_work_inner::<LayoutV0>();
|
||||
}
|
||||
fn random_should_work_inner<L: TrieConfiguration>() {
|
||||
let mut seed = <Blake2Hasher as Hasher>::Out::zero();
|
||||
for test_i in 0..10000 {
|
||||
for test_i in 0..10_000 {
|
||||
if test_i % 50 == 0 {
|
||||
println!("{:?} of 10000 stress tests done", test_i);
|
||||
}
|
||||
@@ -662,10 +747,11 @@ mod tests {
|
||||
}
|
||||
.make_with(seed.as_fixed_bytes_mut());
|
||||
|
||||
let real = Layout::trie_root(x.clone());
|
||||
let real = L::trie_root(x.clone());
|
||||
let mut memdb = MemoryDB::default();
|
||||
let mut root = Default::default();
|
||||
let mut memtrie = populate_trie::<Layout>(&mut memdb, &mut root, &x);
|
||||
|
||||
let mut memtrie = populate_trie::<L>(&mut memdb, &mut root, &x);
|
||||
|
||||
memtrie.commit();
|
||||
if *memtrie.root() != real {
|
||||
@@ -677,9 +763,9 @@ mod tests {
|
||||
}
|
||||
}
|
||||
assert_eq!(*memtrie.root(), real);
|
||||
unpopulate_trie::<Layout>(&mut memtrie, &x);
|
||||
unpopulate_trie::<L>(&mut memtrie, &x);
|
||||
memtrie.commit();
|
||||
let hashed_null_node = hashed_null_node::<Layout>();
|
||||
let hashed_null_node = hashed_null_node::<L>();
|
||||
if *memtrie.root() != hashed_null_node {
|
||||
println!("- TRIE MISMATCH");
|
||||
println!("");
|
||||
@@ -699,7 +785,7 @@ mod tests {
|
||||
#[test]
|
||||
fn codec_trie_empty() {
|
||||
let input: Vec<(&[u8], &[u8])> = vec![];
|
||||
let trie = Layout::trie_root_unhashed::<_, _, _>(input);
|
||||
let trie = LayoutV1::trie_root_unhashed(input);
|
||||
println!("trie: {:#x?}", trie);
|
||||
assert_eq!(trie, vec![0x0]);
|
||||
}
|
||||
@@ -707,7 +793,7 @@ mod tests {
|
||||
#[test]
|
||||
fn codec_trie_single_tuple() {
|
||||
let input = vec![(vec![0xaa], vec![0xbb])];
|
||||
let trie = Layout::trie_root_unhashed::<_, _, _>(input);
|
||||
let trie = LayoutV1::trie_root_unhashed(input);
|
||||
println!("trie: {:#x?}", trie);
|
||||
assert_eq!(
|
||||
trie,
|
||||
@@ -723,7 +809,7 @@ mod tests {
|
||||
#[test]
|
||||
fn codec_trie_two_tuples_disjoint_keys() {
|
||||
let input = vec![(&[0x48, 0x19], &[0xfe]), (&[0x13, 0x14], &[0xff])];
|
||||
let trie = Layout::trie_root_unhashed::<_, _, _>(input);
|
||||
let trie = LayoutV1::trie_root_unhashed(input);
|
||||
println!("trie: {:#x?}", trie);
|
||||
let mut ex = Vec::<u8>::new();
|
||||
ex.push(0x80); // branch, no value (0b_10..) no nibble
|
||||
@@ -747,6 +833,10 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn iterator_works() {
|
||||
iterator_works_inner::<LayoutV1>();
|
||||
iterator_works_inner::<LayoutV0>();
|
||||
}
|
||||
fn iterator_works_inner<Layout: TrieConfiguration>() {
|
||||
let pairs = vec![
|
||||
(hex!("0103000000000000000464").to_vec(), hex!("0400000000").to_vec()),
|
||||
(hex!("0103000000000000000469").to_vec(), hex!("0401000000").to_vec()),
|
||||
@@ -777,15 +867,15 @@ mod tests {
|
||||
|
||||
let mut memdb = MemoryDB::default();
|
||||
let mut root = Default::default();
|
||||
populate_trie::<Layout>(&mut memdb, &mut root, &pairs);
|
||||
populate_trie::<LayoutV1>(&mut memdb, &mut root, &pairs);
|
||||
|
||||
let non_included_key: Vec<u8> = hex!("0909").to_vec();
|
||||
let proof =
|
||||
generate_trie_proof::<Layout, _, _, _>(&memdb, root, &[non_included_key.clone()])
|
||||
generate_trie_proof::<LayoutV1, _, _, _>(&memdb, root, &[non_included_key.clone()])
|
||||
.unwrap();
|
||||
|
||||
// Verifying that the K was not included into the trie should work.
|
||||
assert!(verify_trie_proof::<Layout, _, _, Vec<u8>>(
|
||||
assert!(verify_trie_proof::<LayoutV1, _, _, Vec<u8>>(
|
||||
&root,
|
||||
&proof,
|
||||
&[(non_included_key.clone(), None)],
|
||||
@@ -793,7 +883,7 @@ mod tests {
|
||||
.is_ok());
|
||||
|
||||
// Verifying that the K was included into the trie should fail.
|
||||
assert!(verify_trie_proof::<Layout, _, _, Vec<u8>>(
|
||||
assert!(verify_trie_proof::<LayoutV1, _, _, Vec<u8>>(
|
||||
&root,
|
||||
&proof,
|
||||
&[(non_included_key, Some(hex!("1010").to_vec()))],
|
||||
@@ -810,13 +900,13 @@ mod tests {
|
||||
|
||||
let mut memdb = MemoryDB::default();
|
||||
let mut root = Default::default();
|
||||
populate_trie::<Layout>(&mut memdb, &mut root, &pairs);
|
||||
populate_trie::<LayoutV1>(&mut memdb, &mut root, &pairs);
|
||||
|
||||
let proof =
|
||||
generate_trie_proof::<Layout, _, _, _>(&memdb, root, &[pairs[0].0.clone()]).unwrap();
|
||||
generate_trie_proof::<LayoutV1, _, _, _>(&memdb, root, &[pairs[0].0.clone()]).unwrap();
|
||||
|
||||
// Check that a K, V included into the proof are verified.
|
||||
assert!(verify_trie_proof::<Layout, _, _, _>(
|
||||
assert!(verify_trie_proof::<LayoutV1, _, _, _>(
|
||||
&root,
|
||||
&proof,
|
||||
&[(pairs[0].0.clone(), Some(pairs[0].1.clone()))]
|
||||
@@ -824,7 +914,7 @@ mod tests {
|
||||
.is_ok());
|
||||
|
||||
// Absence of the V is not verified with the proof that has K, V included.
|
||||
assert!(verify_trie_proof::<Layout, _, _, Vec<u8>>(
|
||||
assert!(verify_trie_proof::<LayoutV1, _, _, Vec<u8>>(
|
||||
&root,
|
||||
&proof,
|
||||
&[(pairs[0].0.clone(), None)]
|
||||
@@ -832,7 +922,7 @@ mod tests {
|
||||
.is_err());
|
||||
|
||||
// K not included into the trie is not verified.
|
||||
assert!(verify_trie_proof::<Layout, _, _, _>(
|
||||
assert!(verify_trie_proof::<LayoutV1, _, _, _>(
|
||||
&root,
|
||||
&proof,
|
||||
&[(hex!("4242").to_vec(), Some(pairs[0].1.clone()))]
|
||||
@@ -840,7 +930,7 @@ mod tests {
|
||||
.is_err());
|
||||
|
||||
// K included into the trie but not included into the proof is not verified.
|
||||
assert!(verify_trie_proof::<Layout, _, _, _>(
|
||||
assert!(verify_trie_proof::<LayoutV1, _, _, _>(
|
||||
&root,
|
||||
&proof,
|
||||
&[(pairs[1].0.clone(), Some(pairs[1].1.clone()))]
|
||||
@@ -865,13 +955,13 @@ mod tests {
|
||||
.unwrap();
|
||||
|
||||
let proof_db = proof.into_memory_db::<Blake2Hasher>();
|
||||
let first_storage_root = delta_trie_root::<Layout, _, _, _, _, _>(
|
||||
let first_storage_root = delta_trie_root::<LayoutV0, _, _, _, _, _>(
|
||||
&mut proof_db.clone(),
|
||||
storage_root,
|
||||
valid_delta,
|
||||
)
|
||||
.unwrap();
|
||||
let second_storage_root = delta_trie_root::<Layout, _, _, _, _, _>(
|
||||
let second_storage_root = delta_trie_root::<LayoutV0, _, _, _, _, _>(
|
||||
&mut proof_db.clone(),
|
||||
storage_root,
|
||||
invalid_delta,
|
||||
|
||||
Reference in New Issue
Block a user