diff --git a/substrate/frame/merkle-mountain-range/Cargo.toml b/substrate/frame/merkle-mountain-range/Cargo.toml index 03b80a3339..28de91b060 100644 --- a/substrate/frame/merkle-mountain-range/Cargo.toml +++ b/substrate/frame/merkle-mountain-range/Cargo.toml @@ -13,16 +13,19 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false } -frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } -frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } -frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } mmr-lib = { package = "ckb-merkle-mountain-range", default-features = false, version = "0.3.1" } -pallet-mmr-primitives = { version = "4.0.0-dev", default-features = false, path = "./primitives" } + sp-core = { version = "4.0.0-dev", default-features = false, path = "../../primitives/core" } sp-io = { version = "4.0.0-dev", default-features = false, path = "../../primitives/io" } sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../primitives/runtime" } sp-std = { version = "4.0.0-dev", default-features = false, path = "../../primitives/std" } +frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } +frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } +frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } + +pallet-mmr-primitives = { version = "4.0.0-dev", default-features = false, path = "./primitives" } + [dev-dependencies] env_logger = "0.8" hex-literal = "0.3" @@ -31,15 +34,15 @@ hex-literal = "0.3" default = ["std"] std = [ "codec/std", - "frame-benchmarking/std", - "frame-support/std", - "frame-system/std", "mmr-lib/std", - "pallet-mmr-primitives/std", "sp-core/std", "sp-io/std", "sp-runtime/std", "sp-std/std", + "frame-benchmarking/std", + "frame-support/std", + "frame-system/std", + "pallet-mmr-primitives/std", ] runtime-benchmarks = ["frame-benchmarking"] try-runtime = ["frame-support/try-runtime"] diff --git a/substrate/frame/merkle-mountain-range/primitives/Cargo.toml b/substrate/frame/merkle-mountain-range/primitives/Cargo.toml index 04b744ffb0..07b2f8ae3a 100644 --- a/substrate/frame/merkle-mountain-range/primitives/Cargo.toml +++ b/substrate/frame/merkle-mountain-range/primitives/Cargo.toml @@ -13,14 +13,16 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false } -frame-support = { version = "4.0.0-dev", default-features = false, path = "../../support" } -frame-system = { version = "4.0.0-dev", default-features = false, path = "../../system" } +log = { version = "0.4.14", default-features = false } serde = { version = "1.0.126", optional = true, features = ["derive"] } + sp-api = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/api" } sp-core = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/core" } sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/runtime" } sp-std = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/std" } -log = { version = "0.4.14", default-features = false } + +frame-support = { version = "4.0.0-dev", default-features = false, path = "../../support" } +frame-system = { version = "4.0.0-dev", default-features = false, path = "../../system" } [dev-dependencies] hex-literal = "0.3" @@ -29,12 +31,12 @@ hex-literal = "0.3" default = ["std"] std = [ "codec/std", - "frame-support/std", - "frame-system/std", + "log/std", "serde", "sp-api/std", "sp-core/std", "sp-runtime/std", "sp-std/std", - "log/std", + "frame-support/std", + "frame-system/std", ] diff --git a/substrate/frame/merkle-mountain-range/rpc/Cargo.toml b/substrate/frame/merkle-mountain-range/rpc/Cargo.toml index b99a8f35c0..637abe60c2 100644 --- a/substrate/frame/merkle-mountain-range/rpc/Cargo.toml +++ b/substrate/frame/merkle-mountain-range/rpc/Cargo.toml @@ -17,13 +17,15 @@ codec = { package = "parity-scale-codec", version = "2.0.0" } jsonrpc-core = "15.1.0" jsonrpc-core-client = "15.1.0" jsonrpc-derive = "15.1.0" -pallet-mmr-primitives = { version = "4.0.0-dev", path = "../primitives" } serde = { version = "1.0.126", features = ["derive"] } + sp-api = { version = "4.0.0-dev", path = "../../../primitives/api" } sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } sp-core = { version = "4.0.0-dev", path = "../../../primitives/core" } sp-rpc = { version = "4.0.0-dev", path = "../../../primitives/rpc" } sp-runtime = { version = "4.0.0-dev", path = "../../../primitives/runtime" } +pallet-mmr-primitives = { version = "4.0.0-dev", path = "../primitives" } + [dev-dependencies] serde_json = "1.0.41" diff --git a/substrate/frame/merkle-mountain-range/rpc/src/lib.rs b/substrate/frame/merkle-mountain-range/rpc/src/lib.rs index 5277f4fa47..fb46fc6280 100644 --- a/substrate/frame/merkle-mountain-range/rpc/src/lib.rs +++ b/substrate/frame/merkle-mountain-range/rpc/src/lib.rs @@ -25,6 +25,7 @@ use codec::{Codec, Encode}; use jsonrpc_core::{Error, ErrorCode, Result}; use jsonrpc_derive::rpc; use serde::{Deserialize, Serialize}; + use sp_api::ProvideRuntimeApi; use sp_blockchain::HeaderBackend; use sp_core::Bytes; diff --git a/substrate/frame/merkle-mountain-range/src/benchmarking.rs b/substrate/frame/merkle-mountain-range/src/benchmarking.rs index f64e2e39aa..af7531a00b 100644 --- a/substrate/frame/merkle-mountain-range/src/benchmarking.rs +++ b/substrate/frame/merkle-mountain-range/src/benchmarking.rs @@ -21,24 +21,24 @@ use crate::*; use frame_support::traits::OnInitialize; -use frame_benchmarking::{benchmarks, impl_benchmark_test_suite}; +use frame_benchmarking::{benchmarks_instance_pallet, impl_benchmark_test_suite}; -benchmarks! { +benchmarks_instance_pallet! { on_initialize { let x in 1 .. 1_000; let leaves = x as u64; }: { for b in 0..leaves { - Module::::on_initialize((b as u32).into()); + Pallet::::on_initialize((b as u32).into()); } } verify { - assert_eq!(crate::NumberOfLeaves::::get(), leaves); + assert_eq!(crate::NumberOfLeaves::::get(), leaves); } } impl_benchmark_test_suite!( - Module, + Pallet, crate::tests::new_test_ext(), crate::mock::Test, ); diff --git a/substrate/frame/merkle-mountain-range/src/lib.rs b/substrate/frame/merkle-mountain-range/src/lib.rs index a8e707c7ac..307326b59b 100644 --- a/substrate/frame/merkle-mountain-range/src/lib.rs +++ b/substrate/frame/merkle-mountain-range/src/lib.rs @@ -58,10 +58,7 @@ #![cfg_attr(not(feature = "std"), no_std)] use codec::Encode; -use frame_support::{ - decl_module, decl_storage, - weights::Weight, -}; +use frame_support::weights::Weight; use sp_runtime::traits; mod default_weights; @@ -74,86 +71,105 @@ mod mock; mod tests; pub use pallet_mmr_primitives as primitives; +pub use pallet::*; pub trait WeightInfo { fn on_initialize(peaks: u64) -> Weight; } -/// This pallet's configuration trait -pub trait Config: frame_system::Config { - /// Prefix for elements stored in the Off-chain DB via Indexing API. - /// - /// Each node of the MMR is inserted both on-chain and off-chain via Indexing API. - /// The former does not store full leaf content, just it's compact version (hash), - /// and some of the inner mmr nodes might be pruned from on-chain storage. - /// The later will contain all the entries in their full form. - /// - /// Each node is stored in the Off-chain DB under key derived from the [`Self::INDEXING_PREFIX`] and - /// it's in-tree index (MMR position). - const INDEXING_PREFIX: &'static [u8]; +#[frame_support::pallet] +pub mod pallet { + use frame_support::pallet_prelude::*; + use frame_system::pallet_prelude::*; + use super::*; - /// A hasher type for MMR. - /// - /// To construct trie nodes that result in merging (bagging) two peaks, depending on the node - /// kind we take either: - /// - The node (hash) itself if it's an inner node. - /// - The hash of SCALE-encoding of the leaf data if it's a leaf node. - /// - /// Then we create a tuple of these two hashes, SCALE-encode it (concatenate) and - /// hash, to obtain a new MMR inner node - the new peak. - type Hashing: traits::Hash>::Hash>; + #[pallet::pallet] + #[pallet::generate_store(pub(super) trait Store)] + pub struct Pallet(PhantomData<(T, I)>); - /// The hashing output type. - /// - /// This type is actually going to be stored in the MMR. - /// Required to be provided again, to satisfy trait bounds for storage items. - type Hash: traits::Member + traits::MaybeSerializeDeserialize + sp_std::fmt::Debug - + sp_std::hash::Hash + AsRef<[u8]> + AsMut<[u8]> + Copy + Default + codec::Codec - + codec::EncodeLike; - - /// Data stored in the leaf nodes. - /// - /// The [LeafData](primitives::LeafDataProvider) is responsible for returning the entire leaf - /// data that will be inserted to the MMR. - /// [LeafDataProvider](primitives::LeafDataProvider)s can be composed into tuples to put - /// multiple elements into the tree. In such a case it might be worth using [primitives::Compact] - /// to make MMR proof for one element of the tuple leaner. - /// - /// Note that the leaf at each block MUST be unique. You may want to include a block hash or block - /// number as an easiest way to ensure that. - type LeafData: primitives::LeafDataProvider; - - /// A hook to act on the new MMR root. - /// - /// For some applications it might be beneficial to make the MMR root available externally - /// apart from having it in the storage. For instance you might output it in the header digest - /// (see [`frame_system::Pallet::deposit_log`]) to make it available for Light Clients. - /// Hook complexity should be `O(1)`. - type OnNewRoot: primitives::OnNewRoot<>::Hash>; - - /// Weights for this pallet. - type WeightInfo: WeightInfo; -} - -decl_storage! { - trait Store for Module, I: Instance = DefaultInstance> as MerkleMountainRange { - /// Latest MMR Root hash. - pub RootHash get(fn mmr_root_hash): >::Hash; - - /// Current size of the MMR (number of leaves). - pub NumberOfLeaves get(fn mmr_leaves): u64; - - /// Hashes of the nodes in the MMR. + /// This pallet's configuration trait + #[pallet::config] + pub trait Config: frame_system::Config { + /// Prefix for elements stored in the Off-chain DB via Indexing API. /// - /// Note this collection only contains MMR peaks, the inner nodes (and leaves) - /// are pruned and only stored in the Offchain DB. - pub Nodes get(fn mmr_peak): map hasher(identity) u64 => Option<>::Hash>; - } -} + /// Each node of the MMR is inserted both on-chain and off-chain via Indexing API. + /// The former does not store full leaf content, just it's compact version (hash), + /// and some of the inner mmr nodes might be pruned from on-chain storage. + /// The latter will contain all the entries in their full form. + /// + /// Each node is stored in the Off-chain DB under key derived from the [`Self::INDEXING_PREFIX`] and + /// it's in-tree index (MMR position). + const INDEXING_PREFIX: &'static [u8]; -decl_module! { - /// A public part of the pallet. - pub struct Module, I: Instance = DefaultInstance> for enum Call where origin: T::Origin { + /// A hasher type for MMR. + /// + /// To construct trie nodes that result in merging (bagging) two peaks, depending on the node + /// kind we take either: + /// - The node (hash) itself if it's an inner node. + /// - The hash of SCALE-encoding of the leaf data if it's a leaf node. + /// + /// Then we create a tuple of these two hashes, SCALE-encode it (concatenate) and + /// hash, to obtain a new MMR inner node - the new peak. + type Hashing: traits::Hash>::Hash>; + + /// The hashing output type. + /// + /// This type is actually going to be stored in the MMR. + /// Required to be provided again, to satisfy trait bounds for storage items. + type Hash: traits::Member + traits::MaybeSerializeDeserialize + sp_std::fmt::Debug + + sp_std::hash::Hash + AsRef<[u8]> + AsMut<[u8]> + Copy + Default + codec::Codec + + codec::EncodeLike; + + /// Data stored in the leaf nodes. + /// + /// The [LeafData](primitives::LeafDataProvider) is responsible for returning the entire leaf + /// data that will be inserted to the MMR. + /// [LeafDataProvider](primitives::LeafDataProvider)s can be composed into tuples to put + /// multiple elements into the tree. In such a case it might be worth using [primitives::Compact] + /// to make MMR proof for one element of the tuple leaner. + /// + /// Note that the leaf at each block MUST be unique. You may want to include a block hash or block + /// number as an easiest way to ensure that. + type LeafData: primitives::LeafDataProvider; + + /// A hook to act on the new MMR root. + /// + /// For some applications it might be beneficial to make the MMR root available externally + /// apart from having it in the storage. For instance you might output it in the header digest + /// (see [`frame_system::Pallet::deposit_log`]) to make it available for Light Clients. + /// Hook complexity should be `O(1)`. + type OnNewRoot: primitives::OnNewRoot<>::Hash>; + + /// Weights for this pallet. + type WeightInfo: WeightInfo; + } + + /// Latest MMR Root hash. + #[pallet::storage] + #[pallet::getter(fn mmr_root_hash)] + pub type RootHash, I: 'static = ()> = StorageValue<_, >::Hash, ValueQuery>; + + /// Current size of the MMR (number of leaves). + #[pallet::storage] + #[pallet::getter(fn mmr_leaves)] + pub type NumberOfLeaves = StorageValue<_, u64, ValueQuery>; + + /// Hashes of the nodes in the MMR. + /// + /// Note this collection only contains MMR peaks, the inner nodes (and leaves) + /// are pruned and only stored in the Offchain DB. + #[pallet::storage] + #[pallet::getter(fn mmr_peak)] + pub type Nodes, I: 'static = ()> = StorageMap< + _, + Identity, + u64, + >::Hash, + OptionQuery + >; + + #[pallet::hooks] + impl, I: 'static> Hooks> for Pallet { fn on_initialize(_n: T::BlockNumber) -> Weight { use primitives::LeafDataProvider; let leaves = Self::mmr_leaves(); @@ -167,7 +183,7 @@ decl_module! { let (leaves, root) = mmr.finalize().expect("MMR finalize never fails."); >::on_new_root(&root); - ::put(leaves); + >::put(leaves); >::put(root); let peaks_after = mmr::utils::NodesUtils::new(leaves).number_of_peaks(); @@ -207,7 +223,7 @@ pub fn verify_leaf_proof( } } -impl, I: Instance> Module { +impl, I: 'static> Pallet { fn offchain_key(pos: u64) -> sp_std::prelude::Vec { (T::INDEXING_PREFIX, pos).encode() } diff --git a/substrate/frame/merkle-mountain-range/src/mmr/mmr.rs b/substrate/frame/merkle-mountain-range/src/mmr/mmr.rs index a3d373bfd2..53b76ba800 100644 --- a/substrate/frame/merkle-mountain-range/src/mmr/mmr.rs +++ b/substrate/frame/merkle-mountain-range/src/mmr/mmr.rs @@ -16,7 +16,7 @@ // limitations under the License. use crate::{ - Config, HashingOf, Instance, + Config, HashingOf, mmr::{ Node, NodeOf, Hasher, storage::{Storage, OffchainStorage, RuntimeStorage}, @@ -58,7 +58,7 @@ pub fn verify_leaf_proof( /// vs [Off-chain](crate::mmr::storage::OffchainStorage)). pub struct Mmr where T: Config, - I: Instance, + I: 'static, L: primitives::FullLeaf, Storage: mmr_lib::MMRStore>, { @@ -72,7 +72,7 @@ pub struct Mmr where impl Mmr where T: Config, - I: Instance, + I: 'static, L: primitives::FullLeaf, Storage: mmr_lib::MMRStore>, { @@ -116,7 +116,7 @@ impl Mmr where /// Runtime specific MMR functions. impl Mmr where T: Config, - I: Instance, + I: 'static, L: primitives::FullLeaf, { @@ -145,7 +145,7 @@ impl Mmr where /// Off-chain specific MMR functions. impl Mmr where T: Config, - I: Instance, + I: 'static, L: primitives::FullLeaf + codec::Decode, { /// Generate a proof for given leaf index. diff --git a/substrate/frame/merkle-mountain-range/src/mmr/storage.rs b/substrate/frame/merkle-mountain-range/src/mmr/storage.rs index 021c0716b1..65fe195566 100644 --- a/substrate/frame/merkle-mountain-range/src/mmr/storage.rs +++ b/substrate/frame/merkle-mountain-range/src/mmr/storage.rs @@ -18,12 +18,12 @@ //! A MMR storage implementations. use codec::Encode; -use crate::mmr::{NodeOf, Node}; -use crate::{NumberOfLeaves, Nodes, Module, Config, Instance, primitives}; -use frame_support::{StorageMap, StorageValue}; #[cfg(not(feature = "std"))] use sp_std::prelude::Vec; +use crate::mmr::{NodeOf, Node}; +use crate::{NumberOfLeaves, Nodes, Pallet, Config, primitives}; + /// A marker type for runtime-specific storage implementation. /// /// Allows appending new items to the MMR and proof verification. @@ -56,11 +56,11 @@ impl Default for Storage { impl mmr_lib::MMRStore> for Storage where T: Config, - I: Instance, + I: 'static, L: primitives::FullLeaf + codec::Decode, { fn get_elem(&self, pos: u64) -> mmr_lib::Result>> { - let key = Module::::offchain_key(pos); + let key = Pallet::::offchain_key(pos); // Retrieve the element from Off-chain DB. Ok(sp_io::offchain ::local_storage_get(sp_core::offchain::StorageKind::PERSISTENT, &key) @@ -74,7 +74,7 @@ impl mmr_lib::MMRStore> for Storage mmr_lib::MMRStore> for Storage where T: Config, - I: Instance, + I: 'static, L: primitives::FullLeaf, { fn get_elem(&self, pos: u64) -> mmr_lib::Result>> { @@ -84,7 +84,7 @@ impl mmr_lib::MMRStore> for Storage>) -> mmr_lib::Result<()> { - let mut leaves = crate::NumberOfLeaves::::get(); + let mut leaves = crate::NumberOfLeaves::::get(); let mut size = crate::mmr::utils::NodesUtils::new(leaves).size(); if pos != size { return Err(mmr_lib::Error::InconsistentStore); @@ -94,7 +94,7 @@ impl mmr_lib::MMRStore> for Storage>::insert(size, elem.hash()); // Indexing API is used to store the full leaf content. - let key = Module::::offchain_key(size); + let key = Pallet::::offchain_key(size); elem.using_encoded(|elem| sp_io::offchain_index::set(&key, elem)); size += 1; @@ -103,7 +103,7 @@ impl mmr_lib::MMRStore> for Storage::put(leaves); + NumberOfLeaves::::put(leaves); Ok(()) } diff --git a/substrate/frame/merkle-mountain-range/src/mmr/utils.rs b/substrate/frame/merkle-mountain-range/src/mmr/utils.rs index e966367b71..34ae6e1a3c 100644 --- a/substrate/frame/merkle-mountain-range/src/mmr/utils.rs +++ b/substrate/frame/merkle-mountain-range/src/mmr/utils.rs @@ -114,7 +114,7 @@ mod tests { let mut mmr = crate::mmr::Mmr::< crate::mmr::storage::RuntimeStorage, crate::mock::Test, - crate::DefaultInstance, + _, _, >::new(0); for i in 0..*s { diff --git a/substrate/frame/merkle-mountain-range/src/mock.rs b/substrate/frame/merkle-mountain-range/src/mock.rs index 0d89021ae9..cfd8212e69 100644 --- a/substrate/frame/merkle-mountain-range/src/mock.rs +++ b/substrate/frame/merkle-mountain-range/src/mock.rs @@ -41,7 +41,7 @@ frame_support::construct_runtime!( UncheckedExtrinsic = UncheckedExtrinsic, { System: frame_system::{Pallet, Call, Config, Storage, Event}, - MMR: pallet_mmr::{Pallet, Call, Storage}, + MMR: pallet_mmr::{Pallet, Storage}, } ); diff --git a/substrate/frame/merkle-mountain-range/src/tests.rs b/substrate/frame/merkle-mountain-range/src/tests.rs index dfaf60ef2e..5640468ac9 100644 --- a/substrate/frame/merkle-mountain-range/src/tests.rs +++ b/substrate/frame/merkle-mountain-range/src/tests.rs @@ -91,14 +91,14 @@ fn should_start_empty() { crate::RootHash::::get(), "0000000000000000000000000000000000000000000000000000000000000000".parse().unwrap() ); - assert_eq!(crate::NumberOfLeaves::::get(), 0); + assert_eq!(crate::NumberOfLeaves::::get(), 0); assert_eq!(crate::Nodes::::get(0), None); // when let weight = new_block(); // then - assert_eq!(crate::NumberOfLeaves::::get(), 1); + assert_eq!(crate::NumberOfLeaves::::get(), 1); assert_eq!(crate::Nodes::::get(0), Some(hex("4320435e8c3318562dba60116bdbcc0b82ffcecb9bb39aae3300cfda3ad0b8b0"))); assert_eq!( @@ -119,7 +119,7 @@ fn should_append_to_mmr_when_on_initialize_is_called() { new_block(); // then - assert_eq!(crate::NumberOfLeaves::::get(), 2); + assert_eq!(crate::NumberOfLeaves::::get(), 2); assert_eq!(( crate::Nodes::::get(0), crate::Nodes::::get(1), @@ -160,7 +160,7 @@ fn should_construct_larger_mmr_correctly() { init_chain(7); // then - assert_eq!(crate::NumberOfLeaves::::get(), 7); + assert_eq!(crate::NumberOfLeaves::::get(), 7); assert_eq!(( crate::Nodes::::get(0), crate::Nodes::::get(10), @@ -186,9 +186,9 @@ fn should_generate_proofs_correctly() { register_offchain_ext(&mut ext); ext.execute_with(|| { // when generate proofs for all leaves - let proofs = (0_u64..crate::NumberOfLeaves::::get()) + let proofs = (0_u64..crate::NumberOfLeaves::::get()) .into_iter() - .map(|leaf_index| crate::Module::::generate_proof(leaf_index).unwrap()) + .map(|leaf_index| crate::Pallet::::generate_proof(leaf_index).unwrap()) .collect::>(); // then @@ -245,7 +245,7 @@ fn should_verify() { register_offchain_ext(&mut ext); let (leaf, proof5) = ext.execute_with(|| { // when - crate::Module::::generate_proof(5).unwrap() + crate::Pallet::::generate_proof(5).unwrap() }); // Now to verify the proof, we really shouldn't require offchain storage or extension. @@ -255,7 +255,7 @@ fn should_verify() { ext2.execute_with(|| { init_chain(7); // then - assert_eq!(crate::Module::::verify_leaf(leaf, proof5), Ok(())); + assert_eq!(crate::Pallet::::verify_leaf(leaf, proof5), Ok(())); }); } @@ -274,9 +274,9 @@ fn verification_should_be_stateless() { register_offchain_ext(&mut ext); let (leaf, proof5) = ext.execute_with(|| { // when - crate::Module::::generate_proof(5).unwrap() + crate::Pallet::::generate_proof(5).unwrap() }); - let root = ext.execute_with(|| crate::Module::::mmr_root_hash()); + let root = ext.execute_with(|| crate::Pallet::::mmr_root_hash()); // Verify proof without relying on any on-chain data. let leaf = crate::primitives::DataOrHash::Data(leaf); @@ -295,10 +295,10 @@ fn should_verify_on_the_next_block_since_there_is_no_pruning_yet() { ext.execute_with(|| { // when - let (leaf, proof5) = crate::Module::::generate_proof(5).unwrap(); + let (leaf, proof5) = crate::Pallet::::generate_proof(5).unwrap(); new_block(); // then - assert_eq!(crate::Module::::verify_leaf(leaf, proof5), Ok(())); + assert_eq!(crate::Pallet::::verify_leaf(leaf, proof5), Ok(())); }); }