Merkle Mountain Range pallet improvements (#7891)

* Add stateless verification helper function.

* Split MMR primitives.

* Add RuntimeAPI

* RuntimeAPI with OpaqueLeaves

* Bump spec_version,.

* Move primitives back to frame.

* Fix OpaqueLeaf encoding.

* Add block number to frame_system implementation of LeafDataProvider.

* Relax leaf codec requirements and fix OpaqueLeaf

* Add root to debug line.

* Apply suggestions from code review

Co-authored-by: Hernando Castano <HCastano@users.noreply.github.com>

* Typo.

Co-authored-by: Hernando Castano <HCastano@users.noreply.github.com>
This commit is contained in:
Tomasz Drwięga
2021-01-28 11:58:52 +01:00
committed by GitHub
parent fa23de2c03
commit 6c2dd28dfb
12 changed files with 373 additions and 93 deletions
@@ -22,12 +22,35 @@ use crate::{
storage::{Storage, OffchainStorage, RuntimeStorage},
utils::NodesUtils,
},
primitives,
primitives::{self, Error},
};
use frame_support::{debug, RuntimeDebug};
use sp_std::fmt;
#[cfg(not(feature = "std"))]
use sp_std::{vec, prelude::Vec};
use sp_std::vec;
/// Stateless verification of the leaf proof.
pub fn verify_leaf_proof<H, L>(
root: H::Output,
leaf: Node<H, L>,
proof: primitives::Proof<H::Output>,
) -> Result<bool, Error> where
H: sp_runtime::traits::Hash,
L: primitives::FullLeaf,
{
let size = NodesUtils::new(proof.leaf_count).size();
let leaf_position = mmr_lib::leaf_index_to_pos(proof.leaf_index);
let p = mmr_lib::MerkleProof::<
Node<H, L>,
Hasher<H, L>,
>::new(
size,
proof.items.into_iter().map(Node::Hash).collect(),
);
p.verify(
Node::Hash(root),
vec![(leaf_position, leaf)],
).map_err(|e| Error::Verify.log_debug(e))
}
/// A wrapper around a MMR library to expose limited functionality.
///
@@ -123,7 +146,7 @@ impl<T, I, L> Mmr<RuntimeStorage, T, I, L> where
impl<T, I, L> Mmr<OffchainStorage, T, I, L> where
T: Config<I>,
I: Instance,
L: primitives::FullLeaf,
L: primitives::FullLeaf + codec::Decode,
{
/// Generate a proof for given leaf index.
///
@@ -151,36 +174,3 @@ impl<T, I, L> Mmr<OffchainStorage, T, I, L> where
}
}
/// Merkle Mountain Range operation error.
#[derive(RuntimeDebug)]
#[cfg_attr(test, derive(PartialEq, Eq))]
pub enum Error {
/// Error while pushing new node.
Push,
/// Error getting the new root.
GetRoot,
/// Error commiting changes.
Commit,
/// Error during proof generation.
GenerateProof,
/// Proof verification error.
Verify,
/// Leaf not found in the storage.
LeafNotFound,
}
impl Error {
/// Consume given error `e` with `self` and generate a native log entry with error details.
pub(crate) fn log_error(self, e: impl fmt::Debug) -> Self {
debug::native::error!("[{:?}] MMR error: {:?}", self, e);
self
}
/// Consume given error `e` with `self` and generate a native log entry with error details.
pub(crate) fn log_debug(self, e: impl fmt::Debug) -> Self {
debug::native::debug!("[{:?}] MMR error: {:?}", self, e);
self
}
}
@@ -22,7 +22,7 @@ mod mmr;
use crate::primitives::FullLeaf;
use sp_runtime::traits;
pub use self::mmr::{Mmr, Error};
pub use self::mmr::{Mmr, verify_leaf_proof};
/// Node type for runtime `T`.
pub type NodeOf<T, I, L> = Node<<T as crate::Config<I>>::Hashing, L>;
@@ -57,7 +57,7 @@ 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,
L: primitives::FullLeaf,
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);