Skip to content
This repository was archived by the owner on Nov 15, 2023. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 11 additions & 8 deletions frame/merkle-mountain-range/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -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"]
14 changes: 8 additions & 6 deletions frame/merkle-mountain-range/primitives/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -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",
]
4 changes: 3 additions & 1 deletion frame/merkle-mountain-range/rpc/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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"
1 change: 1 addition & 0 deletions frame/merkle-mountain-range/rpc/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
10 changes: 5 additions & 5 deletions frame/merkle-mountain-range/src/benchmarking.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
);
160 changes: 88 additions & 72 deletions frame/merkle-mountain-range/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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];

/// 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;
#[frame_support::pallet]
pub mod pallet {
use frame_support::pallet_prelude::*;
use frame_system::pallet_prelude::*;
use super::*;

/// 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;
#[pallet::pallet]
#[pallet::generate_store(pub(super) trait Store)]
pub struct Pallet<T, I = ()>(PhantomData<(T, I)>);

/// 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>;
/// 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.
///
/// 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];

/// Weights for this pallet.
type WeightInfo: WeightInfo;
}
/// 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>;

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;
/// 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;

/// Current size of the MMR (number of leaves).
pub NumberOfLeaves get(fn mmr_leaves): u64;
/// 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;

/// Hashes of the nodes in the MMR.
/// A hook to act on the new MMR root.
///
/// 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>;
/// 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_module! {
/// A public part of the pallet.
pub struct Module<T: Config<I>, I: Instance = DefaultInstance> for enum Call where origin: T::Origin {
/// 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();
Expand All @@ -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();
Expand Down Expand Up @@ -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()
}
Expand Down
10 changes: 5 additions & 5 deletions frame/merkle-mountain-range/src/mmr/mmr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
// limitations under the License.

use crate::{
Config, HashingOf, Instance,
Config, HashingOf,
mmr::{
Node, NodeOf, Hasher,
storage::{Storage, OffchainStorage, RuntimeStorage},
Expand Down Expand Up @@ -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>>,
{
Expand All @@ -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>>,
{
Expand Down Expand Up @@ -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,
{

Expand Down Expand Up @@ -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.
Expand Down
Loading