From 42d629d9ea57fb384e030dd0a3630ab2fbfe608a Mon Sep 17 00:00:00 2001 From: HackFisher Date: Sun, 15 Mar 2020 15:50:27 +0800 Subject: [PATCH 1/8] add new merkle mountain range digest item for header --- primitives/runtime/src/generic/digest.rs | 31 ++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/primitives/runtime/src/generic/digest.rs b/primitives/runtime/src/generic/digest.rs index dad3e1fc26b7c..224cc51d6dd20 100644 --- a/primitives/runtime/src/generic/digest.rs +++ b/primitives/runtime/src/generic/digest.rs @@ -108,6 +108,11 @@ pub enum DigestItem { /// native code. ChangesTrieSignal(ChangesTrieSignal), + /// Blockchain history digest item that contains the merkle mountain range root + /// at given block. It is created for providing super light client a commitment + /// of all the previous blocks. + MerkleMountainRangeRoot(Hash), + /// Some other thing. Unsupported and experimental. Other(Vec), } @@ -173,6 +178,10 @@ pub enum DigestItemRef<'a, Hash: 'a> { /// Digest item that contains signal from changes tries manager to the /// native code. ChangesTrieSignal(&'a ChangesTrieSignal), + + /// Reference to `DigestItem::MerkleMountainRangeRoot`. + MerkleMountainRangeRoot(&'a Hash), + /// Any 'non-system' digest item, opaque to the native code. Other(&'a Vec), } @@ -190,6 +199,7 @@ pub enum DigestItemType { Seal = 5, PreRuntime = 6, ChangesTrieSignal = 7, + MerkleMountainRangeRoot = 18, } /// Type of a digest item that contains raw data; this also names the consensus engine ID where @@ -215,6 +225,7 @@ impl DigestItem { DigestItem::Consensus(ref v, ref s) => DigestItemRef::Consensus(v, s), DigestItem::Seal(ref v, ref s) => DigestItemRef::Seal(v, s), DigestItem::ChangesTrieSignal(ref s) => DigestItemRef::ChangesTrieSignal(s), + DigestItem::MerkleMountainRangeRoot(ref v) => DigestItemRef::MerkleMountainRangeRoot(v), DigestItem::Other(ref v) => DigestItemRef::Other(v), } } @@ -244,6 +255,11 @@ impl DigestItem { self.dref().as_changes_trie_signal() } + /// Returns `Some` if the entry is the `MerkleMountainRangeRoot` entry. + pub fn as_merkle_mountain_range_root(&self) -> Option<&Hash> { + self.dref().as_merkle_mountain_range_root() + } + /// Returns Some if `self` is a `DigestItem::Other`. pub fn as_other(&self) -> Option<&[u8]> { match *self { @@ -295,6 +311,9 @@ impl Decode for DigestItem { DigestItemType::ChangesTrieSignal => Ok(DigestItem::ChangesTrieSignal( Decode::decode(input)?, )), + DigestItemType::MerkleMountainRangeRoot => Ok(DigestItem::MerkleMountainRangeRoot( + Decode::decode(input)?, + )), DigestItemType::Other => Ok(DigestItem::Other( Decode::decode(input)?, )), @@ -343,6 +362,14 @@ impl<'a, Hash> DigestItemRef<'a, Hash> { } } + /// Cast this digest item into `MerkleMountainRangeRoot`. + pub fn as_merkle_mountain_range_root(&self) -> Option<&'a Hash> { + match *self { + DigestItemRef::MerkleMountainRangeRoot(ref merkle_mountain_range_root) => Some(merkle_mountain_range_root), + _ => None, + } + } + /// Cast this digest item into `PreRuntime` pub fn as_other(&self) -> Option<&'a [u8]> { match *self { @@ -396,6 +423,10 @@ impl<'a, Hash: Encode> Encode for DigestItemRef<'a, Hash> { DigestItemType::ChangesTrieSignal.encode_to(&mut v); changes_trie_signal.encode_to(&mut v); }, + DigestItemRef::MerkleMountainRangeRoot(merkle_mountain_range_root) => { + DigestItemType::MerkleMountainRangeRoot.encode_to(&mut v); + merkle_mountain_range_root.encode_to(&mut v); + }, DigestItemRef::Other(val) => { DigestItemType::Other.encode_to(&mut v); val.encode_to(&mut v); From 28cf12db216c0cae5f59c461b6ae4840845e595e Mon Sep 17 00:00:00 2001 From: HackFisher Date: Sun, 15 Mar 2020 18:00:16 +0800 Subject: [PATCH 2/8] introduce merkle mountain range lib --- Cargo.lock | 9 + Cargo.toml | 1 + primitives/merkle-mountain-range/Cargo.toml | 20 +++ .../merkle-mountain-range/src/common.rs | 131 +++++++++++++++ primitives/merkle-mountain-range/src/lib.rs | 17 ++ .../merkle-mountain-range/src/merkle_proof.rs | 80 +++++++++ primitives/merkle-mountain-range/src/mmr.rs | 157 ++++++++++++++++++ .../merkle-mountain-range/src/tests/mod.rs | 73 ++++++++ .../src/tests/support.rs | 41 +++++ 9 files changed, 529 insertions(+) create mode 100644 primitives/merkle-mountain-range/Cargo.toml create mode 100644 primitives/merkle-mountain-range/src/common.rs create mode 100644 primitives/merkle-mountain-range/src/lib.rs create mode 100644 primitives/merkle-mountain-range/src/merkle_proof.rs create mode 100644 primitives/merkle-mountain-range/src/mmr.rs create mode 100644 primitives/merkle-mountain-range/src/tests/mod.rs create mode 100644 primitives/merkle-mountain-range/src/tests/support.rs diff --git a/Cargo.lock b/Cargo.lock index 1cb703fd5f713..821e32e83e305 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3182,6 +3182,15 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "71d96e3f3c0b6325d8ccd83c33b28acb183edcb6c67938ba104ec546854b0882" +[[package]] +name = "merkle-mountain-range" +version = "0.1.0" +dependencies = [ + "blake2", + "parity-scale-codec", + "sp-std", +] + [[package]] name = "merlin" version = "1.3.0" diff --git a/Cargo.toml b/Cargo.toml index 0459bc8ebbd6a..82c05e3784ba6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -151,6 +151,7 @@ members = [ "primitives/transaction-pool", "primitives/trie", "primitives/wasm-interface", + "primitives/merkle-mountain-range", "test-utils/client", "test-utils/runtime", "test-utils/runtime/client", diff --git a/primitives/merkle-mountain-range/Cargo.toml b/primitives/merkle-mountain-range/Cargo.toml new file mode 100644 index 0000000000000..633a9c00b6e53 --- /dev/null +++ b/primitives/merkle-mountain-range/Cargo.toml @@ -0,0 +1,20 @@ +[package] +name = "merkle-mountain-range" +version = "0.1.0" +authors = ["Darwinia Network "] +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +blake2 = { version = "0.8.1", default-features = false } +codec = { package = "parity-scale-codec", version = "1.2.0", default-features = false, features = ["derive"] } +sp-std = { version = "2.0.0-alpha.2", default-features = false, path = "../std" } + +[features] +default = ["std"] +std = [ + "codec/std", + "blake2/std", + "sp-std/std", +] diff --git a/primitives/merkle-mountain-range/src/common.rs b/primitives/merkle-mountain-range/src/common.rs new file mode 100644 index 0000000000000..d9d93880dae3d --- /dev/null +++ b/primitives/merkle-mountain-range/src/common.rs @@ -0,0 +1,131 @@ +use blake2::Digest; +// for `vec![]` macro +use sp_std::vec; +use sp_std::vec::Vec; + +const ALL_ONES: usize = usize::max_value(); + +pub type Hash = Vec; + +pub fn peak_map_height(mut index: usize) -> (usize, usize) { + if index == 0 { + return (0, 0); + } + + let mut peak_size = ALL_ONES >> index.leading_zeros(); + let mut bitmap = 0; + while peak_size != 0 { + bitmap <<= 1; + if index >= peak_size { + index -= peak_size; + bitmap |= 1; + } + + peak_size >>= 1; + } + + (bitmap, index) +} + +pub fn peak_indexes(size: usize) -> Vec { + if size == 0 { + return vec![]; + } + + let mut peak_size = ALL_ONES >> size.leading_zeros(); + let mut num_left = size; + let mut sum_prev_peaks = 0; + let mut peaks = vec![]; + + while peak_size != 0 { + if num_left >= peak_size { + sum_prev_peaks += peak_size; + num_left -= peak_size; + + peaks.push(sum_prev_peaks - 1); + } + + peak_size >>= 1; + } + + if num_left > 0 { + vec![] + } else { + peaks + } +} + +#[inline] +pub fn is_leaf(index: usize) -> bool { + bintree_height(index) == 0 +} + +#[inline] +pub fn bintree_height(index: usize) -> usize { + if index == 0 { + 0 + } else { + peak_map_height(index).1 + } +} + +pub fn family_branch(index: usize, last_index: usize) -> Vec<(usize, usize)> { + let (peak_map, height) = peak_map_height(index); + let mut peak = 1 << height; + let mut branch = vec![]; + let mut current = index; + let mut sibling; + while current < last_index { + if (peak_map & peak) != 0 { + current += 1; + sibling = current - 2 * peak; + } else { + current += 2 * peak; + sibling = current - 1; + } + if current > last_index { + break; + } + + branch.push((current, sibling)); + peak <<= 1; + } + + branch +} + +pub fn family(index: usize) -> (usize, usize) { + let (peak_map, height) = peak_map_height(index); + let peak = 1 << height; + + if (peak_map & peak) != 0 { + (index + 1, index + 1 - 2 * peak) + } else { + (index + 2 * peak, index + 2 * peak - 1) + } +} + +#[inline] +pub fn is_left_sibling(index: usize) -> bool { + let (peak_map, height) = peak_map_height(index); + let peak = 1 << height; + (peak_map & peak) == 0 +} + +#[inline] +pub fn leaf_index(n: usize) -> usize { + if n == 0 { + 0 + } else { + 2 * n - n.count_ones() as usize + } +} + +#[inline] +pub fn chain_two_hash(left: H, right: H) -> Hash +where + D: Digest, + H: AsRef<[u8]>, +{ + D::new().chain(left).chain(right).result().to_vec() +} diff --git a/primitives/merkle-mountain-range/src/lib.rs b/primitives/merkle-mountain-range/src/lib.rs new file mode 100644 index 0000000000000..ac21d0d571ae8 --- /dev/null +++ b/primitives/merkle-mountain-range/src/lib.rs @@ -0,0 +1,17 @@ +#![cfg_attr(not(feature = "std"), no_std)] +#![feature(test)] + +#[cfg(all(feature = "std", test))] +extern crate test; + +mod common; +mod merkle_proof; +mod mmr; + +#[allow(unused)] +#[cfg(all(feature = "std", test))] +mod tests; + +pub use common::*; +pub use merkle_proof::MerkleProof; +pub use mmr::MerkleMountainRange; diff --git a/primitives/merkle-mountain-range/src/merkle_proof.rs b/primitives/merkle-mountain-range/src/merkle_proof.rs new file mode 100644 index 0000000000000..32a4ca342a704 --- /dev/null +++ b/primitives/merkle-mountain-range/src/merkle_proof.rs @@ -0,0 +1,80 @@ +use blake2::Digest; +use sp_std::vec::Vec; + +use crate::*; + +#[derive(Clone, Debug)] +pub struct MerkleProof { + pub mmr_size: usize, + // + // λ cargo bench b1 + // Finished bench [optimized] target(s) in 0.00s + // Running target/release/deps/mmr-0c4d672df8c18022 + // + // running 1 test + // test tests::b1 ... bench: 42,015 ns/iter (+/- 23) + // + // test result: ok. 0 passed; 0 failed; 0 ignored; 1 measured; 2 filtered out + pub path: Vec, + // + // λ cargo bench b1 + // Finished bench [optimized] target(s) in 0.00s + // Running target/release/deps/mmr-0c4d672df8c18022 + // + // running 1 test + // test tests::b1 ... bench: 42,299 ns/iter (+/- 37) + // + // test result: ok. 0 passed; 0 failed; 0 ignored; 1 measured; 2 filtered out + // pub path: VecDeque, +} + +impl MerkleProof { + pub fn verify(&self, root: H, hash: H, index: usize) -> bool + where + D: Digest, + H: AsRef<[u8]>, + { + self.clone().verify_consume::(root, hash, index) + } + + fn verify_consume(&mut self, root: H, hash: H, index: usize) -> bool + where + D: Digest, + H: AsRef<[u8]>, + { + let root = root.as_ref(); + let hash = hash.as_ref(); + let peak_indexes = peak_indexes(self.mmr_size); + + if self.path.is_empty() { + return root == hash; + } + + let sibling = self.path.remove(0); + // let sibling = self.path.pop_front().unwrap(); + let sibling = sibling.as_ref(); + let (parent_index, sibling_index) = family(index); + + match peak_indexes.binary_search(&index) { + Ok(x) => { + let parent = if x == peak_indexes.len() - 1 { + chain_two_hash::(sibling, hash) + } else { + chain_two_hash::(hash, sibling) + }; + self.verify::(root, &parent, parent_index) + } + _ if parent_index > self.mmr_size => { + self.verify::(root, &chain_two_hash::(sibling, hash), parent_index) + } + _ => { + let parent = if is_left_sibling(sibling_index) { + chain_two_hash::(sibling, hash) + } else { + chain_two_hash::(hash, sibling) + }; + self.verify::(root, &parent, parent_index) + } + } + } +} diff --git a/primitives/merkle-mountain-range/src/mmr.rs b/primitives/merkle-mountain-range/src/mmr.rs new file mode 100644 index 0000000000000..8c73e7ed4e050 --- /dev/null +++ b/primitives/merkle-mountain-range/src/mmr.rs @@ -0,0 +1,157 @@ +use blake2::Digest; +use codec::{Decode, Encode}; +use sp_std::{borrow::ToOwned, vec::Vec, marker::PhantomData, ops::Index}; + +use crate::*; + +#[derive(Clone, Debug, Default, Encode, Decode)] +pub struct MerkleMountainRange { + hashes: Vec, + _hasher: PhantomData, +} + +impl MerkleMountainRange { + pub fn new(hashes: Vec) -> Self { + Self { + hashes, + _hasher: PhantomData, + } + } + + #[inline] + pub fn len(&self) -> usize { + self.hashes.len() + } + + #[inline] + pub fn is_empty(&self) -> bool { + self.hashes.is_empty() + } + + #[inline] + pub fn get(&self, index: usize) -> Option<&Hash> { + self.hashes.get(index) + } + + #[inline] + pub fn push(&mut self, hash: Hash) -> usize { + self.hashes.push(hash); + self.len() - 1 + } + + pub fn append>(&mut self, hash: H) -> Option { + let hash = hash.as_ref(); + + if self.is_empty() { + return Some(self.push(hash.to_owned())); + } + + let mut index = self.len(); + let (peak_map, height) = peak_map_height(index); + + if height != 0 { + return None; + } + + self.push(hash.to_owned()); + + let mut peak = 1; + while (peak_map & peak) != 0 { + let new_hash = chain_two_hash::(&self[index + 1 - 2 * peak], &self[self.len() - 1]); + self.push(new_hash); + + peak *= 2; + index += 1; + } + + Some(index) + } + + pub fn root(&self) -> Option { + if self.is_empty() { + None + } else { + // TODO: bagging strategy + // Some( + // peak_indexes(self.len()) + // .into_iter() + // .fold(D::new(), |hasher, peak_index| { + // hasher.chain(&self[peak_index]) + // }) + // .result() + // .to_vec(), + // ) + + let mut hash = None; + for peak_index in peak_indexes(self.len()).into_iter().rev() { + hash = match hash { + None => Some(self[peak_index].to_owned()), + Some(right_peak) => Some(chain_two_hash::(&self[peak_index], &right_peak)), + } + } + + hash + } + } + + pub fn to_merkle_proof(&self, index: usize) -> Option { + if !is_leaf(index) { + return None; + } + + let family_branch = family_branch(index, self.len()); + let peak_index = if let Some((current, _)) = family_branch.last() { + *current + } else { + index + }; + let mut path: Vec<_> = family_branch + .into_iter() + .map(|(_, sibling)| self.get(sibling).unwrap().to_owned()) + .collect(); + path.append(&mut self.peak_path(peak_index)); + + Some(MerkleProof { + mmr_size: self.len(), + path, + }) + } + + pub fn peak_path(&self, peak_index: usize) -> Vec { + let mut peaks: Vec<_> = peak_indexes(self.len()) + .into_iter() + .filter(|peak_index_| *peak_index_ < peak_index) + .map(|peak_index| self[peak_index].to_owned()) + .collect(); + if let Some(peak) = self.bag_the_rhs(peak_index) { + peaks.push(peak); + } + peaks.reverse(); + + peaks + } + + pub fn bag_the_rhs(&self, peak_index: usize) -> Option { + let peak_indexes: Vec<_> = peak_indexes(self.len()) + .into_iter() + .filter(|peak_index_| *peak_index_ > peak_index) + .collect(); + let mut hash = None; + for peak_index in peak_indexes.into_iter().rev() { + hash = match hash { + None => Some(self[peak_index].to_owned()), + Some(right_peak) => Some(chain_two_hash::(&self[peak_index], &right_peak)), + } + } + + hash + } +} + +impl Index for MerkleMountainRange { + type Output = Hash; + + fn index(&self, index: usize) -> &Self::Output { + &self.hashes[index] + } +} diff --git a/primitives/merkle-mountain-range/src/tests/mod.rs b/primitives/merkle-mountain-range/src/tests/mod.rs new file mode 100644 index 0000000000000..5ef77be3b995c --- /dev/null +++ b/primitives/merkle-mountain-range/src/tests/mod.rs @@ -0,0 +1,73 @@ +pub mod support; + +use std::time::Instant; + +use blake2::{Blake2b, Digest}; +use test::Bencher; + +use crate::*; +// pub use support::{Digest, *}; + +type Hasher = Blake2b; +// type Hasher = DebugHasher; + +fn mmr_with_count(count: usize) -> MerkleMountainRange { + let mut mmr = MerkleMountainRange::::new(vec![]); + for i in 0..count { + let hash = usize_to_hash(i); + mmr.append(&hash); + } + + mmr +} + +fn usize_to_hash(x: usize) -> Hash { + Hasher::digest(&x.to_le_bytes()).to_vec() +} + +#[test] +fn t1() { + let mmr = mmr_with_count(6); + let a = chain_two_hash::(&mmr[0], &mmr[1]); + let b = chain_two_hash::(&a, &mmr[5]); + let c = chain_two_hash::(&mmr[7], &mmr[8]); + let d = chain_two_hash::(&b, &c); + assert_eq!(mmr.root().unwrap(), d); +} + +#[test] +fn t2() { + let mmr = mmr_with_count(6); + let root = mmr.root().unwrap(); + let index = 0; + let hash = usize_to_hash(index); + let proof = mmr.to_merkle_proof(index).unwrap(); + assert!(proof.verify::(root, hash, index)); +} + +#[bench] +fn b1(b: &mut Bencher) { + let mmr = mmr_with_count(10_000_000); + let index = 23_333; + let mmr_index = leaf_index(index); + let root = mmr.root().unwrap(); + let hash = usize_to_hash(index); + let proof = mmr.to_merkle_proof(mmr_index).unwrap(); + + b.iter(|| assert!(proof.verify::(root.clone(), hash.clone(), mmr_index))); +} + +#[test] +fn b2() { + let mmr = mmr_with_count(100_000_000); + let index = 233_333; + let mmr_index = leaf_index(index); + let root = mmr.root().unwrap(); + let hash = usize_to_hash(index); + + let start = Instant::now(); + let proof = mmr.to_merkle_proof(mmr_index).unwrap(); + proof.verify::(root, hash, mmr_index); + let elapsed = start.elapsed(); + println!("{}", elapsed.as_nanos()); +} diff --git a/primitives/merkle-mountain-range/src/tests/support.rs b/primitives/merkle-mountain-range/src/tests/support.rs new file mode 100644 index 0000000000000..23676e2443457 --- /dev/null +++ b/primitives/merkle-mountain-range/src/tests/support.rs @@ -0,0 +1,41 @@ +pub struct DebugHasher; + +pub trait Digest { + fn new() -> Self; + + fn chain>(self, data: B) -> Self + where + Self: Sized; + + fn result(self) -> Vec; + + fn digest(data: &[u8]) -> Vec; +} + +impl Specify for DebugHasher { + fn new() -> Self { + DebugHasher + } +} + +impl Digest for D { + fn new() -> Self { + ::new() + } + + fn chain>(self, data: B) -> Self { + self + } + + fn result(self) -> Vec { + unimplemented!() + } + + fn digest(data: &[u8]) -> Vec { + unimplemented!() + } +} + +pub trait Specify { + fn new() -> Self; +} From 4209a5281dba50235c46d3a4ec48856a8cf6b8b8 Mon Sep 17 00:00:00 2001 From: HackFisher Date: Sun, 15 Mar 2020 20:11:34 +0800 Subject: [PATCH 3/8] add mmr root to digest in System::finalize(), waiting mmr crate supporting T:Hash to make compile pass --- Cargo.lock | 4 +++- frame/system/Cargo.toml | 5 +++++ frame/system/src/lib.rs | 15 +++++++++++++++ primitives/merkle-mountain-range/Cargo.toml | 2 +- 4 files changed, 24 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 821e32e83e305..2ca7894d2f0a8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1587,9 +1587,11 @@ dependencies = [ name = "frame-system" version = "2.0.0-alpha.3" dependencies = [ + "blake2", "criterion 0.2.11", "frame-support", "impl-trait-for-tuples", + "merkle-mountain-range", "parity-scale-codec", "serde", "sp-core", @@ -3184,7 +3186,7 @@ checksum = "71d96e3f3c0b6325d8ccd83c33b28acb183edcb6c67938ba104ec546854b0882" [[package]] name = "merkle-mountain-range" -version = "0.1.0" +version = "0.2.0" dependencies = [ "blake2", "parity-scale-codec", diff --git a/frame/system/Cargo.toml b/frame/system/Cargo.toml index 4e350be1a90c7..7b94ee97c5a20 100644 --- a/frame/system/Cargo.toml +++ b/frame/system/Cargo.toml @@ -19,6 +19,9 @@ sp-version = { version = "2.0.0-alpha.2", default-features = false, path = "../. frame-support = { version = "2.0.0-alpha.2", default-features = false, path = "../support" } impl-trait-for-tuples = "0.1.3" +merkle-mountain-range = { default-features = false, path = "../../primitives/merkle-mountain-range" } +blake2 = { version = "0.8.1", default-features = false } + [dev-dependencies] criterion = "0.2.11" sp-externalities = { version = "0.8.0-alpha.2", path = "../../primitives/externalities" } @@ -35,6 +38,8 @@ std = [ "frame-support/std", "sp-runtime/std", "sp-version/std", + "merkle-mountain-range/std", + "blake2/std", ] runtime-benchmarks = [] diff --git a/frame/system/src/lib.rs b/frame/system/src/lib.rs index 5f9928d78d0ad..a6386e9502335 100644 --- a/frame/system/src/lib.rs +++ b/frame/system/src/lib.rs @@ -122,6 +122,8 @@ use frame_support::{ }; use codec::{Encode, Decode, FullCodec, EncodeLike}; +use merkle_mountain_range::MerkleMountainRange; + #[cfg(any(feature = "std", test))] use sp_io::TestExternalities; @@ -339,6 +341,9 @@ decl_storage! { /// Hash of the previous block. ParentHash get(fn parent_hash) build(|_| hash69()): T::Hash; + /// MMR struct of the previous blocks, from first(genesis) to parent hash. + MMR get(fn mmr) : MerkleMountainRange; + /// Extrinsics root of the current block, also part of the block header. ExtrinsicsRoot get(fn extrinsics_root): T::Hash; @@ -860,6 +865,16 @@ impl Module { digest.push(item); } + // Update MMR and add mmr root to digest of block header + let mut mmr = ::take(); + mmr.append(parent_hash); + let mmr_root = mmr.root().expect("Failed to calculate merkle mountain range; qed"); + + let mmr_item = generic::DigestItem::MerkleMountainRangeRoot( + mmr_root.into() + ); + digest.push(mmr_item); + // The following fields // // - > diff --git a/primitives/merkle-mountain-range/Cargo.toml b/primitives/merkle-mountain-range/Cargo.toml index 633a9c00b6e53..e94144d7ebdbd 100644 --- a/primitives/merkle-mountain-range/Cargo.toml +++ b/primitives/merkle-mountain-range/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "merkle-mountain-range" -version = "0.1.0" +version = "0.2.0" authors = ["Darwinia Network "] edition = "2018" From f56bcf9aa9978bc3ea5c69a657059389bc122d55 Mon Sep 17 00:00:00 2001 From: HackFisher Date: Mon, 16 Mar 2020 00:04:56 +0800 Subject: [PATCH 4/8] upgrade to use mmr lib from ckb --- Cargo.lock | 20 +-- Cargo.toml | 1 - frame/system/Cargo.toml | 4 +- frame/system/src/lib.rs | 60 ++++++- primitives/merkle-mountain-range/Cargo.toml | 20 --- .../merkle-mountain-range/src/common.rs | 131 --------------- primitives/merkle-mountain-range/src/lib.rs | 17 -- .../merkle-mountain-range/src/merkle_proof.rs | 80 --------- primitives/merkle-mountain-range/src/mmr.rs | 157 ------------------ .../merkle-mountain-range/src/tests/mod.rs | 73 -------- .../src/tests/support.rs | 41 ----- 11 files changed, 65 insertions(+), 539 deletions(-) delete mode 100644 primitives/merkle-mountain-range/Cargo.toml delete mode 100644 primitives/merkle-mountain-range/src/common.rs delete mode 100644 primitives/merkle-mountain-range/src/lib.rs delete mode 100644 primitives/merkle-mountain-range/src/merkle_proof.rs delete mode 100644 primitives/merkle-mountain-range/src/mmr.rs delete mode 100644 primitives/merkle-mountain-range/src/tests/mod.rs delete mode 100644 primitives/merkle-mountain-range/src/tests/support.rs diff --git a/Cargo.lock b/Cargo.lock index 2ca7894d2f0a8..b64c43c6f5b45 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -590,6 +590,14 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "ckb-merkle-mountain-range" +version = "0.3.0" +source = "git+https://github.com/nervosnetwork/merkle-mountain-range.git#ea232474496bdf072d7de33297fd54f1ef8df599" +dependencies = [ + "cfg-if", +] + [[package]] name = "clang-sys" version = "0.28.1" @@ -1587,11 +1595,10 @@ dependencies = [ name = "frame-system" version = "2.0.0-alpha.3" dependencies = [ - "blake2", + "ckb-merkle-mountain-range", "criterion 0.2.11", "frame-support", "impl-trait-for-tuples", - "merkle-mountain-range", "parity-scale-codec", "serde", "sp-core", @@ -3184,15 +3191,6 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "71d96e3f3c0b6325d8ccd83c33b28acb183edcb6c67938ba104ec546854b0882" -[[package]] -name = "merkle-mountain-range" -version = "0.2.0" -dependencies = [ - "blake2", - "parity-scale-codec", - "sp-std", -] - [[package]] name = "merlin" version = "1.3.0" diff --git a/Cargo.toml b/Cargo.toml index 82c05e3784ba6..0459bc8ebbd6a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -151,7 +151,6 @@ members = [ "primitives/transaction-pool", "primitives/trie", "primitives/wasm-interface", - "primitives/merkle-mountain-range", "test-utils/client", "test-utils/runtime", "test-utils/runtime/client", diff --git a/frame/system/Cargo.toml b/frame/system/Cargo.toml index 7b94ee97c5a20..a968b66153658 100644 --- a/frame/system/Cargo.toml +++ b/frame/system/Cargo.toml @@ -19,8 +19,7 @@ sp-version = { version = "2.0.0-alpha.2", default-features = false, path = "../. frame-support = { version = "2.0.0-alpha.2", default-features = false, path = "../support" } impl-trait-for-tuples = "0.1.3" -merkle-mountain-range = { default-features = false, path = "../../primitives/merkle-mountain-range" } -blake2 = { version = "0.8.1", default-features = false } +merkle-mountain-range = { package = "ckb-merkle-mountain-range", git = "https://github.com/nervosnetwork/merkle-mountain-range.git", default-features = false } [dev-dependencies] criterion = "0.2.11" @@ -39,7 +38,6 @@ std = [ "sp-runtime/std", "sp-version/std", "merkle-mountain-range/std", - "blake2/std", ] runtime-benchmarks = [] diff --git a/frame/system/src/lib.rs b/frame/system/src/lib.rs index a6386e9502335..a4e1f53991ee0 100644 --- a/frame/system/src/lib.rs +++ b/frame/system/src/lib.rs @@ -122,7 +122,7 @@ use frame_support::{ }; use codec::{Encode, Decode, FullCodec, EncodeLike}; -use merkle_mountain_range::MerkleMountainRange; +use merkle_mountain_range::{MMR, MMRStore}; #[cfg(any(feature = "std", test))] use sp_io::TestExternalities; @@ -342,7 +342,11 @@ decl_storage! { ParentHash get(fn parent_hash) build(|_| hash69()): T::Hash; /// MMR struct of the previous blocks, from first(genesis) to parent hash. - MMR get(fn mmr) : MerkleMountainRange; + pub MMRList get(fn mmr_list): map hasher(twox_64_concat) u64 => T::Hash; + pub MMRCounter get(fn mmr_counter): u64; + + +// MMR get(fn mmr) : MerkleMountainRange; /// Extrinsics root of the current block, also part of the block header. ExtrinsicsRoot get(fn extrinsics_root): T::Hash; @@ -865,10 +869,14 @@ impl Module { digest.push(item); } + let store = ModuleMMRStore::::default(); + let mut mmr = MMR::<_, MMRMerge, _>::new(::get(), store); // Update MMR and add mmr root to digest of block header - let mut mmr = ::take(); - mmr.append(parent_hash); - let mmr_root = mmr.root().expect("Failed to calculate merkle mountain range; qed"); + mmr.push(parent_hash).expect("Failed to push parent hash to mmr."); + + let mmr_root = mmr.get_root().expect("Failed to calculate merkle mountain range; qed"); + + mmr.commit().expect("Failed to push parent hash to mmr."); let mmr_item = generic::DigestItem::MerkleMountainRangeRoot( mmr_root.into() @@ -1036,6 +1044,48 @@ impl Happened for CallKillAccount { } } +pub struct MMRMerge(PhantomData); + +impl merkle_mountain_range::Merge for MMRMerge { + type Item = T::Hash; + fn merge(lhs: &Self::Item, rhs: &Self::Item) -> Self::Item { + let encoded_vec = vec![lhs, rhs]; + T::Hashing::hash_of(&encoded_vec) + } +} + +pub struct ModuleMMRStore(PhantomData); +impl Default for ModuleMMRStore { + fn default() -> Self { + ModuleMMRStore(sp_std::marker::PhantomData) + } +} + +impl MMRStore for ModuleMMRStore { + fn get_elem(&self, pos: u64) -> merkle_mountain_range::Result> { + Ok(Some(Module::::mmr_list(pos))) + } + + fn append(&mut self, pos: u64, elems: Vec) -> merkle_mountain_range::Result<()> { + let mmr_count = ::get(); + if pos != mmr_count { + // Must be append only. + return Err(merkle_mountain_range::Error::InconsistentStore) + } + + let elems_len = elems.len() as u64; + + for (i, elem) in elems.into_iter().enumerate() { + >::insert(mmr_count + i as u64, elem); + } + + // increment counter + ::put(mmr_count + elems_len); + + Ok(()) + } +} + // Implement StoredMap for a simple single-item, kill-account-on-remove system. This works fine for // storing a single item which is required to not be empty/default for the account to exist. // Anything more complex will need more sophisticated logic. diff --git a/primitives/merkle-mountain-range/Cargo.toml b/primitives/merkle-mountain-range/Cargo.toml deleted file mode 100644 index e94144d7ebdbd..0000000000000 --- a/primitives/merkle-mountain-range/Cargo.toml +++ /dev/null @@ -1,20 +0,0 @@ -[package] -name = "merkle-mountain-range" -version = "0.2.0" -authors = ["Darwinia Network "] -edition = "2018" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] -blake2 = { version = "0.8.1", default-features = false } -codec = { package = "parity-scale-codec", version = "1.2.0", default-features = false, features = ["derive"] } -sp-std = { version = "2.0.0-alpha.2", default-features = false, path = "../std" } - -[features] -default = ["std"] -std = [ - "codec/std", - "blake2/std", - "sp-std/std", -] diff --git a/primitives/merkle-mountain-range/src/common.rs b/primitives/merkle-mountain-range/src/common.rs deleted file mode 100644 index d9d93880dae3d..0000000000000 --- a/primitives/merkle-mountain-range/src/common.rs +++ /dev/null @@ -1,131 +0,0 @@ -use blake2::Digest; -// for `vec![]` macro -use sp_std::vec; -use sp_std::vec::Vec; - -const ALL_ONES: usize = usize::max_value(); - -pub type Hash = Vec; - -pub fn peak_map_height(mut index: usize) -> (usize, usize) { - if index == 0 { - return (0, 0); - } - - let mut peak_size = ALL_ONES >> index.leading_zeros(); - let mut bitmap = 0; - while peak_size != 0 { - bitmap <<= 1; - if index >= peak_size { - index -= peak_size; - bitmap |= 1; - } - - peak_size >>= 1; - } - - (bitmap, index) -} - -pub fn peak_indexes(size: usize) -> Vec { - if size == 0 { - return vec![]; - } - - let mut peak_size = ALL_ONES >> size.leading_zeros(); - let mut num_left = size; - let mut sum_prev_peaks = 0; - let mut peaks = vec![]; - - while peak_size != 0 { - if num_left >= peak_size { - sum_prev_peaks += peak_size; - num_left -= peak_size; - - peaks.push(sum_prev_peaks - 1); - } - - peak_size >>= 1; - } - - if num_left > 0 { - vec![] - } else { - peaks - } -} - -#[inline] -pub fn is_leaf(index: usize) -> bool { - bintree_height(index) == 0 -} - -#[inline] -pub fn bintree_height(index: usize) -> usize { - if index == 0 { - 0 - } else { - peak_map_height(index).1 - } -} - -pub fn family_branch(index: usize, last_index: usize) -> Vec<(usize, usize)> { - let (peak_map, height) = peak_map_height(index); - let mut peak = 1 << height; - let mut branch = vec![]; - let mut current = index; - let mut sibling; - while current < last_index { - if (peak_map & peak) != 0 { - current += 1; - sibling = current - 2 * peak; - } else { - current += 2 * peak; - sibling = current - 1; - } - if current > last_index { - break; - } - - branch.push((current, sibling)); - peak <<= 1; - } - - branch -} - -pub fn family(index: usize) -> (usize, usize) { - let (peak_map, height) = peak_map_height(index); - let peak = 1 << height; - - if (peak_map & peak) != 0 { - (index + 1, index + 1 - 2 * peak) - } else { - (index + 2 * peak, index + 2 * peak - 1) - } -} - -#[inline] -pub fn is_left_sibling(index: usize) -> bool { - let (peak_map, height) = peak_map_height(index); - let peak = 1 << height; - (peak_map & peak) == 0 -} - -#[inline] -pub fn leaf_index(n: usize) -> usize { - if n == 0 { - 0 - } else { - 2 * n - n.count_ones() as usize - } -} - -#[inline] -pub fn chain_two_hash(left: H, right: H) -> Hash -where - D: Digest, - H: AsRef<[u8]>, -{ - D::new().chain(left).chain(right).result().to_vec() -} diff --git a/primitives/merkle-mountain-range/src/lib.rs b/primitives/merkle-mountain-range/src/lib.rs deleted file mode 100644 index ac21d0d571ae8..0000000000000 --- a/primitives/merkle-mountain-range/src/lib.rs +++ /dev/null @@ -1,17 +0,0 @@ -#![cfg_attr(not(feature = "std"), no_std)] -#![feature(test)] - -#[cfg(all(feature = "std", test))] -extern crate test; - -mod common; -mod merkle_proof; -mod mmr; - -#[allow(unused)] -#[cfg(all(feature = "std", test))] -mod tests; - -pub use common::*; -pub use merkle_proof::MerkleProof; -pub use mmr::MerkleMountainRange; diff --git a/primitives/merkle-mountain-range/src/merkle_proof.rs b/primitives/merkle-mountain-range/src/merkle_proof.rs deleted file mode 100644 index 32a4ca342a704..0000000000000 --- a/primitives/merkle-mountain-range/src/merkle_proof.rs +++ /dev/null @@ -1,80 +0,0 @@ -use blake2::Digest; -use sp_std::vec::Vec; - -use crate::*; - -#[derive(Clone, Debug)] -pub struct MerkleProof { - pub mmr_size: usize, - // - // λ cargo bench b1 - // Finished bench [optimized] target(s) in 0.00s - // Running target/release/deps/mmr-0c4d672df8c18022 - // - // running 1 test - // test tests::b1 ... bench: 42,015 ns/iter (+/- 23) - // - // test result: ok. 0 passed; 0 failed; 0 ignored; 1 measured; 2 filtered out - pub path: Vec, - // - // λ cargo bench b1 - // Finished bench [optimized] target(s) in 0.00s - // Running target/release/deps/mmr-0c4d672df8c18022 - // - // running 1 test - // test tests::b1 ... bench: 42,299 ns/iter (+/- 37) - // - // test result: ok. 0 passed; 0 failed; 0 ignored; 1 measured; 2 filtered out - // pub path: VecDeque, -} - -impl MerkleProof { - pub fn verify(&self, root: H, hash: H, index: usize) -> bool - where - D: Digest, - H: AsRef<[u8]>, - { - self.clone().verify_consume::(root, hash, index) - } - - fn verify_consume(&mut self, root: H, hash: H, index: usize) -> bool - where - D: Digest, - H: AsRef<[u8]>, - { - let root = root.as_ref(); - let hash = hash.as_ref(); - let peak_indexes = peak_indexes(self.mmr_size); - - if self.path.is_empty() { - return root == hash; - } - - let sibling = self.path.remove(0); - // let sibling = self.path.pop_front().unwrap(); - let sibling = sibling.as_ref(); - let (parent_index, sibling_index) = family(index); - - match peak_indexes.binary_search(&index) { - Ok(x) => { - let parent = if x == peak_indexes.len() - 1 { - chain_two_hash::(sibling, hash) - } else { - chain_two_hash::(hash, sibling) - }; - self.verify::(root, &parent, parent_index) - } - _ if parent_index > self.mmr_size => { - self.verify::(root, &chain_two_hash::(sibling, hash), parent_index) - } - _ => { - let parent = if is_left_sibling(sibling_index) { - chain_two_hash::(sibling, hash) - } else { - chain_two_hash::(hash, sibling) - }; - self.verify::(root, &parent, parent_index) - } - } - } -} diff --git a/primitives/merkle-mountain-range/src/mmr.rs b/primitives/merkle-mountain-range/src/mmr.rs deleted file mode 100644 index 8c73e7ed4e050..0000000000000 --- a/primitives/merkle-mountain-range/src/mmr.rs +++ /dev/null @@ -1,157 +0,0 @@ -use blake2::Digest; -use codec::{Decode, Encode}; -use sp_std::{borrow::ToOwned, vec::Vec, marker::PhantomData, ops::Index}; - -use crate::*; - -#[derive(Clone, Debug, Default, Encode, Decode)] -pub struct MerkleMountainRange { - hashes: Vec, - _hasher: PhantomData, -} - -impl MerkleMountainRange { - pub fn new(hashes: Vec) -> Self { - Self { - hashes, - _hasher: PhantomData, - } - } - - #[inline] - pub fn len(&self) -> usize { - self.hashes.len() - } - - #[inline] - pub fn is_empty(&self) -> bool { - self.hashes.is_empty() - } - - #[inline] - pub fn get(&self, index: usize) -> Option<&Hash> { - self.hashes.get(index) - } - - #[inline] - pub fn push(&mut self, hash: Hash) -> usize { - self.hashes.push(hash); - self.len() - 1 - } - - pub fn append>(&mut self, hash: H) -> Option { - let hash = hash.as_ref(); - - if self.is_empty() { - return Some(self.push(hash.to_owned())); - } - - let mut index = self.len(); - let (peak_map, height) = peak_map_height(index); - - if height != 0 { - return None; - } - - self.push(hash.to_owned()); - - let mut peak = 1; - while (peak_map & peak) != 0 { - let new_hash = chain_two_hash::(&self[index + 1 - 2 * peak], &self[self.len() - 1]); - self.push(new_hash); - - peak *= 2; - index += 1; - } - - Some(index) - } - - pub fn root(&self) -> Option { - if self.is_empty() { - None - } else { - // TODO: bagging strategy - // Some( - // peak_indexes(self.len()) - // .into_iter() - // .fold(D::new(), |hasher, peak_index| { - // hasher.chain(&self[peak_index]) - // }) - // .result() - // .to_vec(), - // ) - - let mut hash = None; - for peak_index in peak_indexes(self.len()).into_iter().rev() { - hash = match hash { - None => Some(self[peak_index].to_owned()), - Some(right_peak) => Some(chain_two_hash::(&self[peak_index], &right_peak)), - } - } - - hash - } - } - - pub fn to_merkle_proof(&self, index: usize) -> Option { - if !is_leaf(index) { - return None; - } - - let family_branch = family_branch(index, self.len()); - let peak_index = if let Some((current, _)) = family_branch.last() { - *current - } else { - index - }; - let mut path: Vec<_> = family_branch - .into_iter() - .map(|(_, sibling)| self.get(sibling).unwrap().to_owned()) - .collect(); - path.append(&mut self.peak_path(peak_index)); - - Some(MerkleProof { - mmr_size: self.len(), - path, - }) - } - - pub fn peak_path(&self, peak_index: usize) -> Vec { - let mut peaks: Vec<_> = peak_indexes(self.len()) - .into_iter() - .filter(|peak_index_| *peak_index_ < peak_index) - .map(|peak_index| self[peak_index].to_owned()) - .collect(); - if let Some(peak) = self.bag_the_rhs(peak_index) { - peaks.push(peak); - } - peaks.reverse(); - - peaks - } - - pub fn bag_the_rhs(&self, peak_index: usize) -> Option { - let peak_indexes: Vec<_> = peak_indexes(self.len()) - .into_iter() - .filter(|peak_index_| *peak_index_ > peak_index) - .collect(); - let mut hash = None; - for peak_index in peak_indexes.into_iter().rev() { - hash = match hash { - None => Some(self[peak_index].to_owned()), - Some(right_peak) => Some(chain_two_hash::(&self[peak_index], &right_peak)), - } - } - - hash - } -} - -impl Index for MerkleMountainRange { - type Output = Hash; - - fn index(&self, index: usize) -> &Self::Output { - &self.hashes[index] - } -} diff --git a/primitives/merkle-mountain-range/src/tests/mod.rs b/primitives/merkle-mountain-range/src/tests/mod.rs deleted file mode 100644 index 5ef77be3b995c..0000000000000 --- a/primitives/merkle-mountain-range/src/tests/mod.rs +++ /dev/null @@ -1,73 +0,0 @@ -pub mod support; - -use std::time::Instant; - -use blake2::{Blake2b, Digest}; -use test::Bencher; - -use crate::*; -// pub use support::{Digest, *}; - -type Hasher = Blake2b; -// type Hasher = DebugHasher; - -fn mmr_with_count(count: usize) -> MerkleMountainRange { - let mut mmr = MerkleMountainRange::::new(vec![]); - for i in 0..count { - let hash = usize_to_hash(i); - mmr.append(&hash); - } - - mmr -} - -fn usize_to_hash(x: usize) -> Hash { - Hasher::digest(&x.to_le_bytes()).to_vec() -} - -#[test] -fn t1() { - let mmr = mmr_with_count(6); - let a = chain_two_hash::(&mmr[0], &mmr[1]); - let b = chain_two_hash::(&a, &mmr[5]); - let c = chain_two_hash::(&mmr[7], &mmr[8]); - let d = chain_two_hash::(&b, &c); - assert_eq!(mmr.root().unwrap(), d); -} - -#[test] -fn t2() { - let mmr = mmr_with_count(6); - let root = mmr.root().unwrap(); - let index = 0; - let hash = usize_to_hash(index); - let proof = mmr.to_merkle_proof(index).unwrap(); - assert!(proof.verify::(root, hash, index)); -} - -#[bench] -fn b1(b: &mut Bencher) { - let mmr = mmr_with_count(10_000_000); - let index = 23_333; - let mmr_index = leaf_index(index); - let root = mmr.root().unwrap(); - let hash = usize_to_hash(index); - let proof = mmr.to_merkle_proof(mmr_index).unwrap(); - - b.iter(|| assert!(proof.verify::(root.clone(), hash.clone(), mmr_index))); -} - -#[test] -fn b2() { - let mmr = mmr_with_count(100_000_000); - let index = 233_333; - let mmr_index = leaf_index(index); - let root = mmr.root().unwrap(); - let hash = usize_to_hash(index); - - let start = Instant::now(); - let proof = mmr.to_merkle_proof(mmr_index).unwrap(); - proof.verify::(root, hash, mmr_index); - let elapsed = start.elapsed(); - println!("{}", elapsed.as_nanos()); -} diff --git a/primitives/merkle-mountain-range/src/tests/support.rs b/primitives/merkle-mountain-range/src/tests/support.rs deleted file mode 100644 index 23676e2443457..0000000000000 --- a/primitives/merkle-mountain-range/src/tests/support.rs +++ /dev/null @@ -1,41 +0,0 @@ -pub struct DebugHasher; - -pub trait Digest { - fn new() -> Self; - - fn chain>(self, data: B) -> Self - where - Self: Sized; - - fn result(self) -> Vec; - - fn digest(data: &[u8]) -> Vec; -} - -impl Specify for DebugHasher { - fn new() -> Self { - DebugHasher - } -} - -impl Digest for D { - fn new() -> Self { - ::new() - } - - fn chain>(self, data: B) -> Self { - self - } - - fn result(self) -> Vec { - unimplemented!() - } - - fn digest(data: &[u8]) -> Vec { - unimplemented!() - } -} - -pub trait Specify { - fn new() -> Self; -} From 78f12ed2dbfa9dd93224e8b4e09e93d4416966cd Mon Sep 17 00:00:00 2001 From: HackFisher Date: Wed, 18 Mar 2020 19:40:34 +0800 Subject: [PATCH 5/8] move mmr logic to seprate darwinia pallet --- Cargo.lock | 9 ------ frame/system/Cargo.toml | 3 +- frame/system/src/lib.rs | 65 ----------------------------------------- 3 files changed, 1 insertion(+), 76 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b525b1cdaf77e..cb7d7c713b9ed 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -590,14 +590,6 @@ dependencies = [ "wasm-bindgen", ] -[[package]] -name = "ckb-merkle-mountain-range" -version = "0.3.0" -source = "git+https://github.com/nervosnetwork/merkle-mountain-range.git#ea232474496bdf072d7de33297fd54f1ef8df599" -dependencies = [ - "cfg-if", -] - [[package]] name = "clang-sys" version = "0.28.1" @@ -1597,7 +1589,6 @@ dependencies = [ name = "frame-system" version = "2.0.0-alpha.3" dependencies = [ - "ckb-merkle-mountain-range", "criterion 0.2.11", "frame-support", "impl-trait-for-tuples", diff --git a/frame/system/Cargo.toml b/frame/system/Cargo.toml index a968b66153658..d61797610992a 100644 --- a/frame/system/Cargo.toml +++ b/frame/system/Cargo.toml @@ -19,7 +19,7 @@ sp-version = { version = "2.0.0-alpha.2", default-features = false, path = "../. frame-support = { version = "2.0.0-alpha.2", default-features = false, path = "../support" } impl-trait-for-tuples = "0.1.3" -merkle-mountain-range = { package = "ckb-merkle-mountain-range", git = "https://github.com/nervosnetwork/merkle-mountain-range.git", default-features = false } + [dev-dependencies] criterion = "0.2.11" @@ -37,7 +37,6 @@ std = [ "frame-support/std", "sp-runtime/std", "sp-version/std", - "merkle-mountain-range/std", ] runtime-benchmarks = [] diff --git a/frame/system/src/lib.rs b/frame/system/src/lib.rs index 11538e3922041..29167d5b7e268 100644 --- a/frame/system/src/lib.rs +++ b/frame/system/src/lib.rs @@ -122,8 +122,6 @@ use frame_support::{ }; use codec::{Encode, Decode, FullCodec, EncodeLike}; -use merkle_mountain_range::{MMR, MMRStore}; - #[cfg(any(feature = "std", test))] use sp_io::TestExternalities; @@ -368,13 +366,6 @@ decl_storage! { /// Hash of the previous block. ParentHash get(fn parent_hash) build(|_| hash69()): T::Hash; - /// MMR struct of the previous blocks, from first(genesis) to parent hash. - pub MMRList get(fn mmr_list): map hasher(twox_64_concat) u64 => T::Hash; - pub MMRCounter get(fn mmr_counter): u64; - - -// MMR get(fn mmr) : MerkleMountainRange; - /// Extrinsics root of the current block, also part of the block header. ExtrinsicsRoot get(fn extrinsics_root): T::Hash; @@ -903,20 +894,6 @@ impl Module { digest.push(item); } - let store = ModuleMMRStore::::default(); - let mut mmr = MMR::<_, MMRMerge, _>::new(::get(), store); - // Update MMR and add mmr root to digest of block header - mmr.push(parent_hash).expect("Failed to push parent hash to mmr."); - - let mmr_root = mmr.get_root().expect("Failed to calculate merkle mountain range; qed"); - - mmr.commit().expect("Failed to push parent hash to mmr."); - - let mmr_item = generic::DigestItem::MerkleMountainRangeRoot( - mmr_root.into() - ); - digest.push(mmr_item); - // The following fields // // - > @@ -1078,48 +1055,6 @@ impl Happened for CallKillAccount { } } -pub struct MMRMerge(PhantomData); - -impl merkle_mountain_range::Merge for MMRMerge { - type Item = T::Hash; - fn merge(lhs: &Self::Item, rhs: &Self::Item) -> Self::Item { - let encoded_vec = vec![lhs, rhs]; - T::Hashing::hash_of(&encoded_vec) - } -} - -pub struct ModuleMMRStore(PhantomData); -impl Default for ModuleMMRStore { - fn default() -> Self { - ModuleMMRStore(sp_std::marker::PhantomData) - } -} - -impl MMRStore for ModuleMMRStore { - fn get_elem(&self, pos: u64) -> merkle_mountain_range::Result> { - Ok(Some(Module::::mmr_list(pos))) - } - - fn append(&mut self, pos: u64, elems: Vec) -> merkle_mountain_range::Result<()> { - let mmr_count = ::get(); - if pos != mmr_count { - // Must be append only. - return Err(merkle_mountain_range::Error::InconsistentStore) - } - - let elems_len = elems.len() as u64; - - for (i, elem) in elems.into_iter().enumerate() { - >::insert(mmr_count + i as u64, elem); - } - - // increment counter - ::put(mmr_count + elems_len); - - Ok(()) - } -} - // Implement StoredMap for a simple single-item, kill-account-on-remove system. This works fine for // storing a single item which is required to not be empty/default for the account to exist. // Anything more complex will need more sophisticated logic. From 4bf592865e17ace0bb9e76a0266d320a9c6bdb4c Mon Sep 17 00:00:00 2001 From: HackFisher Date: Wed, 18 Mar 2020 19:42:00 +0800 Subject: [PATCH 6/8] remove useless lines --- frame/system/Cargo.toml | 2 -- 1 file changed, 2 deletions(-) diff --git a/frame/system/Cargo.toml b/frame/system/Cargo.toml index d61797610992a..4e350be1a90c7 100644 --- a/frame/system/Cargo.toml +++ b/frame/system/Cargo.toml @@ -19,8 +19,6 @@ sp-version = { version = "2.0.0-alpha.2", default-features = false, path = "../. frame-support = { version = "2.0.0-alpha.2", default-features = false, path = "../support" } impl-trait-for-tuples = "0.1.3" - - [dev-dependencies] criterion = "0.2.11" sp-externalities = { version = "0.8.0-alpha.2", path = "../../primitives/externalities" } From 9d17c9fdabf048cc0826106f0dfc8d7a93daef0d Mon Sep 17 00:00:00 2001 From: HackFisher Date: Fri, 20 Mar 2020 13:00:00 +0800 Subject: [PATCH 7/8] add tests for header mmr digest --- primitives/runtime/src/generic/digest.rs | 5 +++-- primitives/runtime/src/generic/tests.rs | 22 ++++++++++++++++++++++ 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/primitives/runtime/src/generic/digest.rs b/primitives/runtime/src/generic/digest.rs index 224cc51d6dd20..1d106172982a6 100644 --- a/primitives/runtime/src/generic/digest.rs +++ b/primitives/runtime/src/generic/digest.rs @@ -458,13 +458,14 @@ mod tests { logs: vec![ DigestItem::ChangesTrieRoot(4), DigestItem::Other(vec![1, 2, 3]), - DigestItem::Seal(*b"test", vec![1, 2, 3]) + DigestItem::Seal(*b"test", vec![1, 2, 3]), + DigestItem::MerkleMountainRangeRoot(5), ], }; assert_eq!( ::serde_json::to_string(&digest).unwrap(), - r#"{"logs":["0x0204000000","0x000c010203","0x05746573740c010203"]}"# + r#"{"logs":["0x0204000000","0x000c010203","0x05746573740c010203","0x1205000000"]}"# ); } } diff --git a/primitives/runtime/src/generic/tests.rs b/primitives/runtime/src/generic/tests.rs index de2f4a19d99cf..29209ee026504 100644 --- a/primitives/runtime/src/generic/tests.rs +++ b/primitives/runtime/src/generic/tests.rs @@ -58,3 +58,25 @@ fn non_system_digest_item_encoding() { let decoded: DigestItem = Decode::decode(&mut &encoded[..]).unwrap(); assert_eq!(item, decoded); } + +#[test] +fn non_system_mmr_digest_item_encoding() { + let item = DigestItem::MerkleMountainRangeRoot::(H256::default()); + let encoded = item.encode(); + assert_eq!(encoded, vec![ + // type = DigestItemType::ChangesTrieRoot + 18, + // trie root + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + ]); + + let decoded: DigestItem = Decode::decode(&mut &encoded[..]).unwrap(); + assert_eq!(item, decoded); +} From 9ae957714e98d608bb1f43ba81894644fef24297 Mon Sep 17 00:00:00 2001 From: HackFisher Date: Fri, 20 Mar 2020 14:57:18 +0800 Subject: [PATCH 8/8] update test comment --- primitives/runtime/src/generic/tests.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/primitives/runtime/src/generic/tests.rs b/primitives/runtime/src/generic/tests.rs index 29209ee026504..0eee8b794bab1 100644 --- a/primitives/runtime/src/generic/tests.rs +++ b/primitives/runtime/src/generic/tests.rs @@ -64,7 +64,7 @@ fn non_system_mmr_digest_item_encoding() { let item = DigestItem::MerkleMountainRangeRoot::(H256::default()); let encoded = item.encode(); assert_eq!(encoded, vec![ - // type = DigestItemType::ChangesTrieRoot + // type = DigestItemType::MerkleMountainRangeRoot 18, // trie root 0, 0, 0, 0,