pallet-mmr: generate historical proofs (#12324)

* BEEFY: generate historical proofs

Signed-off-by: Serban Iorga <serban@parity.io>

* Update frame/merkle-mountain-range/rpc/src/lib.rs

Co-authored-by: Adrian Catangiu <adrian@parity.io>

* Update primitives/merkle-mountain-range/src/lib.rs

Co-authored-by: Adrian Catangiu <adrian@parity.io>

* Update frame/merkle-mountain-range/src/lib.rs

Co-authored-by: Adrian Catangiu <adrian@parity.io>

* cargo fmt

* fix off-by-one in leaves powerset generation

* test all possible mmr sizes for historical proofs

* remove now redundant simple_historical_proof

* cargo fmt

Signed-off-by: Serban Iorga <serban@parity.io>
Co-authored-by: Adrian Catangiu <adrian@parity.io>
Co-authored-by: Robert Hambrock <roberthambrock@gmail.com>
This commit is contained in:
Serban Iorga
2022-09-30 13:46:48 +03:00
committed by GitHub
parent 5e00d361cc
commit 54713ca17a
6 changed files with 379 additions and 25 deletions
@@ -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 all `leaf_indices`
/// for 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.
///
/// 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.
@@ -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`].