From 9dd89e7fa37ebbfa205bb2216d7f1e6eb8b2259b Mon Sep 17 00:00:00 2001 From: Sergej Sakac <73715684+Szegoo@users.noreply.github.com> Date: Thu, 13 Oct 2022 12:13:56 +0200 Subject: [PATCH] pallet-mmr: RPC API and Runtime API work with block numbers (#12345) * pallet-mmr: RPC API works with block_numbers * fixes * update rpc * fmt * final touches in the rpc * temporary fix * fix * fmt * docs * Update lib.rs * use NumberFor * validate input * update runtime * convert block_number to u64 * small edit * update runtime api * test fix * runtime fix * update test function * fmt * fix nits * remove block_num_to_leaf_index from runtime api * Update frame/merkle-mountain-range/src/lib.rs Co-authored-by: Robert Hambrock <roberthambrock@gmail.com> * fix tests * get the code to compile after merge * get the tests to compile * fix in tests? * fix test * Update frame/merkle-mountain-range/src/tests.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> * Update primitives/merkle-mountain-range/src/lib.rs Co-authored-by: Adrian Catangiu <adrian@parity.io> * fix errors & nits * change block_num_to_leaf_index * don't make any assumptions * Update frame/merkle-mountain-range/src/tests.rs Co-authored-by: Adrian Catangiu <adrian@parity.io> * Update frame/merkle-mountain-range/src/tests.rs Co-authored-by: Adrian Catangiu <adrian@parity.io> * Update frame/merkle-mountain-range/src/tests.rs Co-authored-by: Adrian Catangiu <adrian@parity.io> * fix * small fix * use best_known_block_number * best_known_block_number instead of leaves_count * more readable? * remove warning * Update frame/merkle-mountain-range/src/lib.rs Co-authored-by: Robert Hambrock <roberthambrock@gmail.com> * simplify * update docs * nits * fmt & fix * merge fixes * fix * small fix * docs & nit fixes * Nit fixes * remove leaf_indices_to_block_numbers() * fmt Co-authored-by: Robert Hambrock <roberthambrock@gmail.com> Co-authored-by: Adrian Catangiu <adrian@parity.io> --- substrate/bin/node/rpc/src/lib.rs | 6 +- substrate/bin/node/runtime/src/lib.rs | 20 +++-- substrate/client/beefy/src/lib.rs | 4 +- substrate/client/beefy/src/tests.rs | 16 ++-- substrate/client/beefy/src/worker.rs | 2 +- .../merkle-mountain-range/rpc/src/lib.rs | 59 +++++++------- .../frame/merkle-mountain-range/src/lib.rs | 56 ++++++++++--- .../frame/merkle-mountain-range/src/tests.rs | 81 ++++++++++--------- substrate/primitives/beefy/src/mmr.rs | 6 +- .../merkle-mountain-range/src/lib.rs | 23 +++--- 10 files changed, 160 insertions(+), 113 deletions(-) diff --git a/substrate/bin/node/rpc/src/lib.rs b/substrate/bin/node/rpc/src/lib.rs index 94e01619c6e..8596fe23321 100644 --- a/substrate/bin/node/rpc/src/lib.rs +++ b/substrate/bin/node/rpc/src/lib.rs @@ -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>, diff --git a/substrate/bin/node/runtime/src/lib.rs b/substrate/bin/node/runtime/src/lib.rs index 14217362103..f137b36eff0 100644 --- a/substrate/bin/node/runtime/src/lib.rs +++ b/substrate/bin/node/runtime/src/lib.rs @@ -2016,11 +2016,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)? @@ -2052,9 +2056,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() @@ -2066,10 +2070,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 diff --git a/substrate/client/beefy/src/lib.rs b/substrate/client/beefy/src/lib.rs index 1c61cac0722..441f6e42481 100644 --- a/substrate/client/beefy/src/lib.rs +++ b/substrate/client/beefy/src/lib.rs @@ -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; @@ -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 { diff --git a/substrate/client/beefy/src/tests.rs b/substrate/client/beefy/src/tests.rs index 24cf89acd57..89be1cac4f8 100644 --- a/substrate/client/beefy/src/tests.rs +++ b/substrate/client/beefy/src/tests.rs @@ -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; @@ -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!() } @@ -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!() } @@ -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(); diff --git a/substrate/client/beefy/src/worker.rs b/substrate/client/beefy/src/worker.rs index a21807c8ee8..4381081f74e 100644 --- a/substrate/client/beefy/src/worker.rs +++ b/substrate/client/beefy/src/worker.rs @@ -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. diff --git a/substrate/frame/merkle-mountain-range/rpc/src/lib.rs b/substrate/frame/merkle-mountain-range/rpc/src/lib.rs index e939ff8ae7c..ffc7ac2da56 100644 --- a/substrate/frame/merkle-mountain-range/rpc/src/lib.rs +++ b/substrate/frame/merkle-mountain-range/rpc/src/lib.rs @@ -30,10 +30,10 @@ use jsonrpsee::{ }; use serde::{Deserialize, Serialize}; -use sp_api::ProvideRuntimeApi; +use sp_api::{NumberFor, 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; @@ -96,11 +96,11 @@ 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 @@ -108,49 +108,49 @@ pub trait MmrApi<BlockHash> { #[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`. /// 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 + /// is the same as the order of the entries in `block_numbers` supplied #[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. /// 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 + /// is the same as the order of the entries in `block_numbers` supplied #[method(name = "mmr_generateHistoricalBatchProof")] fn generate_historical_batch_proof( &self, - leaf_indices: Vec<LeafIndex>, - leaves_count: LeafIndex, + block_numbers: Vec<BlockNumber>, + best_known_block_number: BlockNumber, at: Option<BlockHash>, ) -> RpcResult<LeafBatchProof<BlockHash>>; } @@ -169,16 +169,17 @@ 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> MmrApiServer<<Block as BlockT>::Hash, NumberFor<Block>> + 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, NumberFor<Block>>, MmrHash: Codec + Send + Sync + 'static, { fn generate_proof( &self, - leaf_index: LeafIndex, + block_number: NumberFor<Block>, at: Option<<Block as BlockT>::Hash>, ) -> RpcResult<LeafProof<Block::Hash>> { let api = self.client.runtime_api(); @@ -188,7 +189,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)?; @@ -198,7 +199,7 @@ where fn generate_batch_proof( &self, - leaf_indices: Vec<LeafIndex>, + block_numbers: Vec<NumberFor<Block>>, at: Option<<Block as BlockT>::Hash>, ) -> RpcResult<LeafBatchProof<<Block as BlockT>::Hash>> { let api = self.client.runtime_api(); @@ -210,7 +211,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)?; @@ -220,8 +221,8 @@ where fn generate_historical_batch_proof( &self, - leaf_indices: Vec<LeafIndex>, - leaves_count: LeafIndex, + block_numbers: Vec<NumberFor<Block>>, + best_known_block_number: NumberFor<Block>, at: Option<<Block as BlockT>::Hash>, ) -> RpcResult<LeafBatchProof<<Block as BlockT>::Hash>> { let api = self.client.runtime_api(); @@ -233,8 +234,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)?; diff --git a/substrate/frame/merkle-mountain-range/src/lib.rs b/substrate/frame/merkle-mountain-range/src/lib.rs index 8b4f2b60bc1..ad3ce340496 100644 --- a/substrate/frame/merkle-mountain-range/src/lib.rs +++ b/substrate/frame/merkle-mountain-range/src/lib.rs @@ -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, }; @@ -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) diff --git a/substrate/frame/merkle-mountain-range/src/tests.rs b/substrate/frame/merkle-mountain-range/src/tests.rs index bcb775ba028..a63a4330292 100644 --- a/substrate/frame/merkle-mountain-range/src/tests.rs +++ b/substrate/frame/merkle-mountain-range/src/tests.rs @@ -235,22 +235,21 @@ fn should_generate_proofs_correctly() { // to retrieve full leaf data. register_offchain_ext(&mut ext); ext.execute_with(|| { - // when generate proofs for all leaves - let proofs = (0_u64..crate::NumberOfLeaves::<Test>::get()) + let best_block_number = frame_system::Pallet::<Test>::block_number(); + // when generate proofs for all leaves. + let proofs = (1_u64..=best_block_number) .into_iter() - .map(|leaf_index| { - crate::Pallet::<Test>::generate_batch_proof(vec![leaf_index]).unwrap() - }) + .map(|block_num| crate::Pallet::<Test>::generate_batch_proof(vec![block_num]).unwrap()) .collect::<Vec<_>>(); // when generate historical proofs for all leaves - let historical_proofs = (0_u64..crate::NumberOfLeaves::<Test>::get()) + let historical_proofs = (1_u64..best_block_number) .into_iter() - .map(|leaf_index| { + .map(|block_num| { let mut proofs = vec![]; - for leaves_count in leaf_index + 1..=num_blocks { + for leaves_count in block_num..=num_blocks { proofs.push( crate::Pallet::<Test>::generate_historical_batch_proof( - vec![leaf_index], + vec![block_num], leaves_count, ) .unwrap(), @@ -321,7 +320,7 @@ fn should_generate_proofs_correctly() { leaf_count: 3, items: vec![hex( "672c04a9cd05a644789d769daa552d35d8de7c33129f8a7cbf49e595234c4854" - ),], + )], } ) ); @@ -352,6 +351,7 @@ fn should_generate_proofs_correctly() { assert_eq!( proofs[4], ( + // NOTE: the leaf index is equivalent to the block number(in this case 5) - 1 vec![Compact::new(((4, H256::repeat_byte(5)).into(), LeafData::new(5).into(),))], BatchProof { leaf_indices: vec![4], @@ -393,7 +393,7 @@ fn should_generate_proofs_correctly() { } ) ); - assert_eq!(historical_proofs[6][0], proofs[6]); + assert_eq!(historical_proofs[5][1], proofs[5]); }); } @@ -410,11 +410,12 @@ fn should_generate_batch_proof_correctly() { register_offchain_ext(&mut ext); ext.execute_with(|| { // when generate proofs for a batch of leaves - let (.., proof) = crate::Pallet::<Test>::generate_batch_proof(vec![0, 4, 5]).unwrap(); + let (.., proof) = crate::Pallet::<Test>::generate_batch_proof(vec![1, 5, 6]).unwrap(); // then assert_eq!( proof, BatchProof { + // the leaf indices are equivalent to the above specified block numbers - 1. leaf_indices: vec![0, 4, 5], leaf_count: 7, items: vec![ @@ -427,7 +428,7 @@ fn should_generate_batch_proof_correctly() { // when generate historical proofs for a batch of leaves let (.., historical_proof) = - crate::Pallet::<Test>::generate_historical_batch_proof(vec![0, 4, 5], 6).unwrap(); + crate::Pallet::<Test>::generate_historical_batch_proof(vec![1, 5, 6], 6).unwrap(); // then assert_eq!( historical_proof, @@ -443,7 +444,7 @@ fn should_generate_batch_proof_correctly() { // when generate historical proofs for a batch of leaves let (.., historical_proof) = - crate::Pallet::<Test>::generate_historical_batch_proof(vec![0, 4, 5], 7).unwrap(); + crate::Pallet::<Test>::generate_historical_batch_proof(vec![1, 5, 6], 7).unwrap(); // then assert_eq!(historical_proof, proof); }); @@ -500,15 +501,15 @@ fn should_verify() { fn should_verify_batch_proofs() { fn generate_and_verify_batch_proof( ext: &mut sp_io::TestExternalities, - leaf_indices: &Vec<u64>, + block_numbers: &Vec<u64>, blocks_to_add: usize, ) { let (leaves, proof) = ext.execute_with(|| { - crate::Pallet::<Test>::generate_batch_proof(leaf_indices.to_vec()).unwrap() + crate::Pallet::<Test>::generate_batch_proof(block_numbers.to_vec()).unwrap() }); let mmr_size = ext.execute_with(|| crate::Pallet::<Test>::mmr_leaves()); - let min_mmr_size = leaf_indices.iter().max().unwrap() + 1; + let min_mmr_size = block_numbers.iter().max().unwrap() + 1; // generate historical proofs for all possible mmr sizes, // lower bound being index of highest leaf to be proven @@ -516,7 +517,7 @@ fn should_verify_batch_proofs() { .map(|mmr_size| { ext.execute_with(|| { crate::Pallet::<Test>::generate_historical_batch_proof( - leaf_indices.to_vec(), + block_numbers.to_vec(), mmr_size, ) .unwrap() @@ -546,39 +547,41 @@ fn should_verify_batch_proofs() { // to retrieve full leaf data when generating proofs register_offchain_ext(&mut ext); - // verify that up to n=10, valid proofs are generated for all possible leaf combinations - for n in 0..10 { + // verify that up to n=10, valid proofs are generated for all possible block number + // combinations. + for n in 1..=10 { ext.execute_with(|| new_block()); ext.persist_offchain_overlay(); - // generate powerset (skipping empty set) of all possible leaf combinations for mmr size n - let leaves_set: Vec<Vec<u64>> = (0..=n).into_iter().powerset().skip(1).collect(); + // generate powerset (skipping empty set) of all possible block number combinations for mmr + // size n. + let blocks_set: Vec<Vec<u64>> = (1..=n).into_iter().powerset().skip(1).collect(); - leaves_set.iter().for_each(|leaves_subset| { - generate_and_verify_batch_proof(&mut ext, leaves_subset, 0); + blocks_set.iter().for_each(|blocks_subset| { + generate_and_verify_batch_proof(&mut ext, &blocks_subset, 0); ext.persist_offchain_overlay(); }); } - // verify that up to n=15, valid proofs are generated for all possible 2-leaf combinations - for n in 10..15 { - // (MMR Leafs) + // verify that up to n=15, valid proofs are generated for all possible 2-block number + // combinations. + for n in 11..=15 { ext.execute_with(|| new_block()); ext.persist_offchain_overlay(); - // generate all possible 2-leaf combinations for mmr size n - let leaves_set: Vec<Vec<u64>> = (0..=n).into_iter().combinations(2).collect(); + // generate all possible 2-block number combinations for mmr size n. + let blocks_set: Vec<Vec<u64>> = (1..=n).into_iter().combinations(2).collect(); - leaves_set.iter().for_each(|leaves_subset| { - generate_and_verify_batch_proof(&mut ext, leaves_subset, 0); + blocks_set.iter().for_each(|blocks_subset| { + generate_and_verify_batch_proof(&mut ext, &blocks_subset, 0); ext.persist_offchain_overlay(); }); } - generate_and_verify_batch_proof(&mut ext, &vec![7, 11], 20); + generate_and_verify_batch_proof(&mut ext, &vec![8, 12], 20); ext.execute_with(|| add_blocks(1000)); ext.persist_offchain_overlay(); - generate_and_verify_batch_proof(&mut ext, &vec![7, 11, 100, 800], 100); + generate_and_verify_batch_proof(&mut ext, &vec![8, 12, 100, 800], 100); } #[test] @@ -650,11 +653,11 @@ fn should_verify_batch_proof_statelessly() { register_offchain_ext(&mut ext); let (leaves, proof) = ext.execute_with(|| { // when - crate::Pallet::<Test>::generate_batch_proof(vec![0, 4, 5]).unwrap() + crate::Pallet::<Test>::generate_batch_proof(vec![1, 4, 5]).unwrap() }); let (historical_leaves, historical_proof) = ext.execute_with(|| { // when - crate::Pallet::<Test>::generate_historical_batch_proof(vec![0, 4, 5], 6).unwrap() + crate::Pallet::<Test>::generate_historical_batch_proof(vec![1, 4, 5], 6).unwrap() }); // Verify proof without relying on any on-chain data. @@ -920,7 +923,7 @@ fn should_verify_canonicalized() { // Generate proofs for some blocks. let (leaves, proofs) = - ext.execute_with(|| crate::Pallet::<Test>::generate_batch_proof(vec![0, 4, 5, 7]).unwrap()); + ext.execute_with(|| crate::Pallet::<Test>::generate_batch_proof(vec![1, 4, 5, 7]).unwrap()); // Verify all previously generated proofs. ext.execute_with(|| { assert_eq!(crate::Pallet::<Test>::verify_leaves(leaves, proofs), Ok(())); @@ -953,19 +956,19 @@ fn does_not_panic_when_generating_historical_proofs() { // when leaf index is invalid assert_eq!( crate::Pallet::<Test>::generate_historical_batch_proof(vec![10], 7), - Err(Error::LeafNotFound), + Err(Error::BlockNumToLeafIndex), ); // when leaves count is invalid assert_eq!( crate::Pallet::<Test>::generate_historical_batch_proof(vec![3], 100), - Err(Error::InvalidLeavesCount), + Err(Error::BlockNumToLeafIndex), ); // when both leaf index and leaves count are invalid assert_eq!( crate::Pallet::<Test>::generate_historical_batch_proof(vec![10], 100), - Err(Error::InvalidLeavesCount), + Err(Error::BlockNumToLeafIndex), ); }); } diff --git a/substrate/primitives/beefy/src/mmr.rs b/substrate/primitives/beefy/src/mmr.rs index b479d979f13..0edb8babd60 100644 --- a/substrate/primitives/beefy/src/mmr.rs +++ b/substrate/primitives/beefy/src/mmr.rs @@ -142,7 +142,7 @@ pub use mmr_root_provider::MmrRootProvider; mod mmr_root_provider { use super::*; use crate::{known_payloads, payload::PayloadProvider, Payload}; - use sp_api::ProvideRuntimeApi; + use sp_api::{NumberFor, ProvideRuntimeApi}; use sp_mmr_primitives::MmrApi; use sp_runtime::generic::BlockId; use sp_std::{marker::PhantomData, sync::Arc}; @@ -159,7 +159,7 @@ mod mmr_root_provider { where B: Block, R: ProvideRuntimeApi<B>, - R::Api: MmrApi<B, MmrRootHash>, + R::Api: MmrApi<B, MmrRootHash, NumberFor<B>>, { /// Create new BEEFY Payload provider with MMR Root as payload. pub fn new(runtime: Arc<R>) -> Self { @@ -182,7 +182,7 @@ mod mmr_root_provider { where B: Block, R: ProvideRuntimeApi<B>, - R::Api: MmrApi<B, MmrRootHash>, + R::Api: MmrApi<B, MmrRootHash, NumberFor<B>>, { fn payload(&self, header: &B::Header) -> Option<Payload> { self.mmr_root_from_digest_or_runtime(header).map(|mmr_root| { diff --git a/substrate/primitives/merkle-mountain-range/src/lib.rs b/substrate/primitives/merkle-mountain-range/src/lib.rs index 7a26cae839e..06bc1f4bffe 100644 --- a/substrate/primitives/merkle-mountain-range/src/lib.rs +++ b/substrate/primitives/merkle-mountain-range/src/lib.rs @@ -387,6 +387,8 @@ impl<Hash> Proof<Hash> { /// Merkle Mountain Range operation error. #[derive(RuntimeDebug, codec::Encode, codec::Decode, PartialEq, Eq)] pub enum Error { + /// Error during translation of a block number into a leaf index. + BlockNumToLeafIndex, /// Error while pushing new node. Push, /// Error getting the new root. @@ -403,8 +405,8 @@ pub enum Error { PalletNotIncluded, /// Cannot find the requested leaf index InvalidLeafIndex, - /// The provided leaves count is larger than the actual leaves count. - InvalidLeavesCount, + /// The provided best know block number is invalid. + InvalidBestKnownBlock, } impl Error { @@ -434,9 +436,9 @@ impl Error { sp_api::decl_runtime_apis! { /// API to interact with MMR pallet. - pub trait MmrApi<Hash: codec::Codec> { - /// Generate MMR proof for a leaf under given index. - fn generate_proof(leaf_index: LeafIndex) -> Result<(EncodableOpaqueLeaf, Proof<Hash>), Error>; + pub trait MmrApi<Hash: codec::Codec, BlockNumber: codec::Codec> { + /// Generate MMR proof for a block with a specified `block_number`. + fn generate_proof(block_number: BlockNumber) -> Result<(EncodableOpaqueLeaf, Proof<Hash>), Error>; /// Verify MMR proof against on-chain MMR. /// @@ -457,14 +459,13 @@ sp_api::decl_runtime_apis! { /// Return the on-chain MMR root hash. fn mmr_root() -> Result<Hash, Error>; - /// Generate MMR proof for a series of leaves under given indices. - fn generate_batch_proof(leaf_indices: Vec<LeafIndex>) - -> Result<(Vec<EncodableOpaqueLeaf>, BatchProof<Hash>), Error>; + /// Generate MMR proof for a series of blocks with the specified block numbers. + fn generate_batch_proof(block_numbers: Vec<BlockNumber>) -> Result<(Vec<EncodableOpaqueLeaf>, BatchProof<Hash>), Error>; - /// Generate MMR proof for a series of leaves under given indices, using MMR at given `leaves_count` size. + /// Generate MMR proof for a series of `block_numbers`, given the `best_known_block_number`. fn generate_historical_batch_proof( - leaf_indices: Vec<LeafIndex>, - leaves_count: LeafIndex + block_numbers: Vec<BlockNumber>, + best_known_block_number: BlockNumber ) -> Result<(Vec<EncodableOpaqueLeaf>, BatchProof<Hash>), Error>; /// Verify MMR proof against on-chain MMR for a batch of leaves. -- GitLab