Skip to content
This repository has been archived by the owner on Nov 15, 2023. It is now read-only.

pallet-mmr: generate historical proofs #12324

Merged
merged 9 commits into from
Sep 30, 2022
39 changes: 30 additions & 9 deletions bin/node/runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2010,10 +2010,7 @@ impl_runtime_apis! {
}
}

impl pallet_mmr::primitives::MmrApi<
Block,
mmr::Hash,
> for Runtime {
impl pallet_mmr::primitives::MmrApi<Block, mmr::Hash> for Runtime {
fn generate_proof(leaf_index: pallet_mmr::primitives::LeafIndex)
-> Result<(mmr::EncodableOpaqueLeaf, mmr::Proof<mmr::Hash>), mmr::Error>
{
Expand Down Expand Up @@ -2048,11 +2045,35 @@ impl_runtime_apis! {
Ok(Mmr::mmr_root())
}

fn generate_batch_proof(leaf_indices: Vec<pallet_mmr::primitives::LeafIndex>)
-> Result<(Vec<mmr::EncodableOpaqueLeaf>, mmr::BatchProof<mmr::Hash>), mmr::Error>
{
Mmr::generate_batch_proof(leaf_indices)
.map(|(leaves, proof)| (leaves.into_iter().map(|leaf| mmr::EncodableOpaqueLeaf::from_leaf(&leaf)).collect(), proof))
fn generate_batch_proof(
leaf_indices: Vec<pallet_mmr::primitives::LeafIndex>,
) -> Result<(Vec<mmr::EncodableOpaqueLeaf>, mmr::BatchProof<mmr::Hash>), mmr::Error> {
Mmr::generate_batch_proof(leaf_indices).map(|(leaves, proof)| {
(
leaves
.into_iter()
.map(|leaf| mmr::EncodableOpaqueLeaf::from_leaf(&leaf))
.collect(),
proof,
)
})
}

fn generate_historical_batch_proof(
leaf_indices: Vec<pallet_mmr::primitives::LeafIndex>,
leaves_count: pallet_mmr::primitives::LeafIndex,
) -> Result<(Vec<mmr::EncodableOpaqueLeaf>, mmr::BatchProof<mmr::Hash>), mmr::Error> {
Mmr::generate_historical_batch_proof(leaf_indices, leaves_count).map(
|(leaves, proof)| {
(
leaves
.into_iter()
.map(|leaf| mmr::EncodableOpaqueLeaf::from_leaf(&leaf))
.collect(),
proof,
)
},
)
}

fn verify_batch_proof(leaves: Vec<mmr::EncodableOpaqueLeaf>, proof: mmr::BatchProof<mmr::Hash>)
Expand Down
7 changes: 7 additions & 0 deletions client/beefy/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -277,6 +277,13 @@ macro_rules! create_test_api {
unimplemented!()
}

fn generate_historical_batch_proof(
_leaf_indices: Vec<LeafIndex>,
_leaves_count: LeafIndex
) -> Result<(Vec<EncodableOpaqueLeaf>, BatchProof<MmrRootHash>), MmrError> {
unimplemented!()
}

fn verify_batch_proof(_leaves: Vec<EncodableOpaqueLeaf>, _proof: BatchProof<MmrRootHash>) -> Result<(), MmrError> {
unimplemented!()
}
Expand Down
49 changes: 49 additions & 0 deletions frame/merkle-mountain-range/rpc/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,31 @@ pub trait MmrApi<BlockHash> {
leaf_indices: Vec<LeafIndex>,
at: Option<BlockHash>,
) -> RpcResult<LeafBatchProof<BlockHash>>;

/// Generate a MMR proof for the given `leaf_indices` of the MMR that had `leaves_count` leaves.
///
/// This method calls into a runtime with MMR pallet included and attempts to generate
/// a MMR proof for the set of leaves at the given `leaf_indices` with MMR fixed to the state
/// with exactly `leaves_count` leaves. `leaves_count` must be larger than the `leaf_index` for
serban300 marked this conversation as resolved.
Show resolved Hide resolved
/// the function to succeed.
///
/// Optionally, a block hash at which the runtime should be queried can be specified.
/// Note that specifying the block hash isn't super-useful here, unless you're generating
/// proof using non-finalized blocks where there are several competing forks. That's because
/// MMR state will be fixed to the state with `leaves_count`, which already points to some
/// historical block.
serban300 marked this conversation as resolved.
Show resolved Hide resolved
///
/// Returns the leaves and a proof for these leaves (compact encoding, i.e. hash of
/// the leaves). Both parameters are SCALE-encoded.
/// The order of entries in the `leaves` field of the returned struct
/// is the same as the order of the entries in `leaf_indices` supplied
#[method(name = "mmr_generateHistoricalBatchProof")]
fn generate_historical_batch_proof(
&self,
leaf_indices: Vec<LeafIndex>,
leaves_count: LeafIndex,
at: Option<BlockHash>,
) -> RpcResult<LeafBatchProof<BlockHash>>;
}

/// MMR RPC methods.
Expand Down Expand Up @@ -192,6 +217,30 @@ where

Ok(LeafBatchProof::new(block_hash, leaves, proof))
}

fn generate_historical_batch_proof(
&self,
leaf_indices: Vec<LeafIndex>,
leaves_count: LeafIndex,
at: Option<<Block as BlockT>::Hash>,
) -> RpcResult<LeafBatchProof<<Block as BlockT>::Hash>> {
let api = self.client.runtime_api();
let block_hash = at.unwrap_or_else(||
// If the block hash is not supplied assume the best block.
self.client.info().best_hash);

let (leaves, proof) = api
.generate_historical_batch_proof_with_context(
&BlockId::hash(block_hash),
sp_core::ExecutionContext::OffchainCall(None),
leaf_indices,
leaves_count,
)
.map_err(runtime_error_into_rpc_error)?
.map_err(mmr_error_into_rpc_error)?;

Ok(LeafBatchProof::new(block_hash, leaves, proof))
}
}

/// Converts a mmr-specific error into a [`CallError`].
Expand Down
22 changes: 21 additions & 1 deletion frame/merkle-mountain-range/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -330,7 +330,27 @@ impl<T: Config<I>, I: 'static> Pallet<T, I> {
(Vec<LeafOf<T, I>>, primitives::BatchProof<<T as Config<I>>::Hash>),
primitives::Error,
> {
let mmr: ModuleMmr<mmr::storage::OffchainStorage, T, I> = mmr::Mmr::new(Self::mmr_leaves());
Self::generate_historical_batch_proof(leaf_indices, Self::mmr_leaves())
}

/// Generate a MMR proof for the given `leaf_indices` of the MMR that had `leaves_count` leaves.
serban300 marked this conversation as resolved.
Show resolved Hide resolved
///
/// Note this method can only be used from an off-chain context
/// (Offchain Worker or Runtime API call), since it requires
/// all the leaves to be present.
/// It may return an error or panic if used incorrectly.
pub fn generate_historical_batch_proof(
leaf_indices: Vec<LeafIndex>,
leaves_count: LeafIndex,
) -> Result<
(Vec<LeafOf<T, I>>, primitives::BatchProof<<T as Config<I>>::Hash>),
primitives::Error,
> {
if leaves_count > Self::mmr_leaves() {
return Err(Error::InvalidLeavesCount)
}

let mmr: ModuleMmr<mmr::storage::OffchainStorage, T, I> = mmr::Mmr::new(leaves_count);
mmr.generate_batch_proof(leaf_indices)
serban300 marked this conversation as resolved.
Show resolved Hide resolved
}

Expand Down
Loading