Migrate pallet-mmr to the new pallet attribute macro (#9181)

* Migrate pallet-mmr to the new pallet attribute macro

Signed-off-by: koushiro <koushiro.cqx@gmail.com>

* fix typo

Signed-off-by: koushiro <koushiro.cqx@gmail.com>

* use instance macro

Co-authored-by: thiolliere <gui.thiolliere@gmail.com>
This commit is contained in:
Qinxuan Chen
2021-07-15 05:30:31 +08:00
committed by GitHub
parent de2fdd15cb
commit 2e986dd352
11 changed files with 149 additions and 125 deletions
@@ -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"]
@@ -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",
]
@@ -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"
@@ -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;
@@ -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::<T>::on_initialize((b as u32).into());
Pallet::<T, I>::on_initialize((b as u32).into());
}
} verify {
assert_eq!(crate::NumberOfLeaves::<DefaultInstance>::get(), leaves);
assert_eq!(crate::NumberOfLeaves::<T, I>::get(), leaves);
}
}
impl_benchmark_test_suite!(
Module,
Pallet,
crate::tests::new_test_ext(),
crate::mock::Test,
);
@@ -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<I = DefaultInstance>: 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<Output = <Self as Config<I>>::Hash>;
#[pallet::pallet]
#[pallet::generate_store(pub(super) trait Store)]
pub struct Pallet<T, I = ()>(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<<Self as Config<I>>::Hash>;
/// Weights for this pallet.
type WeightInfo: WeightInfo;
}
decl_storage! {
trait Store for Module<T: Config<I>, I: Instance = DefaultInstance> as MerkleMountainRange {
/// Latest MMR Root hash.
pub RootHash get(fn mmr_root_hash): <T as Config<I>>::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<I: 'static = ()>: 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<<T as Config<I>>::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<T: Config<I>, 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<Output = <Self as Config<I>>::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<<Self as Config<I>>::Hash>;
/// Weights for this pallet.
type WeightInfo: WeightInfo;
}
/// Latest MMR Root hash.
#[pallet::storage]
#[pallet::getter(fn mmr_root_hash)]
pub type RootHash<T: Config<I>, I: 'static = ()> = StorageValue<_, <T as Config<I>>::Hash, ValueQuery>;
/// Current size of the MMR (number of leaves).
#[pallet::storage]
#[pallet::getter(fn mmr_leaves)]
pub type NumberOfLeaves<T, I = ()> = 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<T: Config<I>, I: 'static = ()> = StorageMap<
_,
Identity,
u64,
<T as Config<I>>::Hash,
OptionQuery
>;
#[pallet::hooks]
impl<T: Config<I>, I: 'static> Hooks<BlockNumberFor<T>> for Pallet<T, I> {
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.");
<T::OnNewRoot as primitives::OnNewRoot<_>>::on_new_root(&root);
<NumberOfLeaves>::put(leaves);
<NumberOfLeaves<T, I>>::put(leaves);
<RootHash<T, I>>::put(root);
let peaks_after = mmr::utils::NodesUtils::new(leaves).number_of_peaks();
@@ -207,7 +223,7 @@ pub fn verify_leaf_proof<H, L>(
}
}
impl<T: Config<I>, I: Instance> Module<T, I> {
impl<T: Config<I>, I: 'static> Pallet<T, I> {
fn offchain_key(pos: u64) -> sp_std::prelude::Vec<u8> {
(T::INDEXING_PREFIX, pos).encode()
}
@@ -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<H, L>(
/// vs [Off-chain](crate::mmr::storage::OffchainStorage)).
pub struct Mmr<StorageType, T, I, L> where
T: Config<I>,
I: Instance,
I: 'static,
L: primitives::FullLeaf,
Storage<StorageType, T, I, L>: mmr_lib::MMRStore<NodeOf<T, I, L>>,
{
@@ -72,7 +72,7 @@ pub struct Mmr<StorageType, T, I, L> where
impl<StorageType, T, I, L> Mmr<StorageType, T, I, L> where
T: Config<I>,
I: Instance,
I: 'static,
L: primitives::FullLeaf,
Storage<StorageType, T, I, L>: mmr_lib::MMRStore<NodeOf<T, I, L>>,
{
@@ -116,7 +116,7 @@ impl<StorageType, T, I, L> Mmr<StorageType, T, I, L> where
/// Runtime specific MMR functions.
impl<T, I, L> Mmr<RuntimeStorage, T, I, L> where
T: Config<I>,
I: Instance,
I: 'static,
L: primitives::FullLeaf,
{
@@ -145,7 +145,7 @@ impl<T, I, L> Mmr<RuntimeStorage, T, I, L> where
/// Off-chain specific MMR functions.
impl<T, I, L> Mmr<OffchainStorage, T, I, L> where
T: Config<I>,
I: Instance,
I: 'static,
L: primitives::FullLeaf + codec::Decode,
{
/// Generate a proof for given leaf index.
@@ -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<StorageType, T, I, L> Default for Storage<StorageType, T, I, L> {
impl<T, I, L> mmr_lib::MMRStore<NodeOf<T, I, L>> for Storage<OffchainStorage, T, I, L> where
T: Config<I>,
I: Instance,
I: 'static,
L: primitives::FullLeaf + codec::Decode,
{
fn get_elem(&self, pos: u64) -> mmr_lib::Result<Option<NodeOf<T, I, L>>> {
let key = Module::<T, I>::offchain_key(pos);
let key = Pallet::<T, I>::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<T, I, L> mmr_lib::MMRStore<NodeOf<T, I, L>> for Storage<OffchainStorage, T,
impl<T, I, L> mmr_lib::MMRStore<NodeOf<T, I, L>> for Storage<RuntimeStorage, T, I, L> where
T: Config<I>,
I: Instance,
I: 'static,
L: primitives::FullLeaf,
{
fn get_elem(&self, pos: u64) -> mmr_lib::Result<Option<NodeOf<T, I, L>>> {
@@ -84,7 +84,7 @@ impl<T, I, L> mmr_lib::MMRStore<NodeOf<T, I, L>> for Storage<RuntimeStorage, T,
}
fn append(&mut self, pos: u64, elems: Vec<NodeOf<T, I, L>>) -> mmr_lib::Result<()> {
let mut leaves = crate::NumberOfLeaves::<I>::get();
let mut leaves = crate::NumberOfLeaves::<T, I>::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<T, I, L> mmr_lib::MMRStore<NodeOf<T, I, L>> for Storage<RuntimeStorage, T,
// on-chain we only store the hash (even if it's a leaf)
<Nodes<T, I>>::insert(size, elem.hash());
// Indexing API is used to store the full leaf content.
let key = Module::<T, I>::offchain_key(size);
let key = Pallet::<T, I>::offchain_key(size);
elem.using_encoded(|elem| sp_io::offchain_index::set(&key, elem));
size += 1;
@@ -103,7 +103,7 @@ impl<T, I, L> mmr_lib::MMRStore<NodeOf<T, I, L>> for Storage<RuntimeStorage, T,
}
}
NumberOfLeaves::<I>::put(leaves);
NumberOfLeaves::<T, I>::put(leaves);
Ok(())
}
@@ -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 {
@@ -41,7 +41,7 @@ frame_support::construct_runtime!(
UncheckedExtrinsic = UncheckedExtrinsic,
{
System: frame_system::{Pallet, Call, Config, Storage, Event<T>},
MMR: pallet_mmr::{Pallet, Call, Storage},
MMR: pallet_mmr::{Pallet, Storage},
}
);
@@ -91,14 +91,14 @@ fn should_start_empty() {
crate::RootHash::<Test>::get(),
"0000000000000000000000000000000000000000000000000000000000000000".parse().unwrap()
);
assert_eq!(crate::NumberOfLeaves::<DefaultInstance>::get(), 0);
assert_eq!(crate::NumberOfLeaves::<Test>::get(), 0);
assert_eq!(crate::Nodes::<Test>::get(0), None);
// when
let weight = new_block();
// then
assert_eq!(crate::NumberOfLeaves::<DefaultInstance>::get(), 1);
assert_eq!(crate::NumberOfLeaves::<Test>::get(), 1);
assert_eq!(crate::Nodes::<Test>::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::<DefaultInstance>::get(), 2);
assert_eq!(crate::NumberOfLeaves::<Test>::get(), 2);
assert_eq!((
crate::Nodes::<Test>::get(0),
crate::Nodes::<Test>::get(1),
@@ -160,7 +160,7 @@ fn should_construct_larger_mmr_correctly() {
init_chain(7);
// then
assert_eq!(crate::NumberOfLeaves::<DefaultInstance>::get(), 7);
assert_eq!(crate::NumberOfLeaves::<Test>::get(), 7);
assert_eq!((
crate::Nodes::<Test>::get(0),
crate::Nodes::<Test>::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::<DefaultInstance>::get())
let proofs = (0_u64..crate::NumberOfLeaves::<Test>::get())
.into_iter()
.map(|leaf_index| crate::Module::<Test>::generate_proof(leaf_index).unwrap())
.map(|leaf_index| crate::Pallet::<Test>::generate_proof(leaf_index).unwrap())
.collect::<Vec<_>>();
// then
@@ -245,7 +245,7 @@ fn should_verify() {
register_offchain_ext(&mut ext);
let (leaf, proof5) = ext.execute_with(|| {
// when
crate::Module::<Test>::generate_proof(5).unwrap()
crate::Pallet::<Test>::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::<Test>::verify_leaf(leaf, proof5), Ok(()));
assert_eq!(crate::Pallet::<Test>::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::<Test>::generate_proof(5).unwrap()
crate::Pallet::<Test>::generate_proof(5).unwrap()
});
let root = ext.execute_with(|| crate::Module::<Test>::mmr_root_hash());
let root = ext.execute_with(|| crate::Pallet::<Test>::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::<Test>::generate_proof(5).unwrap();
let (leaf, proof5) = crate::Pallet::<Test>::generate_proof(5).unwrap();
new_block();
// then
assert_eq!(crate::Module::<Test>::verify_leaf(leaf, proof5), Ok(()));
assert_eq!(crate::Pallet::<Test>::verify_leaf(leaf, proof5), Ok(()));
});
}