mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-15 10:21:05 +00:00
Update MMR Runtime API with functionality to generate MMR proof for a series of leaf indices (#10635)
* updated mmr rpc api with functions for batch generation of proof * update code comments * fix build errors * added tests to mmr-rpc * add tests to pallet-mmr * update comments * minor comment fix * remove unused variables * fix rust doc errors * refactor mmr runtime api * fix tests * minor fix * minor fix * fix node-runtime * revert to initial api * impl from proof fot batchproof * minor fix * minor fix * use explicit functions to convert btw batch proof and single proof * minor fix * add new variant to mmr error * fmt * update conversion to single leaf proof * fix style nit Co-authored-by: Adrian Catangiu <adrian@parity.io>
This commit is contained in:
@@ -29,7 +29,7 @@ use serde::{Deserialize, Serialize};
|
||||
use sp_api::ProvideRuntimeApi;
|
||||
use sp_blockchain::HeaderBackend;
|
||||
use sp_core::Bytes;
|
||||
use sp_mmr_primitives::{Error as MmrError, LeafIndex, Proof};
|
||||
use sp_mmr_primitives::{BatchProof, Error as MmrError, LeafIndex, Proof};
|
||||
use sp_runtime::{generic::BlockId, traits::Block as BlockT};
|
||||
|
||||
pub use sp_mmr_primitives::MmrApi as MmrRuntimeApi;
|
||||
@@ -57,6 +57,34 @@ impl<BlockHash> LeafProof<BlockHash> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Retrieved MMR leaves and their proof.
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct LeafBatchProof<BlockHash> {
|
||||
/// Block hash the proof was generated for.
|
||||
pub block_hash: BlockHash,
|
||||
/// SCALE-encoded vector of `LeafData`.
|
||||
pub leaves: Bytes,
|
||||
/// SCALE-encoded proof data. See [sp_mmr_primitives::BatchProof].
|
||||
pub proof: Bytes,
|
||||
}
|
||||
|
||||
impl<BlockHash> LeafBatchProof<BlockHash> {
|
||||
/// Create new `LeafBatchProof` from a given vector of `Leaf` and a
|
||||
/// [sp_mmr_primitives::BatchProof].
|
||||
pub fn new<Leaf, MmrHash>(
|
||||
block_hash: BlockHash,
|
||||
leaves: Vec<Leaf>,
|
||||
proof: BatchProof<MmrHash>,
|
||||
) -> Self
|
||||
where
|
||||
Leaf: Encode,
|
||||
MmrHash: Encode,
|
||||
{
|
||||
Self { block_hash, leaves: Bytes(leaves.encode()), proof: Bytes(proof.encode()) }
|
||||
}
|
||||
}
|
||||
|
||||
/// MMR RPC methods.
|
||||
#[rpc]
|
||||
pub trait MmrApi<BlockHash> {
|
||||
@@ -74,6 +102,23 @@ pub trait MmrApi<BlockHash> {
|
||||
leaf_index: LeafIndex,
|
||||
at: Option<BlockHash>,
|
||||
) -> Result<LeafProof<BlockHash>>;
|
||||
|
||||
/// Generate MMR proof for the given leaf indices.
|
||||
///
|
||||
/// This method calls into a runtime with MMR pallet included and attempts to generate
|
||||
/// MMR proof for a set of leaves at the given `leaf_indices`.
|
||||
/// Optionally, a block hash at which the runtime should be queried can be specified.
|
||||
///
|
||||
/// 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
|
||||
#[rpc(name = "mmr_generateBatchProof")]
|
||||
fn generate_batch_proof(
|
||||
&self,
|
||||
leaf_indices: Vec<LeafIndex>,
|
||||
at: Option<BlockHash>,
|
||||
) -> Result<LeafBatchProof<BlockHash>>;
|
||||
}
|
||||
|
||||
/// An implementation of MMR specific RPC methods.
|
||||
@@ -117,6 +162,28 @@ where
|
||||
|
||||
Ok(LeafProof::new(block_hash, leaf, proof))
|
||||
}
|
||||
|
||||
fn generate_batch_proof(
|
||||
&self,
|
||||
leaf_indices: Vec<LeafIndex>,
|
||||
at: Option<<Block as BlockT>::Hash>,
|
||||
) -> Result<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_batch_proof_with_context(
|
||||
&BlockId::hash(block_hash),
|
||||
sp_core::ExecutionContext::OffchainCall(None),
|
||||
leaf_indices,
|
||||
)
|
||||
.map_err(runtime_error_into_rpc_error)?
|
||||
.map_err(mmr_error_into_rpc_error)?;
|
||||
|
||||
Ok(LeafBatchProof::new(block_hash, leaves, proof))
|
||||
}
|
||||
}
|
||||
|
||||
const RUNTIME_ERROR: i64 = 8000;
|
||||
@@ -179,6 +246,28 @@ mod tests {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn should_serialize_leaf_batch_proof() {
|
||||
// given
|
||||
let leaf = vec![1_u8, 2, 3, 4];
|
||||
let proof = BatchProof {
|
||||
leaf_indices: vec![1],
|
||||
leaf_count: 9,
|
||||
items: vec![H256::repeat_byte(1), H256::repeat_byte(2)],
|
||||
};
|
||||
|
||||
let leaf_proof = LeafBatchProof::new(H256::repeat_byte(0), vec![leaf], proof);
|
||||
|
||||
// when
|
||||
let actual = serde_json::to_string(&leaf_proof).unwrap();
|
||||
|
||||
// then
|
||||
assert_eq!(
|
||||
actual,
|
||||
r#"{"blockHash":"0x0000000000000000000000000000000000000000000000000000000000000000","leaves":"0x041001020304","proof":"0x04010000000000000009000000000000000801010101010101010101010101010101010101010101010101010101010101010202020202020202020202020202020202020202020202020202020202020202"}"#
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn should_deserialize_leaf_proof() {
|
||||
// given
|
||||
@@ -205,4 +294,31 @@ mod tests {
|
||||
// then
|
||||
assert_eq!(actual, expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn should_deserialize_leaf_batch_proof() {
|
||||
// given
|
||||
let expected = LeafBatchProof {
|
||||
block_hash: H256::repeat_byte(0),
|
||||
leaves: Bytes(vec![vec![1_u8, 2, 3, 4]].encode()),
|
||||
proof: Bytes(
|
||||
BatchProof {
|
||||
leaf_indices: vec![1],
|
||||
leaf_count: 9,
|
||||
items: vec![H256::repeat_byte(1), H256::repeat_byte(2)],
|
||||
}
|
||||
.encode(),
|
||||
),
|
||||
};
|
||||
|
||||
// when
|
||||
let actual: LeafBatchProof<H256> = serde_json::from_str(r#"{
|
||||
"blockHash":"0x0000000000000000000000000000000000000000000000000000000000000000",
|
||||
"leaves":"0x041001020304",
|
||||
"proof":"0x04010000000000000009000000000000000801010101010101010101010101010101010101010101010101010101010101010202020202020202020202020202020202020202020202020202020202020202"
|
||||
}"#).unwrap();
|
||||
|
||||
// then
|
||||
assert_eq!(actual, expected);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user