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

pallet-mmr: RPC API and Runtime API work with block numbers #12345

Merged
merged 65 commits into from
Oct 13, 2022
Merged
Show file tree
Hide file tree
Changes from 61 commits
Commits
Show all changes
65 commits
Select commit Hold shift + click to select a range
1b8a251
pallet-mmr: RPC API works with block_numbers
Szegoo Sep 24, 2022
fe3f2f3
fixes
Szegoo Sep 24, 2022
f01b68b
update rpc
Szegoo Sep 25, 2022
1b572ad
fmt
Szegoo Sep 25, 2022
2a760ba
final touches in the rpc
Szegoo Sep 25, 2022
d7e50ca
temporary fix
Szegoo Sep 25, 2022
e37e32a
fix
Szegoo Sep 25, 2022
02b0cfa
fmt
Szegoo Sep 25, 2022
f39fc8d
docs
Szegoo Sep 25, 2022
fa8155d
Update lib.rs
Szegoo Sep 25, 2022
32bb713
use NumberFor
Szegoo Sep 26, 2022
ae03943
validate input
Szegoo Sep 26, 2022
8dc459e
update runtime
Szegoo Sep 26, 2022
78d2ea1
convert block_number to u64
Szegoo Sep 26, 2022
9a3bfe9
small edit
Szegoo Sep 26, 2022
3c8c396
update runtime api
Szegoo Sep 28, 2022
850c782
test fix
Szegoo Sep 28, 2022
098c88b
runtime fix
Szegoo Sep 28, 2022
5e2eb39
update test function
Szegoo Sep 28, 2022
3bd4b72
fmt
Szegoo Sep 28, 2022
6295c51
fix nits
Szegoo Sep 28, 2022
5f909e3
remove block_num_to_leaf_index from runtime api
Szegoo Sep 28, 2022
379021e
Merge branch 'paritytech:master' into mmr-rpc
Szegoo Sep 28, 2022
6b7b4bb
Merge branch 'paritytech:master' into mmr-rpc
Szegoo Sep 29, 2022
97152b6
Update frame/merkle-mountain-range/src/lib.rs
Szegoo Sep 30, 2022
28e4437
fix tests
Szegoo Sep 30, 2022
f863814
merge
Szegoo Sep 30, 2022
3da0a90
get the code to compile after merge
Szegoo Sep 30, 2022
245d967
get the tests to compile
Szegoo Sep 30, 2022
3c355a0
fix in tests?
Szegoo Sep 30, 2022
f54c3a7
fix test
Szegoo Sep 30, 2022
e3d046b
Merge branch 'master' into mmr-rpc
Szegoo Oct 2, 2022
0dba52b
Update frame/merkle-mountain-range/src/tests.rs
Szegoo Oct 3, 2022
d68aaae
Update frame/merkle-mountain-range/src/lib.rs
Szegoo Oct 3, 2022
a792fc4
Update primitives/merkle-mountain-range/src/lib.rs
Szegoo Oct 3, 2022
e3d304a
Merge branch 'master' into mmr-rpc
Szegoo Oct 3, 2022
dbd7edb
fix errors & nits
Szegoo Oct 3, 2022
2004425
change block_num_to_leaf_index
Szegoo Oct 3, 2022
2778f7a
don't make any assumptions
Szegoo Oct 4, 2022
0a17093
Update frame/merkle-mountain-range/src/tests.rs
Szegoo Oct 4, 2022
e7d2dff
Update frame/merkle-mountain-range/src/tests.rs
Szegoo Oct 4, 2022
701e6d3
Update frame/merkle-mountain-range/src/tests.rs
Szegoo Oct 4, 2022
eb32356
fix
Szegoo Oct 4, 2022
900db49
small fix
Szegoo Oct 4, 2022
5232ef9
Merge branch 'paritytech:master' into mmr-rpc
Szegoo Oct 4, 2022
d57f6f4
Merge branch 'master' into mmr-rpc
Szegoo Oct 5, 2022
3a6b998
use best_known_block_number
Szegoo Oct 5, 2022
66b8c33
best_known_block_number instead of leaves_count
Szegoo Oct 5, 2022
75088ff
more readable?
Szegoo Oct 5, 2022
3dc7838
remove warning
Szegoo Oct 5, 2022
cad6805
Merge branch 'paritytech:master' into mmr-rpc
Szegoo Oct 5, 2022
2ae0e20
Update frame/merkle-mountain-range/src/lib.rs
Szegoo Oct 6, 2022
e8c364b
simplify
Szegoo Oct 6, 2022
4538c08
update docs
Szegoo Oct 6, 2022
42ec4d2
nits
Szegoo Oct 6, 2022
9526295
fmt & fix
Szegoo Oct 7, 2022
e78e3a4
Merge branch 'paritytech:master' into mmr-rpc
Szegoo Oct 7, 2022
ba84f7b
merge fixes
Szegoo Oct 7, 2022
0c01e2a
fix
Szegoo Oct 7, 2022
47dfdfb
small fix
Szegoo Oct 7, 2022
5abad1d
docs & nit fixes
Szegoo Oct 7, 2022
4eb1efe
Nit fixes
Szegoo Oct 11, 2022
c736917
remove leaf_indices_to_block_numbers()
Szegoo Oct 11, 2022
876daf2
Merge branch 'paritytech:master' into mmr-rpc
Szegoo Oct 11, 2022
ac636bd
fmt
Szegoo Oct 11, 2022
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
6 changes: 5 additions & 1 deletion bin/node/rpc/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,11 @@ where
+ Send
+ 'static,
C::Api: substrate_frame_rpc_system::AccountNonceApi<Block, AccountId, Index>,
C::Api: pallet_mmr_rpc::MmrRuntimeApi<Block, <Block as sp_runtime::traits::Block>::Hash>,
C::Api: pallet_mmr_rpc::MmrRuntimeApi<
Block,
<Block as sp_runtime::traits::Block>::Hash,
BlockNumber,
>,
C::Api: pallet_transaction_payment_rpc::TransactionPaymentRuntimeApi<Block, Balance>,
C::Api: BabeApi<Block>,
C::Api: BlockBuilder<Block>,
Expand Down
20 changes: 12 additions & 8 deletions bin/node/runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2013,11 +2013,15 @@ impl_runtime_apis! {
}
}

