Skip to content

Commit

Permalink
Add generate and verify logic for AncestryProof (#4430)
Browse files Browse the repository at this point in the history
Extracting the logic for generating and verifying ancestry proofs from
this PR: #1903 with small
adjustments

@Lederstrumpf I added you as a co-author to each commit. Please let me
know if you want me to also associate an e-mail address with your name
  • Loading branch information
serban300 committed May 13, 2024
1 parent 805d54d commit f4b73bd
Show file tree
Hide file tree
Showing 15 changed files with 251 additions and 105 deletions.
13 changes: 11 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion bridges/primitives/beefy/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
pub use binary_merkle_tree::merkle_root;
pub use pallet_beefy_mmr::BeefyEcdsaToEthereum;
pub use pallet_mmr::{
primitives::{DataOrHash as MmrDataOrHash, Proof as MmrProof},
primitives::{DataOrHash as MmrDataOrHash, LeafProof as MmrProof},
verify_leaves_proof as verify_mmr_leaves_proof,
};
pub use sp_consensus_beefy::{
Expand Down
6 changes: 3 additions & 3 deletions polkadot/node/service/src/fake_runtime_api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -272,11 +272,11 @@ sp_api::impl_runtime_apis! {
fn generate_proof(
_: Vec<BlockNumber>,
_: Option<BlockNumber>,
) -> Result<(Vec<sp_mmr_primitives::EncodableOpaqueLeaf>, sp_mmr_primitives::Proof<Hash>), sp_mmr_primitives::Error> {
) -> Result<(Vec<sp_mmr_primitives::EncodableOpaqueLeaf>, sp_mmr_primitives::LeafProof<Hash>), sp_mmr_primitives::Error> {
unimplemented!()
}

fn verify_proof(_: Vec<sp_mmr_primitives::EncodableOpaqueLeaf>, _: sp_mmr_primitives::Proof<Hash>)
fn verify_proof(_: Vec<sp_mmr_primitives::EncodableOpaqueLeaf>, _: sp_mmr_primitives::LeafProof<Hash>)
-> Result<(), sp_mmr_primitives::Error>
{
unimplemented!()
Expand All @@ -285,7 +285,7 @@ sp_api::impl_runtime_apis! {
fn verify_proof_stateless(
_: Hash,
_: Vec<sp_mmr_primitives::EncodableOpaqueLeaf>,
_: sp_mmr_primitives::Proof<Hash>
_: sp_mmr_primitives::LeafProof<Hash>
) -> Result<(), sp_mmr_primitives::Error> {
unimplemented!()
}
Expand Down
6 changes: 3 additions & 3 deletions polkadot/runtime/rococo/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2134,7 +2134,7 @@ sp_api::impl_runtime_apis! {
fn generate_proof(
block_numbers: Vec<BlockNumber>,
best_known_block_number: Option<BlockNumber>,
) -> Result<(Vec<mmr::EncodableOpaqueLeaf>, mmr::Proof<mmr::Hash>), mmr::Error> {
) -> Result<(Vec<mmr::EncodableOpaqueLeaf>, mmr::LeafProof<mmr::Hash>), mmr::Error> {
Mmr::generate_proof(block_numbers, best_known_block_number).map(
|(leaves, proof)| {
(
Expand All @@ -2148,7 +2148,7 @@ sp_api::impl_runtime_apis! {
)
}

fn verify_proof(leaves: Vec<mmr::EncodableOpaqueLeaf>, proof: mmr::Proof<mmr::Hash>)
fn verify_proof(leaves: Vec<mmr::EncodableOpaqueLeaf>, proof: mmr::LeafProof<mmr::Hash>)
-> Result<(), mmr::Error>
{
let leaves = leaves.into_iter().map(|leaf|
Expand All @@ -2161,7 +2161,7 @@ sp_api::impl_runtime_apis! {
fn verify_proof_stateless(
root: mmr::Hash,
leaves: Vec<mmr::EncodableOpaqueLeaf>,
proof: mmr::Proof<mmr::Hash>
proof: mmr::LeafProof<mmr::Hash>
) -> Result<(), mmr::Error> {
let nodes = leaves.into_iter().map(|leaf|mmr::DataOrHash::Data(leaf.into_opaque_leaf())).collect();
pallet_mmr::verify_leaves_proof::<mmr::Hashing, _>(root, nodes, proof)
Expand Down
6 changes: 3 additions & 3 deletions polkadot/runtime/test-runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1044,11 +1044,11 @@ sp_api::impl_runtime_apis! {
fn generate_proof(
_block_numbers: Vec<BlockNumber>,
_best_known_block_number: Option<BlockNumber>,
) -> Result<(Vec<mmr::EncodableOpaqueLeaf>, mmr::Proof<Hash>), mmr::Error> {
) -> Result<(Vec<mmr::EncodableOpaqueLeaf>, mmr::LeafProof<Hash>), mmr::Error> {
Err(mmr::Error::PalletNotIncluded)
}

fn verify_proof(_leaves: Vec<mmr::EncodableOpaqueLeaf>, _proof: mmr::Proof<Hash>)
fn verify_proof(_leaves: Vec<mmr::EncodableOpaqueLeaf>, _proof: mmr::LeafProof<Hash>)
-> Result<(), mmr::Error>
{
Err(mmr::Error::PalletNotIncluded)
Expand All @@ -1057,7 +1057,7 @@ sp_api::impl_runtime_apis! {
fn verify_proof_stateless(
_root: Hash,
_leaves: Vec<mmr::EncodableOpaqueLeaf>,
_proof: mmr::Proof<Hash>
_proof: mmr::LeafProof<Hash>
) -> Result<(), mmr::Error> {
Err(mmr::Error::PalletNotIncluded)
}
Expand Down
6 changes: 3 additions & 3 deletions polkadot/runtime/westend/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2013,7 +2013,7 @@ sp_api::impl_runtime_apis! {
fn generate_proof(
block_numbers: Vec<BlockNumber>,
best_known_block_number: Option<BlockNumber>,
) -> Result<(Vec<mmr::EncodableOpaqueLeaf>, mmr::Proof<mmr::Hash>), mmr::Error> {
) -> Result<(Vec<mmr::EncodableOpaqueLeaf>, mmr::LeafProof<mmr::Hash>), mmr::Error> {
Mmr::generate_proof(block_numbers, best_known_block_number).map(
|(leaves, proof)| {
(
Expand All @@ -2027,7 +2027,7 @@ sp_api::impl_runtime_apis! {
)
}

fn verify_proof(leaves: Vec<mmr::EncodableOpaqueLeaf>, proof: mmr::Proof<mmr::Hash>)
fn verify_proof(leaves: Vec<mmr::EncodableOpaqueLeaf>, proof: mmr::LeafProof<mmr::Hash>)
-> Result<(), mmr::Error>
{
let leaves = leaves.into_iter().map(|leaf|
Expand All @@ -2040,7 +2040,7 @@ sp_api::impl_runtime_apis! {
fn verify_proof_stateless(
root: mmr::Hash,
leaves: Vec<mmr::EncodableOpaqueLeaf>,
proof: mmr::Proof<mmr::Hash>
proof: mmr::LeafProof<mmr::Hash>
) -> Result<(), mmr::Error> {
let nodes = leaves.into_iter().map(|leaf|mmr::DataOrHash::Data(leaf.into_opaque_leaf())).collect();
pallet_mmr::verify_leaves_proof::<mmr::Hashing, _>(root, nodes, proof)
Expand Down
6 changes: 3 additions & 3 deletions substrate/bin/node/runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3094,7 +3094,7 @@ impl_runtime_apis! {
fn generate_proof(
block_numbers: Vec<BlockNumber>,
best_known_block_number: Option<BlockNumber>,
) -> Result<(Vec<mmr::EncodableOpaqueLeaf>, mmr::Proof<mmr::Hash>), mmr::Error> {
) -> Result<(Vec<mmr::EncodableOpaqueLeaf>, mmr::LeafProof<mmr::Hash>), mmr::Error> {
Mmr::generate_proof(block_numbers, best_known_block_number).map(
|(leaves, proof)| {
(
Expand All @@ -3108,7 +3108,7 @@ impl_runtime_apis! {
)
}

fn verify_proof(leaves: Vec<mmr::EncodableOpaqueLeaf>, proof: mmr::Proof<mmr::Hash>)
fn verify_proof(leaves: Vec<mmr::EncodableOpaqueLeaf>, proof: mmr::LeafProof<mmr::Hash>)
-> Result<(), mmr::Error>
{
let leaves = leaves.into_iter().map(|leaf|
Expand All @@ -3121,7 +3121,7 @@ impl_runtime_apis! {
fn verify_proof_stateless(
root: mmr::Hash,
leaves: Vec<mmr::EncodableOpaqueLeaf>,
proof: mmr::Proof<mmr::Hash>
proof: mmr::LeafProof<mmr::Hash>
) -> Result<(), mmr::Error> {
let nodes = leaves.into_iter().map(|leaf|mmr::DataOrHash::Data(leaf.into_opaque_leaf())).collect();
pallet_mmr::verify_leaves_proof::<mmr::Hashing, _>(root, nodes, proof)
Expand Down
16 changes: 8 additions & 8 deletions substrate/client/merkle-mountain-range/rpc/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ use sp_core::{
offchain::{storage::OffchainDb, OffchainDbExt, OffchainStorage},
Bytes,
};
use sp_mmr_primitives::{Error as MmrError, Proof};
use sp_mmr_primitives::{Error as MmrError, LeafProof};
use sp_runtime::traits::{Block as BlockT, NumberFor};

pub use sp_mmr_primitives::MmrApi as MmrRuntimeApi;
Expand All @@ -52,17 +52,17 @@ pub struct LeavesProof<BlockHash> {
pub block_hash: BlockHash,
/// SCALE-encoded vector of `LeafData`.
pub leaves: Bytes,
/// SCALE-encoded proof data. See [sp_mmr_primitives::Proof].
/// SCALE-encoded proof data. See [sp_mmr_primitives::LeafProof].
pub proof: Bytes,
}

impl<BlockHash> LeavesProof<BlockHash> {
/// Create new `LeavesProof` from a given vector of `Leaf` and a
/// [sp_mmr_primitives::Proof].
/// [sp_mmr_primitives::LeafProof].
pub fn new<Leaf, MmrHash>(
block_hash: BlockHash,
leaves: Vec<Leaf>,
proof: Proof<MmrHash>,
proof: LeafProof<MmrHash>,
) -> Self
where
Leaf: Encode,
Expand Down Expand Up @@ -258,7 +258,7 @@ mod tests {
fn should_serialize_leaf_proof() {
// given
let leaf = vec![1_u8, 2, 3, 4];
let proof = Proof {
let proof = LeafProof {
leaf_indices: vec![1],
leaf_count: 9,
items: vec![H256::repeat_byte(1), H256::repeat_byte(2)],
Expand All @@ -281,7 +281,7 @@ mod tests {
// given
let leaf_a = vec![1_u8, 2, 3, 4];
let leaf_b = vec![2_u8, 2, 3, 4];
let proof = Proof {
let proof = LeafProof {
leaf_indices: vec![1, 2],
leaf_count: 9,
items: vec![H256::repeat_byte(1), H256::repeat_byte(2)],
Expand All @@ -306,7 +306,7 @@ mod tests {
block_hash: H256::repeat_byte(0),
leaves: Bytes(vec![vec![1_u8, 2, 3, 4]].encode()),
proof: Bytes(
Proof {
LeafProof {
leaf_indices: vec![1],
leaf_count: 9,
items: vec![H256::repeat_byte(1), H256::repeat_byte(2)],
Expand All @@ -333,7 +333,7 @@ mod tests {
block_hash: H256::repeat_byte(0),
leaves: Bytes(vec![vec![1_u8, 2, 3, 4], vec![2_u8, 2, 3, 4]].encode()),
proof: Bytes(
Proof {
LeafProof {
leaf_indices: vec![1, 2],
leaf_count: 9,
items: vec![H256::repeat_byte(1), H256::repeat_byte(2)],
Expand Down
6 changes: 3 additions & 3 deletions substrate/client/merkle-mountain-range/src/test_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -309,11 +309,11 @@ sp_api::mock_impl_runtime_apis! {
&self,
_block_numbers: Vec<u64>,
_best_known_block_number: Option<u64>,
) -> Result<(Vec<mmr::EncodableOpaqueLeaf>, mmr::Proof<MmrHash>), mmr::Error> {
) -> Result<(Vec<mmr::EncodableOpaqueLeaf>, mmr::LeafProof<MmrHash>), mmr::Error> {
Err(mmr::Error::PalletNotIncluded)
}

fn verify_proof(_leaves: Vec<mmr::EncodableOpaqueLeaf>, _proof: mmr::Proof<MmrHash>)
fn verify_proof(_leaves: Vec<mmr::EncodableOpaqueLeaf>, _proof: mmr::LeafProof<MmrHash>)
-> Result<(), mmr::Error>
{
Err(mmr::Error::PalletNotIncluded)
Expand All @@ -322,7 +322,7 @@ sp_api::mock_impl_runtime_apis! {
fn verify_proof_stateless(
_root: MmrHash,
_leaves: Vec<mmr::EncodableOpaqueLeaf>,
_proof: mmr::Proof<MmrHash>
_proof: mmr::LeafProof<MmrHash>
) -> Result<(), mmr::Error> {
Err(mmr::Error::PalletNotIncluded)
}
Expand Down
48 changes: 38 additions & 10 deletions substrate/frame/merkle-mountain-range/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -260,15 +260,15 @@ pub mod pallet {

/// Stateless MMR proof verification for batch of leaves.
///
/// This function can be used to verify received MMR [primitives::Proof] (`proof`)
/// This function can be used to verify received MMR [primitives::LeafProof] (`proof`)
/// for given leaves set (`leaves`) against a known MMR root hash (`root`).
/// Note, the leaves should be sorted such that corresponding leaves and leaf indices have the
/// same position in both the `leaves` vector and the `leaf_indices` vector contained in the
/// [primitives::Proof].
/// [primitives::LeafProof].
pub fn verify_leaves_proof<H, L>(
root: H::Output,
leaves: Vec<mmr::Node<H, L>>,
proof: primitives::Proof<H::Output>,
proof: primitives::LeafProof<H::Output>,
) -> Result<(), primitives::Error>
where
H: traits::Hash,
Expand Down Expand Up @@ -342,7 +342,7 @@ impl<T: Config<I>, I: 'static> Pallet<T, I> {
pub fn generate_proof(
block_numbers: Vec<BlockNumberFor<T>>,
best_known_block_number: Option<BlockNumberFor<T>>,
) -> Result<(Vec<LeafOf<T, I>>, primitives::Proof<HashOf<T, I>>), primitives::Error> {
) -> Result<(Vec<LeafOf<T, I>>, primitives::LeafProof<HashOf<T, I>>), primitives::Error> {
// check whether best_known_block_number provided, else use current best block
let best_known_block_number =
best_known_block_number.unwrap_or_else(|| <frame_system::Pallet<T>>::block_number());
Expand All @@ -362,11 +362,6 @@ impl<T: Config<I>, I: 'static> Pallet<T, I> {
mmr.generate_proof(leaf_indices)
}

/// Return the on-chain MMR root hash.
pub fn mmr_root() -> HashOf<T, I> {
RootHash::<T, I>::get()
}

/// Verify MMR proof for given `leaves`.
///
/// This method is safe to use within the runtime code.
Expand All @@ -375,7 +370,7 @@ impl<T: Config<I>, I: 'static> Pallet<T, I> {
/// or the proof is invalid.
pub fn verify_leaves(
leaves: Vec<LeafOf<T, I>>,
proof: primitives::Proof<HashOf<T, I>>,
proof: primitives::LeafProof<HashOf<T, I>>,
) -> Result<(), primitives::Error> {
if proof.leaf_count > NumberOfLeaves::<T, I>::get() ||
proof.leaf_count == 0 ||
Expand All @@ -393,4 +388,37 @@ impl<T: Config<I>, I: 'static> Pallet<T, I> {
Err(primitives::Error::Verify.log_debug("The proof is incorrect."))
}
}

pub fn generate_ancestry_proof(
prev_block_number: BlockNumberFor<T>,
best_known_block_number: Option<BlockNumberFor<T>>,
) -> Result<primitives::AncestryProof<HashOf<T, I>>, Error> {
// check whether best_known_block_number provided, else use current best block
let best_known_block_number =
best_known_block_number.unwrap_or_else(|| <frame_system::Pallet<T>>::block_number());

let leaf_count = Self::block_num_to_leaf_index(best_known_block_number)?.saturating_add(1);
let prev_leaf_count = Self::block_num_to_leaf_index(prev_block_number)?.saturating_add(1);

let mmr: ModuleMmr<mmr::storage::OffchainStorage, T, I> = mmr::Mmr::new(leaf_count);
mmr.generate_ancestry_proof(prev_leaf_count)
}

pub fn verify_ancestry_proof(
ancestry_proof: primitives::AncestryProof<HashOf<T, I>>,
) -> Result<(), Error> {
let mmr: ModuleMmr<mmr::storage::OffchainStorage, T, I> =
mmr::Mmr::new(ancestry_proof.leaf_count);
let is_valid = mmr.verify_ancestry_proof(ancestry_proof)?;
if is_valid {
Ok(())
} else {
Err(Error::Verify.log_debug("The ancestry proof is incorrect."))
}
}

/// Return the on-chain MMR root hash.
pub fn mmr_root() -> HashOf<T, I> {
RootHash::<T, I>::get()
}
}
Loading

0 comments on commit f4b73bd

Please sign in to comment.