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