impl pallet_mmr::primitives::MmrApi<Block, mmr::Hash> for Runtime {
fn generate_proof(leaf_index: pallet_mmr::primitives::LeafIndex)
impl pallet_mmr::primitives::MmrApi<
Block,
mmr::Hash,
BlockNumber,
> for Runtime {
fn generate_proof(block_number: BlockNumber)
-> Result<(mmr::EncodableOpaqueLeaf, mmr::Proof<mmr::Hash>), mmr::Error>
{
Mmr::generate_batch_proof(vec![leaf_index]).and_then(|(leaves, proof)|
Mmr::generate_batch_proof(vec![block_number]).and_then(|(leaves, proof)|
Ok((
mmr::EncodableOpaqueLeaf::from_leaf(&leaves[0]),
mmr::BatchProof::into_single_leaf_proof(proof)?
Expand Down Expand Up @@ -2049,9 +2053,9 @@ impl_runtime_apis! {
}

fn generate_batch_proof(
leaf_indices: Vec<pallet_mmr::primitives::LeafIndex>,
block_numbers: Vec<BlockNumber>,
) -> Result<(Vec<mmr::EncodableOpaqueLeaf>, mmr::BatchProof<mmr::Hash>), mmr::Error> {
Mmr::generate_batch_proof(leaf_indices).map(|(leaves, proof)| {
Mmr::generate_batch_proof(block_numbers).map(|(leaves, proof)| {
(
leaves
.into_iter()
Expand All @@ -2063,10 +2067,10 @@ impl_runtime_apis! {
}

fn generate_historical_batch_proof(
leaf_indices: Vec<pallet_mmr::primitives::LeafIndex>,
leaves_count: pallet_mmr::primitives::LeafIndex,
block_numbers: Vec<BlockNumber>,
best_known_block_number: BlockNumber,
) -> Result<(Vec<mmr::EncodableOpaqueLeaf>, mmr::BatchProof<mmr::Hash>), mmr::Error> {
Mmr::generate_historical_batch_proof(leaf_indices, leaves_count).map(
Mmr::generate_historical_batch_proof(block_numbers, best_known_block_number).map(
|(leaves, proof)| {
(
leaves
Expand Down
4 changes: 2 additions & 2 deletions client/beefy/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ use sc_consensus::BlockImport;
use sc_network::ProtocolName;
use sc_network_common::service::NetworkRequest;
use sc_network_gossip::Network as GossipNetwork;
use sp_api::ProvideRuntimeApi;
use sp_api::{NumberFor, ProvideRuntimeApi};
use sp_blockchain::HeaderBackend;
use sp_consensus::{Error as ConsensusError, SyncOracle};
use sp_keystore::SyncCryptoStorePtr;
Expand Down Expand Up @@ -200,7 +200,7 @@ where
C: Client<B, BE> + BlockBackend<B>,
P: PayloadProvider<B>,
R: ProvideRuntimeApi<B>,
R::Api: BeefyApi<B> + MmrApi<B, MmrRootHash>,
R::Api: BeefyApi<B> + MmrApi<B, MmrRootHash, NumberFor<B>>,
N: GossipNetwork<B> + NetworkRequest + SyncOracle + Send + Sync + 'static,
{
let BeefyParams {
Expand Down
16 changes: 7 additions & 9 deletions client/beefy/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,7 @@ use beefy_primitives::{
KEY_TYPE as BeefyKeyType,
};
use sc_network::{config::RequestResponseConfig, ProtocolName};
use sp_mmr_primitives::{
BatchProof, EncodableOpaqueLeaf, Error as MmrError, LeafIndex, MmrApi, Proof,
};
use sp_mmr_primitives::{BatchProof, EncodableOpaqueLeaf, Error as MmrError, MmrApi, Proof};

use sp_api::{ApiRef, ProvideRuntimeApi};
use sp_consensus::BlockOrigin;
Expand Down Expand Up @@ -247,8 +245,8 @@ macro_rules! create_test_api {
}
}

impl MmrApi<Block, MmrRootHash> for RuntimeApi {
fn generate_proof(_leaf_index: LeafIndex)
impl MmrApi<Block, MmrRootHash, NumberFor<Block>> for RuntimeApi {
fn generate_proof(_block_number: u64)
-> Result<(EncodableOpaqueLeaf, Proof<MmrRootHash>), MmrError> {
unimplemented!()
}
Expand All @@ -270,13 +268,13 @@ macro_rules! create_test_api {
Ok($mmr_root)
}

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

fn generate_historical_batch_proof(
_leaf_indices: Vec<LeafIndex>,
_leaves_count: LeafIndex
_block_numbers: Vec<u64>,
_best_known_block_number: u64
) -> Result<(Vec<EncodableOpaqueLeaf>, BatchProof<MmrRootHash>), MmrError> {
unimplemented!()
}
Expand Down Expand Up @@ -349,7 +347,7 @@ fn initialize_beefy<API>(
) -> impl Future<Output = ()>
where
API: ProvideRuntimeApi<Block> + Default + Sync + Send,
API::Api: BeefyApi<Block> + MmrApi<Block, MmrRootHash>,
API::Api: BeefyApi<Block> + MmrApi<Block, MmrRootHash, NumberFor<Block>>,
{
let tasks = FuturesUnordered::new();

Expand Down
2 changes: 1 addition & 1 deletion client/beefy/src/worker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -252,7 +252,7 @@ where
C: Client<B, BE>,
P: PayloadProvider<B>,
R: ProvideRuntimeApi<B>,
R::Api: BeefyApi<B> + MmrApi<B, MmrRootHash>,
R::Api: BeefyApi<B> + MmrApi<B, MmrRootHash, NumberFor<B>>,
N: NetworkEventStream + NetworkRequest + SyncOracle + Send + Sync + Clone + 'static,
{
/// Return a new BEEFY worker instance.
Expand Down
54 changes: 28 additions & 26 deletions frame/merkle-mountain-range/rpc/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ use serde::{Deserialize, Serialize};
use sp_api::ProvideRuntimeApi;
use sp_blockchain::HeaderBackend;
use sp_core::Bytes;
use sp_mmr_primitives::{BatchProof, Error as MmrError, LeafIndex, Proof};
use sp_mmr_primitives::{BatchProof, Error as MmrError, Proof};
use sp_runtime::{generic::BlockId, traits::Block as BlockT};

pub use sp_mmr_primitives::MmrApi as MmrRuntimeApi;
Expand Down Expand Up @@ -96,26 +96,26 @@ impl<BlockHash> LeafBatchProof<BlockHash> {

/// MMR RPC methods.
#[rpc(client, server)]
pub trait MmrApi<BlockHash> {
/// Generate MMR proof for given leaf index.
pub trait MmrApi<BlockHash, BlockNumber> {
/// Generate MMR proof for given block number.
///
/// This method calls into a runtime with MMR pallet included and attempts to generate
/// MMR proof for leaf at given `leaf_index`.
/// MMR proof for a block with a specified `block_number`.
/// Optionally, a block hash at which the runtime should be queried can be specified.
///
/// Returns the (full) leaf itself and a proof for this leaf (compact encoding, i.e. hash of
/// the leaf). Both parameters are SCALE-encoded.
#[method(name = "mmr_generateProof")]
fn generate_proof(
&self,
leaf_index: LeafIndex,
block_number: BlockNumber,
at: Option<BlockHash>,
) -> RpcResult<LeafProof<BlockHash>>;

/// Generate MMR proof for the given leaf indices.
/// Generate MMR proof for the given block numbers.
///
/// 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`.
/// MMR proof for a set of blocks with the specific `block_numbers`.
Szegoo marked this conversation as resolved.
Show resolved Hide resolved
/// 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
Expand All @@ -125,22 +125,22 @@ pub trait MmrApi<BlockHash> {
#[method(name = "mmr_generateBatchProof")]
fn generate_batch_proof(
&self,
leaf_indices: Vec<LeafIndex>,
block_numbers: Vec<BlockNumber>,
at: Option<BlockHash>,
) -> RpcResult<LeafBatchProof<BlockHash>>;

/// Generate a MMR proof for the given `leaf_indices` of the MMR that had `leaves_count` leaves.
/// Generate a MMR proof for the given `block_numbers` given the `best_known_block_number`.
///
/// 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.
/// a MMR proof for the set of blocks that have the given `block_numbers` with MMR given the
/// `best_known_block_number`. `best_known_block_number` must be larger than all the
/// `block_numbers` 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.
/// MMR state will be fixed to the state with `best_known_block_number`, 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.
Expand All @@ -149,8 +149,8 @@ pub trait MmrApi<BlockHash> {
#[method(name = "mmr_generateHistoricalBatchProof")]
fn generate_historical_batch_proof(
Szegoo marked this conversation as resolved.
Show resolved Hide resolved
&self,
leaf_indices: Vec<LeafIndex>,
leaves_count: LeafIndex,
block_numbers: Vec<BlockNumber>,
best_known_block_number: BlockNumber,
at: Option<BlockHash>,
) -> RpcResult<LeafBatchProof<BlockHash>>;
}
Expand All @@ -169,16 +169,18 @@ impl<C, B> Mmr<C, B> {
}

#[async_trait]
impl<Client, Block, MmrHash> MmrApiServer<<Block as BlockT>::Hash> for Mmr<Client, (Block, MmrHash)>
impl<Client, Block, MmrHash, BlockNumber> MmrApiServer<<Block as BlockT>::Hash, BlockNumber>
Szegoo marked this conversation as resolved.
Show resolved Hide resolved
for Mmr<Client, (Block, MmrHash)>
where
Block: BlockT,
Client: Send + Sync + 'static + ProvideRuntimeApi<Block> + HeaderBackend<Block>,
Client::Api: MmrRuntimeApi<Block, MmrHash>,
Client::Api: MmrRuntimeApi<Block, MmrHash, BlockNumber>,
MmrHash: Codec + Send + Sync + 'static,
BlockNumber: Codec,
{
fn generate_proof(
&self,
leaf_index: LeafIndex,
block_number: BlockNumber,
at: Option<<Block as BlockT>::Hash>,
) -> RpcResult<LeafProof<Block::Hash>> {
let api = self.client.runtime_api();
Expand All @@ -188,7 +190,7 @@ where
.generate_proof_with_context(
&BlockId::hash(block_hash),
sp_core::ExecutionContext::OffchainCall(None),
leaf_index,
block_number,
)
.map_err(runtime_error_into_rpc_error)?
.map_err(mmr_error_into_rpc_error)?;
Expand All @@ -198,7 +200,7 @@ where

fn generate_batch_proof(
&self,
leaf_indices: Vec<LeafIndex>,
block_numbers: Vec<BlockNumber>,
at: Option<<Block as BlockT>::Hash>,
) -> RpcResult<LeafBatchProof<<Block as BlockT>::Hash>> {
let api = self.client.runtime_api();
Expand All @@ -210,7 +212,7 @@ where
.generate_batch_proof_with_context(
&BlockId::hash(block_hash),
sp_core::ExecutionContext::OffchainCall(None),
leaf_indices,
block_numbers,
)
.map_err(runtime_error_into_rpc_error)?
.map_err(mmr_error_into_rpc_error)?;
Expand All @@ -220,8 +222,8 @@ where

fn generate_historical_batch_proof(
&self,
leaf_indices: Vec<LeafIndex>,
leaves_count: LeafIndex,
block_numbers: Vec<BlockNumber>,
best_known_block_number: BlockNumber,
at: Option<<Block as BlockT>::Hash>,
) -> RpcResult<LeafBatchProof<<Block as BlockT>::Hash>> {
let api = self.client.runtime_api();
Expand All @@ -233,8 +235,8 @@ where
.generate_historical_batch_proof_with_context(
&BlockId::hash(block_hash),
sp_core::ExecutionContext::OffchainCall(None),
leaf_indices,
leaves_count,
block_numbers,
best_known_block_number,
)
.map_err(runtime_error_into_rpc_error)?
.map_err(mmr_error_into_rpc_error)?;
Expand Down
56 changes: 46 additions & 10 deletions frame/merkle-mountain-range/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@
use codec::Encode;
use frame_support::weights::Weight;
use sp_runtime::{
traits::{self, One, Saturating},
traits::{self, CheckedSub, One, Saturating},
SaturatedConversion,
};

Expand Down Expand Up @@ -318,37 +318,73 @@ impl<T: Config<I>, I: 'static> Pallet<T, I> {
.saturating_add(leaf_index.saturated_into())
}

/// Generate a MMR proof for the given `leaf_indices`.
/// Convert a `block_num` into a leaf index.
fn block_num_to_leaf_index(block_num: T::BlockNumber) -> Result<LeafIndex, primitives::Error>
where
T: frame_system::Config,
{
// leaf_idx = (leaves_count - 1) - (current_block_num - block_num);
let best_block_num = <frame_system::Pallet<T>>::block_number();
let blocks_diff = best_block_num.checked_sub(&block_num).ok_or_else(|| {
primitives::Error::BlockNumToLeafIndex
.log_debug("The provided block_number is greater than the best block number.")
})?;
let blocks_diff_as_leaf_idx = blocks_diff.try_into().map_err(|_| {
primitives::Error::BlockNumToLeafIndex
.log_debug("The `blocks_diff` couldn't be converted to `LeafIndex`.")
})?;

let leaf_idx = Self::mmr_leaves()
.checked_sub(1)
.and_then(|last_leaf_idx| last_leaf_idx.checked_sub(blocks_diff_as_leaf_idx))
.ok_or_else(|| {
primitives::Error::BlockNumToLeafIndex
.log_debug("There aren't enough leaves in the chain.")
})?;
Ok(leaf_idx)
}

/// Generate a MMR proof for the given `block_numbers`.
///
/// 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_batch_proof(
leaf_indices: Vec<LeafIndex>,
block_numbers: Vec<T::BlockNumber>,
) -> Result<
(Vec<LeafOf<T, I>>, primitives::BatchProof<<T as Config<I>>::Hash>),
primitives::Error,
> {
Self::generate_historical_batch_proof(leaf_indices, Self::mmr_leaves())
Self::generate_historical_batch_proof(
block_numbers,
<frame_system::Pallet<T>>::block_number(),
)
}

/// Generate a MMR proof for the given `leaf_indices` for the MMR of `leaves_count` size.
/// Generate a MMR proof for the given `block_numbers` given the `best_known_block_number`.
///
/// 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,
block_numbers: Vec<T::BlockNumber>,
best_known_block_number: T::BlockNumber,
) -> 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 leaves_count =
Self::block_num_to_leaf_index(best_known_block_number)?.saturating_add(1);

// we need to translate the block_numbers into leaf indices.
let leaf_indices = block_numbers
.iter()
.map(|block_num| -> Result<LeafIndex, primitives::Error> {
Self::block_num_to_leaf_index(*block_num)
})
.collect::<Result<Vec<LeafIndex>, _>>()?;

let mmr: ModuleMmr<mmr::storage::OffchainStorage, T, I> = mmr::Mmr::new(leaves_count);
mmr.generate_batch_proof(leaf_indices)
Expand Down
Loading