Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Migrate pallet-mmr to umbrella crate #7081

Open
wants to merge 20 commits into
base: master
Choose a base branch
from
Open
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
8 changes: 1 addition & 7 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

14 changes: 14 additions & 0 deletions prdoc/pr_7081.prdoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# Schema: Polkadot SDK PRDoc Schema (prdoc) v1.0.0
# See doc at https://raw.githubusercontent.com/paritytech/polkadot-sdk/master/prdoc/schema_user.json

title: '[pallet-mmr] Migrate to using frame umbrella crate'

doc:
- audience: Runtime Dev
description: This PR migrates the pallet-mmr to use the frame umbrella crate. This
is part of the ongoing effort to migrate all pallets to use the frame umbrella crate.
The effort is tracked [here](https://github.com/paritytech/polkadot-sdk/issues/6504).

crates:
- name: pallet-mmr
bump: minor
24 changes: 4 additions & 20 deletions substrate/frame/merkle-mountain-range/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,43 +16,27 @@ targets = ["x86_64-unknown-linux-gnu"]

[dependencies]
codec = { workspace = true }
frame-benchmarking = { optional = true, workspace = true }
frame-support = { workspace = true }
frame-system = { workspace = true }
frame = { workspace = true, features = ["runtime"] }
log = { workspace = true }
scale-info = { features = ["derive"], workspace = true }
sp-core = { workspace = true }
sp-io = { workspace = true }
sp-mmr-primitives = { workspace = true }
sp-runtime = { workspace = true }

[dev-dependencies]
array-bytes = { workspace = true, default-features = true }
itertools = { workspace = true }
sp-tracing = { workspace = true, default-features = true }

[features]
default = ["std"]
std = [
"codec/std",
"frame-benchmarking?/std",
"frame-support/std",
"frame-system/std",
"frame/std",
"log/std",
"scale-info/std",
"sp-core/std",
"sp-io/std",
"sp-mmr-primitives/std",
"sp-runtime/std",
]
runtime-benchmarks = [
"frame-benchmarking/runtime-benchmarks",
"frame-support/runtime-benchmarks",
"frame-system/runtime-benchmarks",
"sp-runtime/runtime-benchmarks",
"frame/runtime-benchmarks",
]
try-runtime = [
"frame-support/try-runtime",
"frame-system/try-runtime",
"sp-runtime/try-runtime",
"frame/try-runtime",
]
10 changes: 6 additions & 4 deletions substrate/frame/merkle-mountain-range/src/benchmarking.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,10 @@
#![cfg(feature = "runtime-benchmarks")]

use crate::*;
use frame_benchmarking::v1::benchmarks_instance_pallet;
use frame_support::traits::OnInitialize;
use frame::{
benchmarking::prelude::v1::benchmarks_instance_pallet,
deps::frame_support::traits::OnInitialize,
};

benchmarks_instance_pallet! {
on_initialize {
Expand All @@ -31,10 +33,10 @@ benchmarks_instance_pallet! {

<<T as pallet::Config::<I>>::BenchmarkHelper as BenchmarkHelper>::setup();
for leaf in 0..(leaves - 1) {
Pallet::<T, I>::on_initialize((leaf as u32).into());
<Pallet::<T, I> as OnInitialize<BlockNumberFor<T>>>::on_initialize((leaf as u32).into());
}
}: {
Pallet::<T, I>::on_initialize((leaves as u32 - 1).into());
<Pallet::<T, I> as OnInitialize<BlockNumberFor<T>>>::on_initialize((leaves as u32 - 1).into());
} verify {
assert_eq!(crate::NumberOfLeaves::<T, I>::get(), leaves);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,16 +18,13 @@
//! Default weights for the MMR Pallet
//! This file was not auto-generated.

use frame_support::weights::{
constants::{RocksDbWeight as DbWeight, WEIGHT_REF_TIME_PER_NANOS},
Weight,
};
use frame::{deps::frame_support::weights::constants::*, weights_prelude::*};

impl crate::WeightInfo for () {
fn on_initialize(peaks: u32) -> Weight {
let peaks = u64::from(peaks);
// Reading the parent hash.
let leaf_weight = DbWeight::get().reads(1);
let leaf_weight = RocksDbWeight::get().reads(1);
// Blake2 hash cost.
let hash_weight = Weight::from_parts(2u64 * WEIGHT_REF_TIME_PER_NANOS, 0);
// No-op hook.
Expand All @@ -36,6 +33,6 @@ impl crate::WeightInfo for () {
leaf_weight
.saturating_add(hash_weight)
.saturating_add(hook_weight)
.saturating_add(DbWeight::get().reads_writes(2 + peaks, 2 + peaks))
.saturating_add(RocksDbWeight::get().reads_writes(2 + peaks, 2 + peaks))
}
}
85 changes: 39 additions & 46 deletions substrate/frame/merkle-mountain-range/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,20 +59,17 @@
extern crate alloc;

use alloc::vec::Vec;
use frame_support::weights::Weight;
use frame_system::pallet_prelude::{BlockNumberFor, HeaderFor};
use log;
use sp_mmr_primitives::utils;
use sp_runtime::{
traits::{self, One, Saturating},
SaturatedConversion,
};

pub use pallet::*;
use frame::prelude::*;

pub use sp_mmr_primitives::{
self as primitives, utils::NodesUtils, Error, LeafDataProvider, LeafIndex, NodeIndex,
self as primitives, utils, utils::NodesUtils, AncestryProof, Error, FullLeaf, LeafDataProvider,
LeafIndex, LeafProof, NodeIndex, OnNewRoot,
};

pub use pallet::*;

#[cfg(feature = "runtime-benchmarks")]
mod benchmarking;
mod default_weights;
Expand All @@ -90,11 +87,11 @@ mod tests;
/// crate-local wrapper over [frame_system::Pallet]. Since the current block hash
/// is not available (since the block is not finished yet),
/// we use the `parent_hash` here along with parent block number.
pub struct ParentNumberAndHash<T: frame_system::Config> {
_phantom: core::marker::PhantomData<T>,
pub struct ParentNumberAndHash<T: Config> {
gui1117 marked this conversation as resolved.
Show resolved Hide resolved
_phantom: PhantomData<T>,
}

impl<T: frame_system::Config> LeafDataProvider for ParentNumberAndHash<T> {
impl<T: Config> LeafDataProvider for ParentNumberAndHash<T> {
gui1117 marked this conversation as resolved.
Show resolved Hide resolved
type LeafData = (BlockNumberFor<T>, <T as frame_system::Config>::Hash);

fn leaf_data() -> Self::LeafData {
Expand All @@ -111,13 +108,11 @@ pub trait BlockHashProvider<BlockNumber, BlockHash> {
}

/// Default implementation of BlockHashProvider using frame_system.
pub struct DefaultBlockHashProvider<T: frame_system::Config> {
pub struct DefaultBlockHashProvider<T: Config> {
gui1117 marked this conversation as resolved.
Show resolved Hide resolved
_phantom: core::marker::PhantomData<T>,
}

impl<T: frame_system::Config> BlockHashProvider<BlockNumberFor<T>, T::Hash>
for DefaultBlockHashProvider<T>
{
impl<T: Config> BlockHashProvider<BlockNumberFor<T>, T::Hash> for DefaultBlockHashProvider<T> {
gui1117 marked this conversation as resolved.
Show resolved Hide resolved
fn block_hash(block_number: BlockNumberFor<T>) -> T::Hash {
frame_system::Pallet::<T>::block_hash(block_number)
}
Expand All @@ -142,17 +137,16 @@ impl BenchmarkHelper for () {
type ModuleMmr<StorageType, T, I> = mmr::Mmr<StorageType, T, I, LeafOf<T, I>>;

/// Leaf data.
type LeafOf<T, I> = <<T as Config<I>>::LeafData as primitives::LeafDataProvider>::LeafData;
type LeafOf<T, I> = <<T as Config<I>>::LeafData as LeafDataProvider>::LeafData;

/// Hashing used for the pallet.
pub(crate) type HashingOf<T, I> = <T as Config<I>>::Hashing;
/// Hash type used for the pallet.
pub(crate) type HashOf<T, I> = <<T as Config<I>>::Hashing as traits::Hash>::Output;
pub(crate) type HashOf<T, I> = <<T as Config<I>>::Hashing as Hash>::Output;

#[frame_support::pallet]
#[frame::pallet]
pub mod pallet {
use super::*;
use frame_support::pallet_prelude::*;

#[pallet::pallet]
pub struct Pallet<T, I = ()>(PhantomData<(T, I)>);
Expand Down Expand Up @@ -180,7 +174,7 @@ pub mod pallet {
///
/// 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;
type Hashing: Hash;

/// Data stored in the leaf nodes.
///
Expand All @@ -198,15 +192,15 @@ pub mod pallet {
/// two forks with identical line of ancestors compete to write the same offchain key, but
/// that's fine as long as leaves only contain data coming from ancestors - conflicting
/// writes are identical).
type LeafData: primitives::LeafDataProvider;
type LeafData: 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<HashOf<Self, I>>;
type OnNewRoot: OnNewRoot<HashOf<Self, I>>;

/// Block hash provider for a given block number.
type BlockHashProvider: BlockHashProvider<
Expand Down Expand Up @@ -248,9 +242,8 @@ pub mod pallet {
#[pallet::hooks]
impl<T: Config<I>, I: 'static> Hooks<BlockNumberFor<T>> for Pallet<T, I> {
fn on_initialize(_n: BlockNumberFor<T>) -> Weight {
use primitives::LeafDataProvider;
let leaves = NumberOfLeaves::<T, I>::get();
let peaks_before = sp_mmr_primitives::utils::NodesUtils::new(leaves).number_of_peaks();
let peaks_before = NodesUtils::new(leaves).number_of_peaks();
let data = T::LeafData::leaf_data();

// append new leaf to MMR
Expand All @@ -268,12 +261,12 @@ pub mod pallet {
return T::WeightInfo::on_initialize(peaks_before as u32)
},
};
<T::OnNewRoot as primitives::OnNewRoot<_>>::on_new_root(&root);
<T::OnNewRoot as OnNewRoot<_>>::on_new_root(&root);

NumberOfLeaves::<T, I>::put(leaves);
RootHash::<T, I>::put(root);

let peaks_after = sp_mmr_primitives::utils::NodesUtils::new(leaves).number_of_peaks();
let peaks_after = NodesUtils::new(leaves).number_of_peaks();

T::WeightInfo::on_initialize(peaks_before.max(peaks_after) as u32)
}
Expand All @@ -290,28 +283,28 @@ pub mod pallet {
pub fn verify_leaves_proof<H, L>(
root: H::Output,
leaves: Vec<mmr::Node<H, L>>,
proof: primitives::LeafProof<H::Output>,
) -> Result<(), primitives::Error>
proof: LeafProof<H::Output>,
) -> Result<(), Error>
where
H: traits::Hash,
L: primitives::FullLeaf,
H: Hash,
L: FullLeaf,
{
let is_valid = mmr::verify_leaves_proof::<H, L>(root, leaves, proof)?;
if is_valid {
Ok(())
} else {
Err(primitives::Error::Verify.log_debug(("The proof is incorrect.", root)))
Err(Error::Verify.log_debug(("The proof is incorrect.", root)))
}
}

/// Stateless ancestry proof verification.
pub fn verify_ancestry_proof<H, L>(
root: H::Output,
ancestry_proof: primitives::AncestryProof<H::Output>,
ancestry_proof: AncestryProof<H::Output>,
) -> Result<H::Output, Error>
where
H: traits::Hash,
L: primitives::FullLeaf,
H: Hash,
L: FullLeaf,
{
mmr::verify_ancestry_proof::<H, L>(root, ancestry_proof)
.map_err(|_| Error::Verify.log_debug(("The ancestry proof is incorrect.", root)))
Expand Down Expand Up @@ -383,7 +376,7 @@ impl<T: Config<I>, I: 'static> Pallet<T, I> {
pub fn generate_proof(
block_numbers: Vec<BlockNumberFor<T>>,
best_known_block_number: Option<BlockNumberFor<T>>,
) -> Result<(Vec<LeafOf<T, I>>, primitives::LeafProof<HashOf<T, I>>), primitives::Error> {
) -> Result<(Vec<LeafOf<T, I>>, LeafProof<HashOf<T, I>>), Error> {
// check whether best_known_block_number provided, else use current best block
let best_known_block_number =
best_known_block_number.unwrap_or_else(|| <frame_system::Pallet<T>>::block_number());
Expand All @@ -393,7 +386,7 @@ impl<T: Config<I>, I: 'static> Pallet<T, I> {
// we need to translate the block_numbers into leaf indices.
let leaf_indices = block_numbers
.iter()
.map(|block_num| -> Result<LeafIndex, primitives::Error> {
.map(|block_num| -> Result<LeafIndex, Error> {
Self::block_num_to_leaf_index(*block_num)
})
.collect::<Result<Vec<LeafIndex>, _>>()?;
Expand All @@ -410,29 +403,30 @@ impl<T: Config<I>, I: 'static> Pallet<T, I> {
/// or the proof is invalid.
pub fn verify_leaves(
leaves: Vec<LeafOf<T, I>>,
proof: primitives::LeafProof<HashOf<T, I>>,
) -> Result<(), primitives::Error> {
proof: LeafProof<HashOf<T, I>>,
) -> Result<(), Error> {
if proof.leaf_count > NumberOfLeaves::<T, I>::get() ||
proof.leaf_count == 0 ||
proof.items.len().saturating_add(leaves.len()) as u64 > proof.leaf_count
{
return Err(primitives::Error::Verify
.log_debug("The proof has incorrect number of leaves or proof items."))
return Err(
Error::Verify.log_debug("The proof has incorrect number of leaves or proof items.")
)
}

let mmr: ModuleMmr<mmr::storage::OffchainStorage, T, I> = mmr::Mmr::new(proof.leaf_count);
let is_valid = mmr.verify_leaves_proof(leaves, proof)?;
if is_valid {
Ok(())
} else {
Err(primitives::Error::Verify.log_debug("The proof is incorrect."))
Err(Error::Verify.log_debug("The proof is incorrect."))
}
}

pub fn generate_ancestry_proof(
prev_block_number: BlockNumberFor<T>,
best_known_block_number: Option<BlockNumberFor<T>>,
) -> Result<primitives::AncestryProof<HashOf<T, I>>, Error> {
) -> Result<AncestryProof<HashOf<T, I>>, Error> {
// check whether best_known_block_number provided, else use current best block
let best_known_block_number =
best_known_block_number.unwrap_or_else(|| <frame_system::Pallet<T>>::block_number());
Expand All @@ -445,16 +439,15 @@ impl<T: Config<I>, I: 'static> Pallet<T, I> {
}

#[cfg(feature = "runtime-benchmarks")]
pub fn generate_mock_ancestry_proof() -> Result<primitives::AncestryProof<HashOf<T, I>>, Error>
{
pub fn generate_mock_ancestry_proof() -> Result<AncestryProof<HashOf<T, I>>, Error> {
let leaf_count = Self::block_num_to_leaf_count(<frame_system::Pallet<T>>::block_number())?;
let mmr: ModuleMmr<mmr::storage::OffchainStorage, T, I> = mmr::Mmr::new(leaf_count);
mmr.generate_mock_ancestry_proof()
}

pub fn verify_ancestry_proof(
root: HashOf<T, I>,
ancestry_proof: primitives::AncestryProof<HashOf<T, I>>,
ancestry_proof: AncestryProof<HashOf<T, I>>,
) -> Result<HashOf<T, I>, Error> {
verify_ancestry_proof::<HashingOf<T, I>, LeafOf<T, I>>(root, ancestry_proof)
}
Expand Down
Loading
Loading