From 2ccf7c0f237cc16cb7da659b1b51da5b6a5c085a Mon Sep 17 00:00:00 2001 From: Robert Hambrock Date: Mon, 17 Oct 2022 17:44:19 +0200 Subject: [PATCH 01/21] histor. batch proof: make best block arg optional --- bin/node/runtime/src/lib.rs | 2 +- client/beefy/src/tests.rs | 2 +- frame/merkle-mountain-range/rpc/src/lib.rs | 16 +++++----- frame/merkle-mountain-range/src/lib.rs | 16 ++++++---- frame/merkle-mountain-range/src/tests.rs | 35 ++++++++++----------- primitives/merkle-mountain-range/src/lib.rs | 8 ++--- 6 files changed, 42 insertions(+), 37 deletions(-) diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index f137b36eff036..2193b6d52c3ae 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -2071,7 +2071,7 @@ impl_runtime_apis! { fn generate_historical_batch_proof( block_numbers: Vec, - best_known_block_number: BlockNumber, + best_known_block_number: Option, ) -> Result<(Vec, mmr::BatchProof), mmr::Error> { Mmr::generate_historical_batch_proof(block_numbers, best_known_block_number).map( |(leaves, proof)| { diff --git a/client/beefy/src/tests.rs b/client/beefy/src/tests.rs index 89be1cac4f886..cdfb5242e2d90 100644 --- a/client/beefy/src/tests.rs +++ b/client/beefy/src/tests.rs @@ -274,7 +274,7 @@ macro_rules! create_test_api { fn generate_historical_batch_proof( _block_numbers: Vec, - _best_known_block_number: u64 + _best_known_block_number: Option ) -> Result<(Vec, BatchProof), MmrError> { unimplemented!() } diff --git a/frame/merkle-mountain-range/rpc/src/lib.rs b/frame/merkle-mountain-range/rpc/src/lib.rs index ffc7ac2da56bf..70c89ea229d6d 100644 --- a/frame/merkle-mountain-range/rpc/src/lib.rs +++ b/frame/merkle-mountain-range/rpc/src/lib.rs @@ -129,17 +129,19 @@ pub trait MmrApi { at: Option, ) -> RpcResult>; - /// Generate a MMR proof for the given `block_numbers` given the `best_known_block_number`. + /// Generate a MMR proof for the given `block_numbers`. /// /// This method calls into a runtime with MMR pallet included and attempts to generate /// 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 `best_known_block_number`, which already points to + /// Optionally via `at`, a block hash at which the runtime should be queried can be specified. + /// Optionally via `best_known_block_number`, the proof can be generated using the MMR's state + /// at a specific best block. Note that if `best_known_block_number` is provided, then also + /// specifying the block hash via `at` 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 `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 @@ -150,7 +152,7 @@ pub trait MmrApi { fn generate_historical_batch_proof( &self, block_numbers: Vec, - best_known_block_number: BlockNumber, + best_known_block_number: Option, at: Option, ) -> RpcResult>; } @@ -222,7 +224,7 @@ where fn generate_historical_batch_proof( &self, block_numbers: Vec>, - best_known_block_number: NumberFor, + best_known_block_number: Option>, at: Option<::Hash>, ) -> RpcResult::Hash>> { let api = self.client.runtime_api(); diff --git a/frame/merkle-mountain-range/src/lib.rs b/frame/merkle-mountain-range/src/lib.rs index 92ab8702b65c0..4b27991307c4e 100644 --- a/frame/merkle-mountain-range/src/lib.rs +++ b/frame/merkle-mountain-range/src/lib.rs @@ -393,13 +393,13 @@ impl, I: 'static> Pallet { (Vec>, primitives::BatchProof<>::Hash>), primitives::Error, > { - Self::generate_historical_batch_proof( - block_numbers, - >::block_number(), - ) + Self::generate_historical_batch_proof(block_numbers, None) } - /// Generate a MMR proof for the given `block_numbers` given the `best_known_block_number`. + /// Generate a MMR proof for the given `block_numbers`. + /// If `best_known_block_number = Some(n)`, this generates a historical proof for + /// the head of the chain was at height `n`. + /// Else it generates a proof for the MMR at the current block height. /// /// Note this method can only be used from an off-chain context /// (Offchain Worker or Runtime API call), since it requires @@ -407,11 +407,15 @@ impl, I: 'static> Pallet { /// It may return an error or panic if used incorrectly. pub fn generate_historical_batch_proof( block_numbers: Vec, - best_known_block_number: T::BlockNumber, + best_known_block_number: Option, ) -> Result< (Vec>, primitives::BatchProof<>::Hash>), 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(|| >::block_number()); + let leaves_count = Self::block_num_to_leaf_index(best_known_block_number)?.saturating_add(1); diff --git a/frame/merkle-mountain-range/src/tests.rs b/frame/merkle-mountain-range/src/tests.rs index dbbdc12c8e1d5..30b8c022a7cfe 100644 --- a/frame/merkle-mountain-range/src/tests.rs +++ b/frame/merkle-mountain-range/src/tests.rs @@ -243,11 +243,11 @@ fn should_generate_proofs_correctly() { .into_iter() .map(|block_num| { let mut proofs = vec![]; - for leaves_count in block_num..=num_blocks { + for historical_best_block in block_num..=num_blocks { proofs.push( crate::Pallet::::generate_historical_batch_proof( vec![block_num], - leaves_count, + Some(historical_best_block), ) .unwrap(), ) @@ -425,7 +425,7 @@ fn should_generate_batch_proof_correctly() { // when generate historical proofs for a batch of leaves let (.., historical_proof) = - crate::Pallet::::generate_historical_batch_proof(vec![1, 5, 6], 6).unwrap(); + crate::Pallet::::generate_historical_batch_proof(vec![1, 5, 6], Some(6)).unwrap(); // then assert_eq!( historical_proof, @@ -441,7 +441,7 @@ fn should_generate_batch_proof_correctly() { // when generate historical proofs for a batch of leaves let (.., historical_proof) = - crate::Pallet::::generate_historical_batch_proof(vec![1, 5, 6], 7).unwrap(); + crate::Pallet::::generate_historical_batch_proof(vec![1, 5, 6], None).unwrap(); // then assert_eq!(historical_proof, proof); }); @@ -466,11 +466,11 @@ fn should_verify() { }); let (simple_historical_leaves, simple_historical_proof5) = ext.execute_with(|| { // when - crate::Pallet::::generate_historical_batch_proof(vec![5], 6).unwrap() + crate::Pallet::::generate_historical_batch_proof(vec![5], Some(6)).unwrap() }); let (advanced_historical_leaves, advanced_historical_proof5) = ext.execute_with(|| { // when - crate::Pallet::::generate_historical_batch_proof(vec![5], 7).unwrap() + crate::Pallet::::generate_historical_batch_proof(vec![5], Some(7)).unwrap() }); ext.execute_with(|| { @@ -505,17 +505,16 @@ fn should_verify_batch_proofs() { crate::Pallet::::generate_batch_proof(block_numbers.to_vec()).unwrap() }); - let mmr_size = ext.execute_with(|| crate::Pallet::::mmr_leaves()); - let min_mmr_size = block_numbers.iter().max().unwrap() + 1; + let max_block_number = ext.execute_with(|| frame_system::Pallet::::block_number()); + let min_block_number = block_numbers.iter().max().unwrap() + 1; - // generate historical proofs for all possible mmr sizes, - // lower bound being index of highest leaf to be proven - let historical_proofs = (min_mmr_size..=mmr_size) - .map(|mmr_size| { + // generate all possible historical proofs for the given blocks + let historical_proofs = (min_block_number..=max_block_number) + .map(|best_block| { ext.execute_with(|| { crate::Pallet::::generate_historical_batch_proof( block_numbers.to_vec(), - mmr_size, + Some(best_block), ) .unwrap() }) @@ -606,7 +605,7 @@ fn verification_should_be_stateless() { }); let (_, historical_proof5) = ext.execute_with(|| { // when - crate::Pallet::::generate_historical_batch_proof(vec![5], 6).unwrap() + crate::Pallet::::generate_historical_batch_proof(vec![5], Some(6)).unwrap() }); // Verify proof without relying on any on-chain data. @@ -654,7 +653,7 @@ fn should_verify_batch_proof_statelessly() { }); let (historical_leaves, historical_proof) = ext.execute_with(|| { // when - crate::Pallet::::generate_historical_batch_proof(vec![1, 4, 5], 6).unwrap() + crate::Pallet::::generate_historical_batch_proof(vec![1, 4, 5], Some(6)).unwrap() }); // Verify proof without relying on any on-chain data. @@ -960,19 +959,19 @@ fn does_not_panic_when_generating_historical_proofs() { ext.execute_with(|| { // when leaf index is invalid assert_eq!( - crate::Pallet::::generate_historical_batch_proof(vec![10], 7), + crate::Pallet::::generate_historical_batch_proof(vec![10], None), Err(Error::BlockNumToLeafIndex), ); // when leaves count is invalid assert_eq!( - crate::Pallet::::generate_historical_batch_proof(vec![3], 100), + crate::Pallet::::generate_historical_batch_proof(vec![3], Some(100)), Err(Error::BlockNumToLeafIndex), ); // when both leaf index and leaves count are invalid assert_eq!( - crate::Pallet::::generate_historical_batch_proof(vec![10], 100), + crate::Pallet::::generate_historical_batch_proof(vec![10], Some(100)), Err(Error::BlockNumToLeafIndex), ); }); diff --git a/primitives/merkle-mountain-range/src/lib.rs b/primitives/merkle-mountain-range/src/lib.rs index 06bc1f4bffe84..81b91f59d0af1 100644 --- a/primitives/merkle-mountain-range/src/lib.rs +++ b/primitives/merkle-mountain-range/src/lib.rs @@ -462,16 +462,16 @@ sp_api::decl_runtime_apis! { /// Generate MMR proof for a series of blocks with the specified block numbers. fn generate_batch_proof(block_numbers: Vec) -> Result<(Vec, BatchProof), Error>; - /// Generate MMR proof for a series of `block_numbers`, given the `best_known_block_number`. + /// Generate MMR proof for a series of block numbers. If `best_known_block_number = Some(n)`, + /// use historical MMR state at given block height `n`. Else, use current MMR state. fn generate_historical_batch_proof( block_numbers: Vec, - best_known_block_number: BlockNumber + best_known_block_number: Option ) -> Result<(Vec, BatchProof), Error>; /// Verify MMR proof against on-chain MMR for a batch of leaves. /// - /// Note this function will use on-chain MMR root hash and check if the proof - /// matches the hash. + /// Note this function will use on-chain MMR root hash and check if the proof matches the hash. /// 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 [BatchProof] fn verify_batch_proof(leaves: Vec, proof: BatchProof) -> Result<(), Error>; From 019d5cdb052fb637875380a6dee343d16c51b901 Mon Sep 17 00:00:00 2001 From: Robert Hambrock Date: Mon, 17 Oct 2022 22:42:51 +0200 Subject: [PATCH 02/21] correct testing range --- frame/merkle-mountain-range/src/tests.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frame/merkle-mountain-range/src/tests.rs b/frame/merkle-mountain-range/src/tests.rs index 30b8c022a7cfe..5069414585d58 100644 --- a/frame/merkle-mountain-range/src/tests.rs +++ b/frame/merkle-mountain-range/src/tests.rs @@ -506,10 +506,10 @@ fn should_verify_batch_proofs() { }); let max_block_number = ext.execute_with(|| frame_system::Pallet::::block_number()); - let min_block_number = block_numbers.iter().max().unwrap() + 1; + let min_block_number = block_numbers.iter().max().unwrap(); // generate all possible historical proofs for the given blocks - let historical_proofs = (min_block_number..=max_block_number) + let historical_proofs = (*min_block_number..=max_block_number) .map(|best_block| { ext.execute_with(|| { crate::Pallet::::generate_historical_batch_proof( From deb12a40a094aaa0c498228c2f770f53daa96c63 Mon Sep 17 00:00:00 2001 From: Robert Hambrock Date: Tue, 18 Oct 2022 13:43:51 +0200 Subject: [PATCH 03/21] make generate_batch_proof stub for historical --- bin/node/runtime/src/lib.rs | 2 +- frame/merkle-mountain-range/rpc/src/lib.rs | 16 +--------------- frame/merkle-mountain-range/src/tests.rs | 5 ++++- 3 files changed, 6 insertions(+), 17 deletions(-) diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index 2193b6d52c3ae..bbaf565bc9c22 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -2058,7 +2058,7 @@ impl_runtime_apis! { fn generate_batch_proof( block_numbers: Vec, ) -> Result<(Vec, mmr::BatchProof), mmr::Error> { - Mmr::generate_batch_proof(block_numbers).map(|(leaves, proof)| { + Mmr::generate_historical_batch_proof(block_numbers, None).map(|(leaves, proof)| { ( leaves .into_iter() diff --git a/frame/merkle-mountain-range/rpc/src/lib.rs b/frame/merkle-mountain-range/rpc/src/lib.rs index 70c89ea229d6d..adcb76902dc54 100644 --- a/frame/merkle-mountain-range/rpc/src/lib.rs +++ b/frame/merkle-mountain-range/rpc/src/lib.rs @@ -204,21 +204,7 @@ where block_numbers: Vec>, at: Option<::Hash>, ) -> RpcResult::Hash>> { - let api = self.client.runtime_api(); - let block_hash = at.unwrap_or_else(|| - // If the block hash is not supplied assume the best block. - self.client.info().best_hash); - - let (leaves, proof) = api - .generate_batch_proof_with_context( - &BlockId::hash(block_hash), - sp_core::ExecutionContext::OffchainCall(None), - block_numbers, - ) - .map_err(runtime_error_into_rpc_error)? - .map_err(mmr_error_into_rpc_error)?; - - Ok(LeafBatchProof::new(block_hash, leaves, proof)) + self.generate_historical_batch_proof(block_numbers, None, at) } fn generate_historical_batch_proof( diff --git a/frame/merkle-mountain-range/src/tests.rs b/frame/merkle-mountain-range/src/tests.rs index 5069414585d58..7bcb22c297228 100644 --- a/frame/merkle-mountain-range/src/tests.rs +++ b/frame/merkle-mountain-range/src/tests.rs @@ -236,7 +236,10 @@ fn should_generate_proofs_correctly() { // when generate proofs for all leaves. let proofs = (1_u64..=best_block_number) .into_iter() - .map(|block_num| crate::Pallet::::generate_batch_proof(vec![block_num]).unwrap()) + .map(|block_num| { + crate::Pallet::::generate_historical_batch_proof(vec![block_num], None) + .unwrap() + }) .collect::>(); // when generate historical proofs for all leaves let historical_proofs = (1_u64..best_block_number) From 5ffff0193b1fcfd91859150b43b2d7199addec0a Mon Sep 17 00:00:00 2001 From: Robert Hambrock Date: Tue, 18 Oct 2022 14:24:24 +0200 Subject: [PATCH 04/21] merge generate_{historical_}batch_proof functions --- bin/node/runtime/src/lib.rs | 18 +-------- client/beefy/src/tests.rs | 6 +-- frame/merkle-mountain-range/rpc/src/lib.rs | 29 +------------- frame/merkle-mountain-range/src/lib.rs | 17 +------- frame/merkle-mountain-range/src/tests.rs | 44 ++++++++++----------- primitives/merkle-mountain-range/src/lib.rs | 5 +-- 6 files changed, 29 insertions(+), 90 deletions(-) diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index bbaf565bc9c22..8bc589a9a1992 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -2024,7 +2024,7 @@ impl_runtime_apis! { fn generate_proof(block_number: BlockNumber) -> Result<(mmr::EncodableOpaqueLeaf, mmr::Proof), mmr::Error> { - Mmr::generate_batch_proof(vec![block_number]).and_then(|(leaves, proof)| + Mmr::generate_batch_proof(vec![block_number], None).and_then(|(leaves, proof)| Ok(( mmr::EncodableOpaqueLeaf::from_leaf(&leaves[0]), mmr::BatchProof::into_single_leaf_proof(proof)? @@ -2057,23 +2057,9 @@ impl_runtime_apis! { fn generate_batch_proof( block_numbers: Vec, - ) -> Result<(Vec, mmr::BatchProof), mmr::Error> { - Mmr::generate_historical_batch_proof(block_numbers, None).map(|(leaves, proof)| { - ( - leaves - .into_iter() - .map(|leaf| mmr::EncodableOpaqueLeaf::from_leaf(&leaf)) - .collect(), - proof, - ) - }) - } - - fn generate_historical_batch_proof( - block_numbers: Vec, best_known_block_number: Option, ) -> Result<(Vec, mmr::BatchProof), mmr::Error> { - Mmr::generate_historical_batch_proof(block_numbers, best_known_block_number).map( + Mmr::generate_batch_proof(block_numbers, best_known_block_number).map( |(leaves, proof)| { ( leaves diff --git a/client/beefy/src/tests.rs b/client/beefy/src/tests.rs index cdfb5242e2d90..87f57672b2741 100644 --- a/client/beefy/src/tests.rs +++ b/client/beefy/src/tests.rs @@ -268,11 +268,7 @@ macro_rules! create_test_api { Ok($mmr_root) } - fn generate_batch_proof(_block_numbers: Vec) -> Result<(Vec, BatchProof), MmrError> { - unimplemented!() - } - - fn generate_historical_batch_proof( + fn generate_batch_proof( _block_numbers: Vec, _best_known_block_number: Option ) -> Result<(Vec, BatchProof), MmrError> { diff --git a/frame/merkle-mountain-range/rpc/src/lib.rs b/frame/merkle-mountain-range/rpc/src/lib.rs index adcb76902dc54..c848c2e6a8d52 100644 --- a/frame/merkle-mountain-range/rpc/src/lib.rs +++ b/frame/merkle-mountain-range/rpc/src/lib.rs @@ -112,23 +112,6 @@ pub trait MmrApi { at: Option, ) -> RpcResult>; - /// 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 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 `block_numbers` supplied - #[method(name = "mmr_generateBatchProof")] - fn generate_batch_proof( - &self, - block_numbers: Vec, - at: Option, - ) -> RpcResult>; - /// Generate a MMR proof for the given `block_numbers`. /// /// This method calls into a runtime with MMR pallet included and attempts to generate @@ -149,7 +132,7 @@ pub trait MmrApi { /// The order of entries in the `leaves` field of the returned struct /// is the same as the order of the entries in `block_numbers` supplied #[method(name = "mmr_generateHistoricalBatchProof")] - fn generate_historical_batch_proof( + fn generate_batch_proof( &self, block_numbers: Vec, best_known_block_number: Option, @@ -200,14 +183,6 @@ where } fn generate_batch_proof( - &self, - block_numbers: Vec>, - at: Option<::Hash>, - ) -> RpcResult::Hash>> { - self.generate_historical_batch_proof(block_numbers, None, at) - } - - fn generate_historical_batch_proof( &self, block_numbers: Vec>, best_known_block_number: Option>, @@ -219,7 +194,7 @@ where self.client.info().best_hash); let (leaves, proof) = api - .generate_historical_batch_proof_with_context( + .generate_batch_proof_with_context( &BlockId::hash(block_hash), sp_core::ExecutionContext::OffchainCall(None), block_numbers, diff --git a/frame/merkle-mountain-range/src/lib.rs b/frame/merkle-mountain-range/src/lib.rs index 4b27991307c4e..429931165afd0 100644 --- a/frame/merkle-mountain-range/src/lib.rs +++ b/frame/merkle-mountain-range/src/lib.rs @@ -381,21 +381,6 @@ impl, I: 'static> Pallet { 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( - block_numbers: Vec, - ) -> Result< - (Vec>, primitives::BatchProof<>::Hash>), - primitives::Error, - > { - Self::generate_historical_batch_proof(block_numbers, None) - } - /// Generate a MMR proof for the given `block_numbers`. /// If `best_known_block_number = Some(n)`, this generates a historical proof for /// the head of the chain was at height `n`. @@ -405,7 +390,7 @@ impl, I: 'static> Pallet { /// (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( + pub fn generate_batch_proof( block_numbers: Vec, best_known_block_number: Option, ) -> Result< diff --git a/frame/merkle-mountain-range/src/tests.rs b/frame/merkle-mountain-range/src/tests.rs index 7bcb22c297228..e970731f96f64 100644 --- a/frame/merkle-mountain-range/src/tests.rs +++ b/frame/merkle-mountain-range/src/tests.rs @@ -237,8 +237,7 @@ fn should_generate_proofs_correctly() { let proofs = (1_u64..=best_block_number) .into_iter() .map(|block_num| { - crate::Pallet::::generate_historical_batch_proof(vec![block_num], None) - .unwrap() + crate::Pallet::::generate_batch_proof(vec![block_num], None).unwrap() }) .collect::>(); // when generate historical proofs for all leaves @@ -248,7 +247,7 @@ fn should_generate_proofs_correctly() { let mut proofs = vec![]; for historical_best_block in block_num..=num_blocks { proofs.push( - crate::Pallet::::generate_historical_batch_proof( + crate::Pallet::::generate_batch_proof( vec![block_num], Some(historical_best_block), ) @@ -410,7 +409,7 @@ 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::::generate_batch_proof(vec![1, 5, 6]).unwrap(); + let (.., proof) = crate::Pallet::::generate_batch_proof(vec![1, 5, 6], None).unwrap(); // then assert_eq!( proof, @@ -428,7 +427,7 @@ fn should_generate_batch_proof_correctly() { // when generate historical proofs for a batch of leaves let (.., historical_proof) = - crate::Pallet::::generate_historical_batch_proof(vec![1, 5, 6], Some(6)).unwrap(); + crate::Pallet::::generate_batch_proof(vec![1, 5, 6], Some(6)).unwrap(); // then assert_eq!( historical_proof, @@ -444,7 +443,7 @@ fn should_generate_batch_proof_correctly() { // when generate historical proofs for a batch of leaves let (.., historical_proof) = - crate::Pallet::::generate_historical_batch_proof(vec![1, 5, 6], None).unwrap(); + crate::Pallet::::generate_batch_proof(vec![1, 5, 6], None).unwrap(); // then assert_eq!(historical_proof, proof); }); @@ -465,15 +464,15 @@ fn should_verify() { register_offchain_ext(&mut ext); let (leaves, proof5) = ext.execute_with(|| { // when - crate::Pallet::::generate_batch_proof(vec![5]).unwrap() + crate::Pallet::::generate_batch_proof(vec![5], None).unwrap() }); let (simple_historical_leaves, simple_historical_proof5) = ext.execute_with(|| { // when - crate::Pallet::::generate_historical_batch_proof(vec![5], Some(6)).unwrap() + crate::Pallet::::generate_batch_proof(vec![5], Some(6)).unwrap() }); let (advanced_historical_leaves, advanced_historical_proof5) = ext.execute_with(|| { // when - crate::Pallet::::generate_historical_batch_proof(vec![5], Some(7)).unwrap() + crate::Pallet::::generate_batch_proof(vec![5], Some(7)).unwrap() }); ext.execute_with(|| { @@ -505,7 +504,7 @@ fn should_verify_batch_proofs() { blocks_to_add: usize, ) { let (leaves, proof) = ext.execute_with(|| { - crate::Pallet::::generate_batch_proof(block_numbers.to_vec()).unwrap() + crate::Pallet::::generate_batch_proof(block_numbers.to_vec(), None).unwrap() }); let max_block_number = ext.execute_with(|| frame_system::Pallet::::block_number()); @@ -515,7 +514,7 @@ fn should_verify_batch_proofs() { let historical_proofs = (*min_block_number..=max_block_number) .map(|best_block| { ext.execute_with(|| { - crate::Pallet::::generate_historical_batch_proof( + crate::Pallet::::generate_batch_proof( block_numbers.to_vec(), Some(best_block), ) @@ -604,11 +603,11 @@ fn verification_should_be_stateless() { register_offchain_ext(&mut ext); let (leaves, proof5) = ext.execute_with(|| { // when - crate::Pallet::::generate_batch_proof(vec![5]).unwrap() + crate::Pallet::::generate_batch_proof(vec![5], None).unwrap() }); let (_, historical_proof5) = ext.execute_with(|| { // when - crate::Pallet::::generate_historical_batch_proof(vec![5], Some(6)).unwrap() + crate::Pallet::::generate_batch_proof(vec![5], Some(6)).unwrap() }); // Verify proof without relying on any on-chain data. @@ -652,11 +651,11 @@ fn should_verify_batch_proof_statelessly() { register_offchain_ext(&mut ext); let (leaves, proof) = ext.execute_with(|| { // when - crate::Pallet::::generate_batch_proof(vec![1, 4, 5]).unwrap() + crate::Pallet::::generate_batch_proof(vec![1, 4, 5], None).unwrap() }); let (historical_leaves, historical_proof) = ext.execute_with(|| { // when - crate::Pallet::::generate_historical_batch_proof(vec![1, 4, 5], Some(6)).unwrap() + crate::Pallet::::generate_batch_proof(vec![1, 4, 5], Some(6)).unwrap() }); // Verify proof without relying on any on-chain data. @@ -696,7 +695,7 @@ fn should_verify_on_the_next_block_since_there_is_no_pruning_yet() { ext.execute_with(|| { // when - let (leaves, proof5) = crate::Pallet::::generate_batch_proof(vec![5]).unwrap(); + let (leaves, proof5) = crate::Pallet::::generate_batch_proof(vec![5], None).unwrap(); new_block(); // then @@ -929,8 +928,9 @@ fn should_verify_canonicalized() { } // Generate proofs for some blocks. - let (leaves, proofs) = - ext.execute_with(|| crate::Pallet::::generate_batch_proof(vec![1, 4, 5, 7]).unwrap()); + let (leaves, proofs) = ext.execute_with(|| { + crate::Pallet::::generate_batch_proof(vec![1, 4, 5, 7], None).unwrap() + }); // Verify all previously generated proofs. ext.execute_with(|| { assert_eq!(crate::Pallet::::verify_leaves(leaves, proofs), Ok(())); @@ -938,7 +938,7 @@ fn should_verify_canonicalized() { // Generate proofs for some new blocks. let (leaves, proofs) = ext.execute_with(|| { - crate::Pallet::::generate_batch_proof(vec![block_hash_size + 7]).unwrap() + crate::Pallet::::generate_batch_proof(vec![block_hash_size + 7], None).unwrap() }); // Add some more blocks then verify all previously generated proofs. ext.execute_with(|| { @@ -962,19 +962,19 @@ fn does_not_panic_when_generating_historical_proofs() { ext.execute_with(|| { // when leaf index is invalid assert_eq!( - crate::Pallet::::generate_historical_batch_proof(vec![10], None), + crate::Pallet::::generate_batch_proof(vec![10], None), Err(Error::BlockNumToLeafIndex), ); // when leaves count is invalid assert_eq!( - crate::Pallet::::generate_historical_batch_proof(vec![3], Some(100)), + crate::Pallet::::generate_batch_proof(vec![3], Some(100)), Err(Error::BlockNumToLeafIndex), ); // when both leaf index and leaves count are invalid assert_eq!( - crate::Pallet::::generate_historical_batch_proof(vec![10], Some(100)), + crate::Pallet::::generate_batch_proof(vec![10], Some(100)), Err(Error::BlockNumToLeafIndex), ); }); diff --git a/primitives/merkle-mountain-range/src/lib.rs b/primitives/merkle-mountain-range/src/lib.rs index 81b91f59d0af1..ec68d5df13f43 100644 --- a/primitives/merkle-mountain-range/src/lib.rs +++ b/primitives/merkle-mountain-range/src/lib.rs @@ -459,12 +459,9 @@ sp_api::decl_runtime_apis! { /// Return the on-chain MMR root hash. fn mmr_root() -> Result; - /// Generate MMR proof for a series of blocks with the specified block numbers. - fn generate_batch_proof(block_numbers: Vec) -> Result<(Vec, BatchProof), Error>; - /// Generate MMR proof for a series of block numbers. If `best_known_block_number = Some(n)`, /// use historical MMR state at given block height `n`. Else, use current MMR state. - fn generate_historical_batch_proof( + fn generate_batch_proof( block_numbers: Vec, best_known_block_number: Option ) -> Result<(Vec, BatchProof), Error>; From ed0f1fa3b292a8ad26382866ff64f947bbb82315 Mon Sep 17 00:00:00 2001 From: Robert Hambrock Date: Tue, 18 Oct 2022 21:18:18 +0200 Subject: [PATCH 05/21] merge generate_{batch_}proof functions --- bin/node/runtime/src/lib.rs | 15 +------ client/beefy/src/tests.rs | 7 +--- frame/merkle-mountain-range/rpc/src/lib.rs | 41 ++----------------- frame/merkle-mountain-range/src/lib.rs | 4 +- frame/merkle-mountain-range/src/mmr/mmr.rs | 2 +- frame/merkle-mountain-range/src/tests.rs | 45 ++++++++++----------- primitives/merkle-mountain-range/src/lib.rs | 5 +-- 7 files changed, 31 insertions(+), 88 deletions(-) diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index 8bc589a9a1992..f1137e334ae26 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -2021,17 +2021,6 @@ impl_runtime_apis! { mmr::Hash, BlockNumber, > for Runtime { - fn generate_proof(block_number: BlockNumber) - -> Result<(mmr::EncodableOpaqueLeaf, mmr::Proof), mmr::Error> - { - Mmr::generate_batch_proof(vec![block_number], None).and_then(|(leaves, proof)| - Ok(( - mmr::EncodableOpaqueLeaf::from_leaf(&leaves[0]), - mmr::BatchProof::into_single_leaf_proof(proof)? - )) - ) - } - fn verify_proof(leaf: mmr::EncodableOpaqueLeaf, proof: mmr::Proof) -> Result<(), mmr::Error> { @@ -2055,11 +2044,11 @@ impl_runtime_apis! { Ok(Mmr::mmr_root()) } - fn generate_batch_proof( + fn generate_proof( block_numbers: Vec, best_known_block_number: Option, ) -> Result<(Vec, mmr::BatchProof), mmr::Error> { - Mmr::generate_batch_proof(block_numbers, best_known_block_number).map( + Mmr::generate_proof(block_numbers, best_known_block_number).map( |(leaves, proof)| { ( leaves diff --git a/client/beefy/src/tests.rs b/client/beefy/src/tests.rs index 87f57672b2741..ee61a23c74fd0 100644 --- a/client/beefy/src/tests.rs +++ b/client/beefy/src/tests.rs @@ -246,11 +246,6 @@ macro_rules! create_test_api { } impl MmrApi> for RuntimeApi { - fn generate_proof(_block_number: u64) - -> Result<(EncodableOpaqueLeaf, Proof), MmrError> { - unimplemented!() - } - fn verify_proof(_leaf: EncodableOpaqueLeaf, _proof: Proof) -> Result<(), MmrError> { unimplemented!() @@ -268,7 +263,7 @@ macro_rules! create_test_api { Ok($mmr_root) } - fn generate_batch_proof( + fn generate_proof( _block_numbers: Vec, _best_known_block_number: Option ) -> Result<(Vec, BatchProof), MmrError> { diff --git a/frame/merkle-mountain-range/rpc/src/lib.rs b/frame/merkle-mountain-range/rpc/src/lib.rs index c848c2e6a8d52..44f444c4957d0 100644 --- a/frame/merkle-mountain-range/rpc/src/lib.rs +++ b/frame/merkle-mountain-range/rpc/src/lib.rs @@ -97,21 +97,6 @@ impl LeafBatchProof { /// MMR RPC methods. #[rpc(client, server)] pub trait MmrApi { - /// Generate MMR proof for given block number. - /// - /// This method calls into a runtime with MMR pallet included and attempts to generate - /// 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, - block_number: BlockNumber, - at: Option, - ) -> RpcResult>; - /// Generate a MMR proof for the given `block_numbers`. /// /// This method calls into a runtime with MMR pallet included and attempts to generate @@ -127,12 +112,12 @@ pub trait MmrApi { /// 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 + /// Returns the (full) 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 `block_numbers` supplied #[method(name = "mmr_generateHistoricalBatchProof")] - fn generate_batch_proof( + fn generate_proof( &self, block_numbers: Vec, best_known_block_number: Option, @@ -163,26 +148,6 @@ where MmrHash: Codec + Send + Sync + 'static, { fn generate_proof( - &self, - block_number: NumberFor, - at: Option<::Hash>, - ) -> RpcResult> { - let api = self.client.runtime_api(); - let block_hash = at.unwrap_or_else(|| self.client.info().best_hash); - - let (leaf, proof) = api - .generate_proof_with_context( - &BlockId::hash(block_hash), - sp_core::ExecutionContext::OffchainCall(None), - block_number, - ) - .map_err(runtime_error_into_rpc_error)? - .map_err(mmr_error_into_rpc_error)?; - - Ok(LeafProof::new(block_hash, leaf, proof)) - } - - fn generate_batch_proof( &self, block_numbers: Vec>, best_known_block_number: Option>, @@ -194,7 +159,7 @@ where self.client.info().best_hash); let (leaves, proof) = api - .generate_batch_proof_with_context( + .generate_proof_with_context( &BlockId::hash(block_hash), sp_core::ExecutionContext::OffchainCall(None), block_numbers, diff --git a/frame/merkle-mountain-range/src/lib.rs b/frame/merkle-mountain-range/src/lib.rs index 429931165afd0..a06c7d744b639 100644 --- a/frame/merkle-mountain-range/src/lib.rs +++ b/frame/merkle-mountain-range/src/lib.rs @@ -390,7 +390,7 @@ impl, I: 'static> Pallet { /// (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( + pub fn generate_proof( block_numbers: Vec, best_known_block_number: Option, ) -> Result< @@ -413,7 +413,7 @@ impl, I: 'static> Pallet { .collect::, _>>()?; let mmr: ModuleMmr = mmr::Mmr::new(leaves_count); - mmr.generate_batch_proof(leaf_indices) + mmr.generate_proof(leaf_indices) } /// Return the on-chain MMR root hash. diff --git a/frame/merkle-mountain-range/src/mmr/mmr.rs b/frame/merkle-mountain-range/src/mmr/mmr.rs index 44e684c1bdcac..10cd05cbae821 100644 --- a/frame/merkle-mountain-range/src/mmr/mmr.rs +++ b/frame/merkle-mountain-range/src/mmr/mmr.rs @@ -163,7 +163,7 @@ where /// /// Proof generation requires all the nodes (or their hashes) to be available in the storage. /// (i.e. you can't run the function in the pruned storage). - pub fn generate_batch_proof( + pub fn generate_proof( &self, leaf_indices: Vec, ) -> Result<(Vec, primitives::BatchProof<>::Hash>), Error> { diff --git a/frame/merkle-mountain-range/src/tests.rs b/frame/merkle-mountain-range/src/tests.rs index e970731f96f64..66d3aaf5f92fd 100644 --- a/frame/merkle-mountain-range/src/tests.rs +++ b/frame/merkle-mountain-range/src/tests.rs @@ -236,9 +236,7 @@ fn should_generate_proofs_correctly() { // when generate proofs for all leaves. let proofs = (1_u64..=best_block_number) .into_iter() - .map(|block_num| { - crate::Pallet::::generate_batch_proof(vec![block_num], None).unwrap() - }) + .map(|block_num| crate::Pallet::::generate_proof(vec![block_num], None).unwrap()) .collect::>(); // when generate historical proofs for all leaves let historical_proofs = (1_u64..best_block_number) @@ -247,7 +245,7 @@ fn should_generate_proofs_correctly() { let mut proofs = vec![]; for historical_best_block in block_num..=num_blocks { proofs.push( - crate::Pallet::::generate_batch_proof( + crate::Pallet::::generate_proof( vec![block_num], Some(historical_best_block), ) @@ -409,7 +407,7 @@ 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::::generate_batch_proof(vec![1, 5, 6], None).unwrap(); + let (.., proof) = crate::Pallet::::generate_proof(vec![1, 5, 6], None).unwrap(); // then assert_eq!( proof, @@ -427,7 +425,7 @@ fn should_generate_batch_proof_correctly() { // when generate historical proofs for a batch of leaves let (.., historical_proof) = - crate::Pallet::::generate_batch_proof(vec![1, 5, 6], Some(6)).unwrap(); + crate::Pallet::::generate_proof(vec![1, 5, 6], Some(6)).unwrap(); // then assert_eq!( historical_proof, @@ -443,7 +441,7 @@ fn should_generate_batch_proof_correctly() { // when generate historical proofs for a batch of leaves let (.., historical_proof) = - crate::Pallet::::generate_batch_proof(vec![1, 5, 6], None).unwrap(); + crate::Pallet::::generate_proof(vec![1, 5, 6], None).unwrap(); // then assert_eq!(historical_proof, proof); }); @@ -464,15 +462,15 @@ fn should_verify() { register_offchain_ext(&mut ext); let (leaves, proof5) = ext.execute_with(|| { // when - crate::Pallet::::generate_batch_proof(vec![5], None).unwrap() + crate::Pallet::::generate_proof(vec![5], None).unwrap() }); let (simple_historical_leaves, simple_historical_proof5) = ext.execute_with(|| { // when - crate::Pallet::::generate_batch_proof(vec![5], Some(6)).unwrap() + crate::Pallet::::generate_proof(vec![5], Some(6)).unwrap() }); let (advanced_historical_leaves, advanced_historical_proof5) = ext.execute_with(|| { // when - crate::Pallet::::generate_batch_proof(vec![5], Some(7)).unwrap() + crate::Pallet::::generate_proof(vec![5], Some(7)).unwrap() }); ext.execute_with(|| { @@ -504,7 +502,7 @@ fn should_verify_batch_proofs() { blocks_to_add: usize, ) { let (leaves, proof) = ext.execute_with(|| { - crate::Pallet::::generate_batch_proof(block_numbers.to_vec(), None).unwrap() + crate::Pallet::::generate_proof(block_numbers.to_vec(), None).unwrap() }); let max_block_number = ext.execute_with(|| frame_system::Pallet::::block_number()); @@ -514,7 +512,7 @@ fn should_verify_batch_proofs() { let historical_proofs = (*min_block_number..=max_block_number) .map(|best_block| { ext.execute_with(|| { - crate::Pallet::::generate_batch_proof( + crate::Pallet::::generate_proof( block_numbers.to_vec(), Some(best_block), ) @@ -603,11 +601,11 @@ fn verification_should_be_stateless() { register_offchain_ext(&mut ext); let (leaves, proof5) = ext.execute_with(|| { // when - crate::Pallet::::generate_batch_proof(vec![5], None).unwrap() + crate::Pallet::::generate_proof(vec![5], None).unwrap() }); let (_, historical_proof5) = ext.execute_with(|| { // when - crate::Pallet::::generate_batch_proof(vec![5], Some(6)).unwrap() + crate::Pallet::::generate_proof(vec![5], Some(6)).unwrap() }); // Verify proof without relying on any on-chain data. @@ -651,11 +649,11 @@ fn should_verify_batch_proof_statelessly() { register_offchain_ext(&mut ext); let (leaves, proof) = ext.execute_with(|| { // when - crate::Pallet::::generate_batch_proof(vec![1, 4, 5], None).unwrap() + crate::Pallet::::generate_proof(vec![1, 4, 5], None).unwrap() }); let (historical_leaves, historical_proof) = ext.execute_with(|| { // when - crate::Pallet::::generate_batch_proof(vec![1, 4, 5], Some(6)).unwrap() + crate::Pallet::::generate_proof(vec![1, 4, 5], Some(6)).unwrap() }); // Verify proof without relying on any on-chain data. @@ -695,7 +693,7 @@ fn should_verify_on_the_next_block_since_there_is_no_pruning_yet() { ext.execute_with(|| { // when - let (leaves, proof5) = crate::Pallet::::generate_batch_proof(vec![5], None).unwrap(); + let (leaves, proof5) = crate::Pallet::::generate_proof(vec![5], None).unwrap(); new_block(); // then @@ -928,9 +926,8 @@ fn should_verify_canonicalized() { } // Generate proofs for some blocks. - let (leaves, proofs) = ext.execute_with(|| { - crate::Pallet::::generate_batch_proof(vec![1, 4, 5, 7], None).unwrap() - }); + let (leaves, proofs) = + ext.execute_with(|| crate::Pallet::::generate_proof(vec![1, 4, 5, 7], None).unwrap()); // Verify all previously generated proofs. ext.execute_with(|| { assert_eq!(crate::Pallet::::verify_leaves(leaves, proofs), Ok(())); @@ -938,7 +935,7 @@ fn should_verify_canonicalized() { // Generate proofs for some new blocks. let (leaves, proofs) = ext.execute_with(|| { - crate::Pallet::::generate_batch_proof(vec![block_hash_size + 7], None).unwrap() + crate::Pallet::::generate_proof(vec![block_hash_size + 7], None).unwrap() }); // Add some more blocks then verify all previously generated proofs. ext.execute_with(|| { @@ -962,19 +959,19 @@ fn does_not_panic_when_generating_historical_proofs() { ext.execute_with(|| { // when leaf index is invalid assert_eq!( - crate::Pallet::::generate_batch_proof(vec![10], None), + crate::Pallet::::generate_proof(vec![10], None), Err(Error::BlockNumToLeafIndex), ); // when leaves count is invalid assert_eq!( - crate::Pallet::::generate_batch_proof(vec![3], Some(100)), + crate::Pallet::::generate_proof(vec![3], Some(100)), Err(Error::BlockNumToLeafIndex), ); // when both leaf index and leaves count are invalid assert_eq!( - crate::Pallet::::generate_batch_proof(vec![10], Some(100)), + crate::Pallet::::generate_proof(vec![10], Some(100)), Err(Error::BlockNumToLeafIndex), ); }); diff --git a/primitives/merkle-mountain-range/src/lib.rs b/primitives/merkle-mountain-range/src/lib.rs index ec68d5df13f43..705bc37ca1805 100644 --- a/primitives/merkle-mountain-range/src/lib.rs +++ b/primitives/merkle-mountain-range/src/lib.rs @@ -437,9 +437,6 @@ impl Error { sp_api::decl_runtime_apis! { /// API to interact with MMR pallet. pub trait MmrApi { - /// Generate MMR proof for a block with a specified `block_number`. - fn generate_proof(block_number: BlockNumber) -> Result<(EncodableOpaqueLeaf, Proof), Error>; - /// Verify MMR proof against on-chain MMR. /// /// Note this function will use on-chain MMR root hash and check if the proof @@ -461,7 +458,7 @@ sp_api::decl_runtime_apis! { /// Generate MMR proof for a series of block numbers. If `best_known_block_number = Some(n)`, /// use historical MMR state at given block height `n`. Else, use current MMR state. - fn generate_batch_proof( + fn generate_proof( block_numbers: Vec, best_known_block_number: Option ) -> Result<(Vec, BatchProof), Error>; From 0730e9af22fd830b85ec0ddd39c9df833b3fc6a9 Mon Sep 17 00:00:00 2001 From: Robert Hambrock Date: Tue, 18 Oct 2022 22:30:55 +0200 Subject: [PATCH 06/21] merge verify_{batch_}proof functions --- bin/node/runtime/src/lib.rs | 12 +----------- client/beefy/src/tests.rs | 7 +------ frame/merkle-mountain-range/src/tests.rs | 7 ++----- primitives/merkle-mountain-range/src/lib.rs | 9 +-------- 4 files changed, 5 insertions(+), 30 deletions(-) diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index f1137e334ae26..165c4238e81f4 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -2021,16 +2021,6 @@ impl_runtime_apis! { mmr::Hash, BlockNumber, > for Runtime { - fn verify_proof(leaf: mmr::EncodableOpaqueLeaf, proof: mmr::Proof) - -> Result<(), mmr::Error> - { - let leaf: mmr::Leaf = leaf - .into_opaque_leaf() - .try_decode() - .ok_or(mmr::Error::Verify)?; - Mmr::verify_leaves(vec![leaf], mmr::Proof::into_batch_proof(proof)) - } - fn verify_proof_stateless( root: mmr::Hash, leaf: mmr::EncodableOpaqueLeaf, @@ -2061,7 +2051,7 @@ impl_runtime_apis! { ) } - fn verify_batch_proof(leaves: Vec, proof: mmr::BatchProof) + fn verify_proof(leaves: Vec, proof: mmr::BatchProof) -> Result<(), mmr::Error> { let leaves = leaves.into_iter().map(|leaf| diff --git a/client/beefy/src/tests.rs b/client/beefy/src/tests.rs index ee61a23c74fd0..11f1e9fbbcb1d 100644 --- a/client/beefy/src/tests.rs +++ b/client/beefy/src/tests.rs @@ -246,11 +246,6 @@ macro_rules! create_test_api { } impl MmrApi> for RuntimeApi { - fn verify_proof(_leaf: EncodableOpaqueLeaf, _proof: Proof) - -> Result<(), MmrError> { - unimplemented!() - } - fn verify_proof_stateless( _root: MmrRootHash, _leaf: EncodableOpaqueLeaf, @@ -270,7 +265,7 @@ macro_rules! create_test_api { unimplemented!() } - fn verify_batch_proof(_leaves: Vec, _proof: BatchProof) -> Result<(), MmrError> { + fn verify_proof(_leaves: Vec, _proof: BatchProof) -> Result<(), MmrError> { unimplemented!() } diff --git a/frame/merkle-mountain-range/src/tests.rs b/frame/merkle-mountain-range/src/tests.rs index 66d3aaf5f92fd..15d924a7eb63b 100644 --- a/frame/merkle-mountain-range/src/tests.rs +++ b/frame/merkle-mountain-range/src/tests.rs @@ -512,11 +512,8 @@ fn should_verify_batch_proofs() { let historical_proofs = (*min_block_number..=max_block_number) .map(|best_block| { ext.execute_with(|| { - crate::Pallet::::generate_proof( - block_numbers.to_vec(), - Some(best_block), - ) - .unwrap() + crate::Pallet::::generate_proof(block_numbers.to_vec(), Some(best_block)) + .unwrap() }) }) .collect::>(); diff --git a/primitives/merkle-mountain-range/src/lib.rs b/primitives/merkle-mountain-range/src/lib.rs index 705bc37ca1805..0c915365e3654 100644 --- a/primitives/merkle-mountain-range/src/lib.rs +++ b/primitives/merkle-mountain-range/src/lib.rs @@ -437,13 +437,6 @@ impl Error { sp_api::decl_runtime_apis! { /// API to interact with MMR pallet. pub trait MmrApi { - /// Verify MMR proof against on-chain MMR. - /// - /// Note this function will use on-chain MMR root hash and check if the proof - /// matches the hash. - /// See [Self::verify_proof_stateless] for a stateless verifier. - fn verify_proof(leaf: EncodableOpaqueLeaf, proof: Proof) -> Result<(), Error>; - /// Verify MMR proof against given root hash. /// /// Note this function does not require any on-chain storage - the @@ -468,7 +461,7 @@ sp_api::decl_runtime_apis! { /// Note this function will use on-chain MMR root hash and check if the proof matches the hash. /// 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 [BatchProof] - fn verify_batch_proof(leaves: Vec, proof: BatchProof) -> Result<(), Error>; + fn verify_proof(leaves: Vec, proof: BatchProof) -> Result<(), Error>; /// Verify MMR proof against given root hash or a batch of leaves. /// From e617095ad1278ad75c3d253c8611ab0c18f20e64 Mon Sep 17 00:00:00 2001 From: Robert Hambrock Date: Tue, 18 Oct 2022 22:38:49 +0200 Subject: [PATCH 07/21] merge verify_{batch_}proof_stateless functions --- bin/node/runtime/src/lib.rs | 11 +---------- client/beefy/src/tests.rs | 10 +--------- primitives/merkle-mountain-range/src/lib.rs | 13 ++----------- 3 files changed, 4 insertions(+), 30 deletions(-) diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index 165c4238e81f4..ee6165bc60edd 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -2021,15 +2021,6 @@ impl_runtime_apis! { mmr::Hash, BlockNumber, > for Runtime { - fn verify_proof_stateless( - root: mmr::Hash, - leaf: mmr::EncodableOpaqueLeaf, - proof: mmr::Proof - ) -> Result<(), mmr::Error> { - let node = mmr::DataOrHash::Data(leaf.into_opaque_leaf()); - pallet_mmr::verify_leaves_proof::(root, vec![node], mmr::Proof::into_batch_proof(proof)) - } - fn mmr_root() -> Result { Ok(Mmr::mmr_root()) } @@ -2061,7 +2052,7 @@ impl_runtime_apis! { Mmr::verify_leaves(leaves, proof) } - fn verify_batch_proof_stateless( + fn verify_proof_stateless( root: mmr::Hash, leaves: Vec, proof: mmr::BatchProof diff --git a/client/beefy/src/tests.rs b/client/beefy/src/tests.rs index 11f1e9fbbcb1d..ea10f39cd8597 100644 --- a/client/beefy/src/tests.rs +++ b/client/beefy/src/tests.rs @@ -246,14 +246,6 @@ macro_rules! create_test_api { } impl MmrApi> for RuntimeApi { - fn verify_proof_stateless( - _root: MmrRootHash, - _leaf: EncodableOpaqueLeaf, - _proof: Proof - ) -> Result<(), MmrError> { - unimplemented!() - } - fn mmr_root() -> Result { Ok($mmr_root) } @@ -269,7 +261,7 @@ macro_rules! create_test_api { unimplemented!() } - fn verify_batch_proof_stateless( + fn verify_proof_stateless( _root: MmrRootHash, _leaves: Vec, _proof: BatchProof diff --git a/primitives/merkle-mountain-range/src/lib.rs b/primitives/merkle-mountain-range/src/lib.rs index 0c915365e3654..8c97b9d183e7c 100644 --- a/primitives/merkle-mountain-range/src/lib.rs +++ b/primitives/merkle-mountain-range/src/lib.rs @@ -437,15 +437,6 @@ impl Error { sp_api::decl_runtime_apis! { /// API to interact with MMR pallet. pub trait MmrApi { - /// Verify MMR proof against given root hash. - /// - /// Note this function does not require any on-chain storage - the - /// proof is verified against given MMR root hash. - /// - /// The leaf data is expected to be encoded in its compact form. - fn verify_proof_stateless(root: Hash, leaf: EncodableOpaqueLeaf, proof: Proof) - -> Result<(), Error>; - /// Return the on-chain MMR root hash. fn mmr_root() -> Result; @@ -463,14 +454,14 @@ sp_api::decl_runtime_apis! { /// same position in both the `leaves` vector and the `leaf_indices` vector contained in the [BatchProof] fn verify_proof(leaves: Vec, proof: BatchProof) -> Result<(), Error>; - /// Verify MMR proof against given root hash or a batch of leaves. + /// Verify MMR proof against given root hash for a batch of leaves. /// /// Note this function does not require any on-chain storage - the /// proof is verified against given MMR root hash. /// /// 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 [BatchProof] - fn verify_batch_proof_stateless(root: Hash, leaves: Vec, proof: BatchProof) + fn verify_proof_stateless(root: Hash, leaves: Vec, proof: BatchProof) -> Result<(), Error>; } } From f08f6f0a6315b9d27d2cdc90f473cf6f5c71704f Mon Sep 17 00:00:00 2001 From: Robert Hambrock Date: Wed, 19 Oct 2022 09:55:27 +0200 Subject: [PATCH 08/21] remove {Leaf}Proof Not utilized by API anymore, so superfluous. Removal consistent with prior changes to just use "batch" proof API. --- frame/merkle-mountain-range/rpc/src/lib.rs | 82 ++++++++------------- primitives/merkle-mountain-range/src/lib.rs | 27 +------ 2 files changed, 33 insertions(+), 76 deletions(-) diff --git a/frame/merkle-mountain-range/rpc/src/lib.rs b/frame/merkle-mountain-range/rpc/src/lib.rs index 44f444c4957d0..4089b0c301aac 100644 --- a/frame/merkle-mountain-range/rpc/src/lib.rs +++ b/frame/merkle-mountain-range/rpc/src/lib.rs @@ -43,33 +43,10 @@ const MMR_ERROR: i32 = 8010; const LEAF_NOT_FOUND_ERROR: i32 = MMR_ERROR + 1; const GENERATE_PROOF_ERROR: i32 = MMR_ERROR + 2; -/// Retrieved MMR leaf and its proof. -#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)] -#[serde(rename_all = "camelCase")] -pub struct LeafProof { - /// Block hash the proof was generated for. - pub block_hash: BlockHash, - /// SCALE-encoded leaf data. - pub leaf: Bytes, - /// SCALE-encoded proof data. See [sp_mmr_primitives::Proof]. - pub proof: Bytes, -} - -impl LeafProof { - /// Create new `LeafProof` from given concrete `leaf` and `proof`. - pub fn new(block_hash: BlockHash, leaf: Leaf, proof: Proof) -> Self - where - Leaf: Encode, - MmrHash: Encode, - { - Self { block_hash, leaf: Bytes(leaf.encode()), proof: Bytes(proof.encode()) } - } -} - /// Retrieved MMR leaves and their proof. #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)] #[serde(rename_all = "camelCase")] -pub struct LeafBatchProof { +pub struct LeavesProof { /// Block hash the proof was generated for. pub block_hash: BlockHash, /// SCALE-encoded vector of `LeafData`. @@ -78,8 +55,8 @@ pub struct LeafBatchProof { pub proof: Bytes, } -impl LeafBatchProof { - /// Create new `LeafBatchProof` from a given vector of `Leaf` and a +impl LeavesProof { + /// Create new `LeavesProof` from a given vector of `Leaf` and a /// [sp_mmr_primitives::BatchProof]. pub fn new( block_hash: BlockHash, @@ -122,7 +99,7 @@ pub trait MmrApi { block_numbers: Vec, best_known_block_number: Option, at: Option, - ) -> RpcResult>; + ) -> RpcResult>; } /// MMR RPC methods. @@ -152,7 +129,7 @@ where block_numbers: Vec>, best_known_block_number: Option>, at: Option<::Hash>, - ) -> RpcResult::Hash>> { + ) -> RpcResult::Hash>> { let api = self.client.runtime_api(); let block_hash = at.unwrap_or_else(|| // If the block hash is not supplied assume the best block. @@ -168,7 +145,7 @@ where .map_err(runtime_error_into_rpc_error)? .map_err(mmr_error_into_rpc_error)?; - Ok(LeafBatchProof::new(block_hash, leaves, proof)) + Ok(LeavesProof::new(block_hash, leaves, proof)) } } @@ -208,13 +185,13 @@ mod tests { fn should_serialize_leaf_proof() { // given let leaf = vec![1_u8, 2, 3, 4]; - let proof = Proof { - leaf_index: 1, + let proof = BatchProof { + leaf_indices: vec![1], leaf_count: 9, items: vec![H256::repeat_byte(1), H256::repeat_byte(2)], }; - let leaf_proof = LeafProof::new(H256::repeat_byte(0), leaf, proof); + let leaf_proof = LeavesProof::new(H256::repeat_byte(0), vec![leaf], proof); // when let actual = serde_json::to_string(&leaf_proof).unwrap(); @@ -222,21 +199,22 @@ mod tests { // then assert_eq!( actual, - r#"{"blockHash":"0x0000000000000000000000000000000000000000000000000000000000000000","leaf":"0x1001020304","proof":"0x010000000000000009000000000000000801010101010101010101010101010101010101010101010101010101010101010202020202020202020202020202020202020202020202020202020202020202"}"# + r#"{"blockHash":"0x0000000000000000000000000000000000000000000000000000000000000000","leaves":"0x041001020304","proof":"0x04010000000000000009000000000000000801010101010101010101010101010101010101010101010101010101010101010202020202020202020202020202020202020202020202020202020202020202"}"# ); } #[test] - fn should_serialize_leaf_batch_proof() { + fn should_serialize_leaves_proof() { // given - let leaf = vec![1_u8, 2, 3, 4]; + let leaf_a = vec![1_u8, 2, 3, 4]; + let leaf_b = vec![2_u8, 2, 3, 4]; let proof = BatchProof { - leaf_indices: vec![1], + leaf_indices: vec![1, 2], leaf_count: 9, items: vec![H256::repeat_byte(1), H256::repeat_byte(2)], }; - let leaf_proof = LeafBatchProof::new(H256::repeat_byte(0), vec![leaf], proof); + let leaf_proof = LeavesProof::new(H256::repeat_byte(0), vec![leaf_a, leaf_b], proof); // when let actual = serde_json::to_string(&leaf_proof).unwrap(); @@ -244,19 +222,19 @@ mod tests { // then assert_eq!( actual, - r#"{"blockHash":"0x0000000000000000000000000000000000000000000000000000000000000000","leaves":"0x041001020304","proof":"0x04010000000000000009000000000000000801010101010101010101010101010101010101010101010101010101010101010202020202020202020202020202020202020202020202020202020202020202"}"# + r#"{"blockHash":"0x0000000000000000000000000000000000000000000000000000000000000000","leaves":"0x0810010203041002020304","proof":"0x080100000000000000020000000000000009000000000000000801010101010101010101010101010101010101010101010101010101010101010202020202020202020202020202020202020202020202020202020202020202"}"# ); } #[test] fn should_deserialize_leaf_proof() { // given - let expected = LeafProof { + let expected = LeavesProof { block_hash: H256::repeat_byte(0), - leaf: Bytes(vec![1_u8, 2, 3, 4].encode()), + leaves: Bytes(vec![vec![1_u8, 2, 3, 4]].encode()), proof: Bytes( - Proof { - leaf_index: 1, + BatchProof { + leaf_indices: vec![1], leaf_count: 9, items: vec![H256::repeat_byte(1), H256::repeat_byte(2)], } @@ -265,10 +243,10 @@ mod tests { }; // when - let actual: LeafProof = serde_json::from_str(r#"{ + let actual: LeavesProof = serde_json::from_str(r#"{ "blockHash":"0x0000000000000000000000000000000000000000000000000000000000000000", - "leaf":"0x1001020304", - "proof":"0x010000000000000009000000000000000801010101010101010101010101010101010101010101010101010101010101010202020202020202020202020202020202020202020202020202020202020202" + "leaves":"0x041001020304", + "proof":"0x04010000000000000009000000000000000801010101010101010101010101010101010101010101010101010101010101010202020202020202020202020202020202020202020202020202020202020202" }"#).unwrap(); // then @@ -276,14 +254,14 @@ mod tests { } #[test] - fn should_deserialize_leaf_batch_proof() { + fn should_deserialize_leaves_proof() { // given - let expected = LeafBatchProof { + let expected = LeavesProof { block_hash: H256::repeat_byte(0), - leaves: Bytes(vec![vec![1_u8, 2, 3, 4]].encode()), + leaves: Bytes(vec![vec![1_u8, 2, 3, 4], vec![2_u8, 2, 3, 4]].encode()), proof: Bytes( BatchProof { - leaf_indices: vec![1], + leaf_indices: vec![1, 2], leaf_count: 9, items: vec![H256::repeat_byte(1), H256::repeat_byte(2)], } @@ -292,10 +270,10 @@ mod tests { }; // when - let actual: LeafBatchProof = serde_json::from_str(r#"{ + let actual: LeavesProof = serde_json::from_str(r#"{ "blockHash":"0x0000000000000000000000000000000000000000000000000000000000000000", - "leaves":"0x041001020304", - "proof":"0x04010000000000000009000000000000000801010101010101010101010101010101010101010101010101010101010101010202020202020202020202020202020202020202020202020202020202020202" + "leaves":"0x0810010203041002020304", + "proof":"0x080100000000000000020000000000000009000000000000000801010101010101010101010101010101010101010101010101010101010101010202020202020202020202020202020202020202020202020202020202020202" }"#).unwrap(); // then diff --git a/primitives/merkle-mountain-range/src/lib.rs b/primitives/merkle-mountain-range/src/lib.rs index 8c97b9d183e7c..366bbd1e2c500 100644 --- a/primitives/merkle-mountain-range/src/lib.rs +++ b/primitives/merkle-mountain-range/src/lib.rs @@ -363,27 +363,6 @@ pub struct BatchProof { pub items: Vec, } -impl BatchProof { - /// Converts batch proof to single leaf proof - pub fn into_single_leaf_proof(proof: BatchProof) -> Result, Error> { - Ok(Proof { - leaf_index: *proof.leaf_indices.get(0).ok_or(Error::InvalidLeafIndex)?, - leaf_count: proof.leaf_count, - items: proof.items, - }) - } -} - -impl Proof { - /// Converts a single leaf proof into a batch proof - pub fn into_batch_proof(proof: Proof) -> BatchProof { - BatchProof { - leaf_indices: vec![proof.leaf_index], - leaf_count: proof.leaf_count, - items: proof.items, - } - } -} /// Merkle Mountain Range operation error. #[derive(RuntimeDebug, codec::Encode, codec::Decode, PartialEq, Eq)] pub enum Error { @@ -480,13 +459,13 @@ mod tests { type Test = DataOrHash; type TestCompact = Compact; - type TestProof = Proof<::Output>; + type TestProof = BatchProof<::Output>; #[test] fn should_encode_decode_proof() { // given - let proof: TestProof = Proof { - leaf_index: 5, + let proof: TestProof = BatchProof { + leaf_indices: vec![5], leaf_count: 10, items: vec![ hex("c3e7ba6b511162fead58f2c8b5764ce869ed1118011ac37392522ed16720bbcd"), From 2657723bafbc7652e6f4fb8437f1a9c92ee3a459 Mon Sep 17 00:00:00 2001 From: Robert Hambrock Date: Wed, 19 Oct 2022 10:07:10 +0200 Subject: [PATCH 09/21] rename BatchProof->Proof no need to qualify if only one universal proof type. --- bin/node/runtime/src/lib.rs | 6 ++--- client/beefy/src/tests.rs | 8 +++--- frame/merkle-mountain-range/rpc/src/lib.rs | 18 +++++++------- frame/merkle-mountain-range/src/lib.rs | 13 ++++------ frame/merkle-mountain-range/src/mmr/mmr.rs | 12 ++++----- frame/merkle-mountain-range/src/tests.rs | 22 ++++++++--------- primitives/merkle-mountain-range/src/lib.rs | 27 ++++++--------------- 7 files changed, 46 insertions(+), 60 deletions(-) diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index ee6165bc60edd..0a678a638230e 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -2028,7 +2028,7 @@ impl_runtime_apis! { fn generate_proof( block_numbers: Vec, best_known_block_number: Option, - ) -> Result<(Vec, mmr::BatchProof), mmr::Error> { + ) -> Result<(Vec, mmr::Proof), mmr::Error> { Mmr::generate_proof(block_numbers, best_known_block_number).map( |(leaves, proof)| { ( @@ -2042,7 +2042,7 @@ impl_runtime_apis! { ) } - fn verify_proof(leaves: Vec, proof: mmr::BatchProof) + fn verify_proof(leaves: Vec, proof: mmr::Proof) -> Result<(), mmr::Error> { let leaves = leaves.into_iter().map(|leaf| @@ -2055,7 +2055,7 @@ impl_runtime_apis! { fn verify_proof_stateless( root: mmr::Hash, leaves: Vec, - proof: mmr::BatchProof + proof: mmr::Proof ) -> Result<(), mmr::Error> { let nodes = leaves.into_iter().map(|leaf|mmr::DataOrHash::Data(leaf.into_opaque_leaf())).collect(); pallet_mmr::verify_leaves_proof::(root, nodes, proof) diff --git a/client/beefy/src/tests.rs b/client/beefy/src/tests.rs index ea10f39cd8597..ca448293e23d5 100644 --- a/client/beefy/src/tests.rs +++ b/client/beefy/src/tests.rs @@ -43,7 +43,7 @@ use beefy_primitives::{ KEY_TYPE as BeefyKeyType, }; use sc_network::{config::RequestResponseConfig, ProtocolName}; -use sp_mmr_primitives::{BatchProof, EncodableOpaqueLeaf, Error as MmrError, MmrApi, Proof}; +use sp_mmr_primitives::{EncodableOpaqueLeaf, Error as MmrError, MmrApi, Proof}; use sp_api::{ApiRef, ProvideRuntimeApi}; use sp_consensus::BlockOrigin; @@ -253,18 +253,18 @@ macro_rules! create_test_api { fn generate_proof( _block_numbers: Vec, _best_known_block_number: Option - ) -> Result<(Vec, BatchProof), MmrError> { + ) -> Result<(Vec, Proof), MmrError> { unimplemented!() } - fn verify_proof(_leaves: Vec, _proof: BatchProof) -> Result<(), MmrError> { + fn verify_proof(_leaves: Vec, _proof: Proof) -> Result<(), MmrError> { unimplemented!() } fn verify_proof_stateless( _root: MmrRootHash, _leaves: Vec, - _proof: BatchProof + _proof: Proof ) -> Result<(), MmrError> { unimplemented!() } diff --git a/frame/merkle-mountain-range/rpc/src/lib.rs b/frame/merkle-mountain-range/rpc/src/lib.rs index 4089b0c301aac..98a35c5a0c033 100644 --- a/frame/merkle-mountain-range/rpc/src/lib.rs +++ b/frame/merkle-mountain-range/rpc/src/lib.rs @@ -33,7 +33,7 @@ use serde::{Deserialize, Serialize}; use sp_api::{NumberFor, ProvideRuntimeApi}; use sp_blockchain::HeaderBackend; use sp_core::Bytes; -use sp_mmr_primitives::{BatchProof, Error as MmrError, Proof}; +use sp_mmr_primitives::{Error as MmrError, Proof}; use sp_runtime::{generic::BlockId, traits::Block as BlockT}; pub use sp_mmr_primitives::MmrApi as MmrRuntimeApi; @@ -51,17 +51,17 @@ pub struct LeavesProof { pub block_hash: BlockHash, /// SCALE-encoded vector of `LeafData`. pub leaves: Bytes, - /// SCALE-encoded proof data. See [sp_mmr_primitives::BatchProof]. + /// SCALE-encoded proof data. See [sp_mmr_primitives::Proof]. pub proof: Bytes, } impl LeavesProof { /// Create new `LeavesProof` from a given vector of `Leaf` and a - /// [sp_mmr_primitives::BatchProof]. + /// [sp_mmr_primitives::Proof]. pub fn new( block_hash: BlockHash, leaves: Vec, - proof: BatchProof, + proof: Proof, ) -> Self where Leaf: Encode, @@ -93,7 +93,7 @@ pub trait MmrApi { /// 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 `block_numbers` supplied - #[method(name = "mmr_generateHistoricalBatchProof")] + #[method(name = "mmr_generateProof")] fn generate_proof( &self, block_numbers: Vec, @@ -185,7 +185,7 @@ mod tests { fn should_serialize_leaf_proof() { // given let leaf = vec![1_u8, 2, 3, 4]; - let proof = BatchProof { + let proof = Proof { leaf_indices: vec![1], leaf_count: 9, items: vec![H256::repeat_byte(1), H256::repeat_byte(2)], @@ -208,7 +208,7 @@ mod tests { // given let leaf_a = vec![1_u8, 2, 3, 4]; let leaf_b = vec![2_u8, 2, 3, 4]; - let proof = BatchProof { + let proof = Proof { leaf_indices: vec![1, 2], leaf_count: 9, items: vec![H256::repeat_byte(1), H256::repeat_byte(2)], @@ -233,7 +233,7 @@ mod tests { block_hash: H256::repeat_byte(0), leaves: Bytes(vec![vec![1_u8, 2, 3, 4]].encode()), proof: Bytes( - BatchProof { + Proof { leaf_indices: vec![1], leaf_count: 9, items: vec![H256::repeat_byte(1), H256::repeat_byte(2)], @@ -260,7 +260,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( - BatchProof { + Proof { leaf_indices: vec![1, 2], leaf_count: 9, items: vec![H256::repeat_byte(1), H256::repeat_byte(2)], diff --git a/frame/merkle-mountain-range/src/lib.rs b/frame/merkle-mountain-range/src/lib.rs index a06c7d744b639..f5b8ff8265e84 100644 --- a/frame/merkle-mountain-range/src/lib.rs +++ b/frame/merkle-mountain-range/src/lib.rs @@ -287,15 +287,15 @@ pub mod pallet { /// Stateless MMR proof verification for batch of leaves. /// -/// This function can be used to verify received MMR [primitives::BatchProof] (`proof`) +/// This function can be used to verify received MMR [primitives::Proof] (`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::BatchProof]. +/// [primitives::Proof]. pub fn verify_leaves_proof( root: H::Output, leaves: Vec>, - proof: primitives::BatchProof, + proof: primitives::Proof, ) -> Result<(), primitives::Error> where H: traits::Hash, @@ -393,10 +393,7 @@ impl, I: 'static> Pallet { pub fn generate_proof( block_numbers: Vec, best_known_block_number: Option, - ) -> Result< - (Vec>, primitives::BatchProof<>::Hash>), - primitives::Error, - > { + ) -> Result<(Vec>, primitives::Proof<>::Hash>), 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(|| >::block_number()); @@ -429,7 +426,7 @@ impl, I: 'static> Pallet { /// or the proof is invalid. pub fn verify_leaves( leaves: Vec>, - proof: primitives::BatchProof<>::Hash>, + proof: primitives::Proof<>::Hash>, ) -> Result<(), primitives::Error> { if proof.leaf_count > Self::mmr_leaves() || proof.leaf_count == 0 || diff --git a/frame/merkle-mountain-range/src/mmr/mmr.rs b/frame/merkle-mountain-range/src/mmr/mmr.rs index 10cd05cbae821..078384486ae43 100644 --- a/frame/merkle-mountain-range/src/mmr/mmr.rs +++ b/frame/merkle-mountain-range/src/mmr/mmr.rs @@ -29,11 +29,11 @@ use sp_std::prelude::*; /// Stateless verification of the proof for a batch of leaves. /// 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::BatchProof] +/// [primitives::Proof] pub fn verify_leaves_proof( root: H::Output, leaves: Vec>, - proof: primitives::BatchProof, + proof: primitives::Proof, ) -> Result where H: sp_runtime::traits::Hash, @@ -91,11 +91,11 @@ where /// Verify proof for a set of leaves. /// 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::BatchProof] + /// [primitives::Proof] pub fn verify_leaves_proof( &self, leaves: Vec, - proof: primitives::BatchProof<>::Hash>, + proof: primitives::Proof<>::Hash>, ) -> Result { let p = mmr_lib::MerkleProof::, Hasher, L>>::new( self.mmr.mmr_size(), @@ -166,7 +166,7 @@ where pub fn generate_proof( &self, leaf_indices: Vec, - ) -> Result<(Vec, primitives::BatchProof<>::Hash>), Error> { + ) -> Result<(Vec, primitives::Proof<>::Hash>), Error> { let positions = leaf_indices .iter() .map(|index| mmr_lib::leaf_index_to_pos(*index)) @@ -184,7 +184,7 @@ where self.mmr .gen_proof(positions) .map_err(|e| Error::GenerateProof.log_error(e)) - .map(|p| primitives::BatchProof { + .map(|p| primitives::Proof { leaf_indices, leaf_count, items: p.proof_items().iter().map(|x| x.hash()).collect(), diff --git a/frame/merkle-mountain-range/src/tests.rs b/frame/merkle-mountain-range/src/tests.rs index 15d924a7eb63b..e47f1b3b2e63a 100644 --- a/frame/merkle-mountain-range/src/tests.rs +++ b/frame/merkle-mountain-range/src/tests.rs @@ -27,7 +27,7 @@ use sp_core::{ offchain::{testing::TestOffchainExt, OffchainDbExt, OffchainWorkerExt}, H256, }; -use sp_mmr_primitives::{BatchProof, Compact}; +use sp_mmr_primitives::{Compact, Proof}; pub(crate) fn new_test_ext() -> sp_io::TestExternalities { frame_system::GenesisConfig::default().build_storage::().unwrap().into() @@ -261,7 +261,7 @@ fn should_generate_proofs_correctly() { proofs[0], ( vec![Compact::new(((0, H256::repeat_byte(1)).into(), LeafData::new(1).into(),))], - BatchProof { + Proof { leaf_indices: vec![0], leaf_count: 7, items: vec![ @@ -276,7 +276,7 @@ fn should_generate_proofs_correctly() { historical_proofs[0][0], ( vec![Compact::new(((0, H256::repeat_byte(1)).into(), LeafData::new(1).into(),))], - BatchProof { leaf_indices: vec![0], leaf_count: 1, items: vec![] } + Proof { leaf_indices: vec![0], leaf_count: 1, items: vec![] } ) ); @@ -292,7 +292,7 @@ fn should_generate_proofs_correctly() { proofs[2], ( vec![Compact::new(((2, H256::repeat_byte(3)).into(), LeafData::new(3).into(),))], - BatchProof { + Proof { leaf_indices: vec![2], leaf_count: 7, items: vec![ @@ -312,7 +312,7 @@ fn should_generate_proofs_correctly() { historical_proofs[2][0], ( vec![Compact::new(((2, H256::repeat_byte(3)).into(), LeafData::new(3).into(),))], - BatchProof { + Proof { leaf_indices: vec![2], leaf_count: 3, items: vec![hex( @@ -332,7 +332,7 @@ fn should_generate_proofs_correctly() { historical_proofs[2][2], ( vec![Compact::new(((2, H256::repeat_byte(3)).into(), LeafData::new(3).into(),))], - BatchProof { + Proof { leaf_indices: vec![2], leaf_count: 5, items: vec![ @@ -350,7 +350,7 @@ fn should_generate_proofs_correctly() { ( // 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 { + Proof { leaf_indices: vec![4], leaf_count: 7, items: vec![ @@ -365,7 +365,7 @@ fn should_generate_proofs_correctly() { historical_proofs[4][0], ( vec![Compact::new(((4, H256::repeat_byte(5)).into(), LeafData::new(5).into(),))], - BatchProof { + Proof { leaf_indices: vec![4], leaf_count: 5, items: vec![hex( @@ -380,7 +380,7 @@ fn should_generate_proofs_correctly() { proofs[6], ( vec![Compact::new(((6, H256::repeat_byte(7)).into(), LeafData::new(7).into(),))], - BatchProof { + Proof { leaf_indices: vec![6], leaf_count: 7, items: vec![ @@ -411,7 +411,7 @@ fn should_generate_batch_proof_correctly() { // then assert_eq!( proof, - BatchProof { + Proof { // the leaf indices are equivalent to the above specified block numbers - 1. leaf_indices: vec![0, 4, 5], leaf_count: 7, @@ -429,7 +429,7 @@ fn should_generate_batch_proof_correctly() { // then assert_eq!( historical_proof, - BatchProof { + Proof { leaf_indices: vec![0, 4, 5], leaf_count: 6, items: vec![ diff --git a/primitives/merkle-mountain-range/src/lib.rs b/primitives/merkle-mountain-range/src/lib.rs index 366bbd1e2c500..6a1c941886cb8 100644 --- a/primitives/merkle-mountain-range/src/lib.rs +++ b/primitives/merkle-mountain-range/src/lib.rs @@ -69,17 +69,6 @@ impl OnNewRoot for () { fn on_new_root(_root: &Hash) {} } -/// A MMR proof data for one of the leaves. -#[derive(codec::Encode, codec::Decode, RuntimeDebug, Clone, PartialEq, Eq, TypeInfo)] -pub struct Proof { - /// The index of the leaf the proof is for. - pub leaf_index: LeafIndex, - /// Number of leaves in MMR, when the proof was generated. - pub leaf_count: NodeIndex, - /// Proof elements (hashes of siblings of inner nodes on the path to the leaf). - pub items: Vec, -} - /// A full leaf content stored in the offchain-db. pub trait FullLeaf: Clone + PartialEq + fmt::Debug { /// Encode the leaf either in its full or compact form. @@ -354,7 +343,7 @@ impl_leaf_data_for_tuple!(A:0, B:1, C:2, D:3, E:4); /// A MMR proof data for a group of leaves. #[derive(codec::Encode, codec::Decode, RuntimeDebug, Clone, PartialEq, Eq, TypeInfo)] -pub struct BatchProof { +pub struct Proof { /// The indices of the leaves the proof is for. pub leaf_indices: Vec, /// Number of leaves in MMR, when the proof was generated. @@ -424,14 +413,14 @@ sp_api::decl_runtime_apis! { fn generate_proof( block_numbers: Vec, best_known_block_number: Option - ) -> Result<(Vec, BatchProof), Error>; + ) -> Result<(Vec, Proof), Error>; /// Verify MMR proof against on-chain MMR for a batch of leaves. /// /// Note this function will use on-chain MMR root hash and check if the proof matches the hash. /// 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 [BatchProof] - fn verify_proof(leaves: Vec, proof: BatchProof) -> Result<(), Error>; + /// same position in both the `leaves` vector and the `leaf_indices` vector contained in the [Proof] + fn verify_proof(leaves: Vec, proof: Proof) -> Result<(), Error>; /// Verify MMR proof against given root hash for a batch of leaves. /// @@ -439,8 +428,8 @@ sp_api::decl_runtime_apis! { /// proof is verified against given MMR root hash. /// /// 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 [BatchProof] - fn verify_proof_stateless(root: Hash, leaves: Vec, proof: BatchProof) + /// same position in both the `leaves` vector and the `leaf_indices` vector contained in the [Proof] + fn verify_proof_stateless(root: Hash, leaves: Vec, proof: Proof) -> Result<(), Error>; } } @@ -459,12 +448,12 @@ mod tests { type Test = DataOrHash; type TestCompact = Compact; - type TestProof = BatchProof<::Output>; + type TestProof = Proof<::Output>; #[test] fn should_encode_decode_proof() { // given - let proof: TestProof = BatchProof { + let proof: TestProof = Proof { leaf_indices: vec![5], leaf_count: 10, items: vec![ From f0454e5ad35f533766bd723fe25cfe6112da3bf1 Mon Sep 17 00:00:00 2001 From: Robert Hambrock Date: Wed, 19 Oct 2022 17:18:43 +0200 Subject: [PATCH 10/21] cleanup --- frame/beefy-mmr/primitives/src/lib.rs | 2 +- primitives/merkle-mountain-range/src/lib.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/frame/beefy-mmr/primitives/src/lib.rs b/frame/beefy-mmr/primitives/src/lib.rs index f56be8bcafe5b..f88fb89acaaab 100644 --- a/frame/beefy-mmr/primitives/src/lib.rs +++ b/frame/beefy-mmr/primitives/src/lib.rs @@ -29,7 +29,7 @@ //! Inner nodes are created by concatenating child hashes and hashing again. The implementation //! does not perform any sorting of the input data (leaves) nor when inner nodes are created. //! -//! If the number of leaves is not even, last leave (hash of) is promoted to the upper layer. +//! If the number of leaves is not even, last leaf (hash of) is promoted to the upper layer. pub use sp_runtime::traits::Keccak256; use sp_runtime::{app_crypto::sp_core, sp_std, traits::Hash as HashT}; diff --git a/primitives/merkle-mountain-range/src/lib.rs b/primitives/merkle-mountain-range/src/lib.rs index 6a1c941886cb8..05a1a36c73f83 100644 --- a/primitives/merkle-mountain-range/src/lib.rs +++ b/primitives/merkle-mountain-range/src/lib.rs @@ -23,9 +23,9 @@ use scale_info::TypeInfo; use sp_debug_derive::RuntimeDebug; use sp_runtime::traits; +use sp_std::fmt; #[cfg(not(feature = "std"))] use sp_std::prelude::Vec; -use sp_std::{fmt, vec}; /// A type to describe node position in the MMR (node index). pub type NodeIndex = u64; From e77bcd9f628f3215381c57d52751d99042743096 Mon Sep 17 00:00:00 2001 From: Robert Hambrock Date: Sun, 6 Nov 2022 23:56:48 +0100 Subject: [PATCH 11/21] expose verify_proof rpc api --- frame/merkle-mountain-range/rpc/src/lib.rs | 51 +++++++++++++++++++++- 1 file changed, 50 insertions(+), 1 deletion(-) diff --git a/frame/merkle-mountain-range/rpc/src/lib.rs b/frame/merkle-mountain-range/rpc/src/lib.rs index 98a35c5a0c033..f376fb11347b6 100644 --- a/frame/merkle-mountain-range/rpc/src/lib.rs +++ b/frame/merkle-mountain-range/rpc/src/lib.rs @@ -22,7 +22,7 @@ use std::{marker::PhantomData, sync::Arc}; -use codec::{Codec, Encode}; +use codec::{Codec, Encode, Decode}; use jsonrpsee::{ core::{async_trait, RpcResult}, proc_macros::rpc, @@ -42,6 +42,9 @@ const RUNTIME_ERROR: i32 = 8000; const MMR_ERROR: i32 = 8010; const LEAF_NOT_FOUND_ERROR: i32 = MMR_ERROR + 1; const GENERATE_PROOF_ERROR: i32 = MMR_ERROR + 2; +const VERIFY_PROOF_ERROR: i32 = MMR_ERROR + 3; +const BLOCK_NUM_TO_LEAF_INDEX_ERROR: i32 = MMR_ERROR + 4; +const INVALID_BEST_KNOWN_BLOCK_ERROR: i32 = MMR_ERROR + 5; /// Retrieved MMR leaves and their proof. #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)] @@ -100,6 +103,14 @@ pub trait MmrApi { best_known_block_number: Option, at: Option, ) -> RpcResult>; + + /// Verify a MMR proof for the given `leaves` + /// TODO: add docs + #[method(name = "mmr_verifyProof")] + fn verify_proof( + &self, + proof: LeavesProof, + ) -> RpcResult; } /// MMR RPC methods. @@ -147,6 +158,29 @@ where Ok(LeavesProof::new(block_hash, leaves, proof)) } + + fn verify_proof( + &self, + proof: LeavesProof<::Hash>, + ) -> RpcResult { + let api = self.client.runtime_api(); + + let leaves = Decode::decode(&mut &proof.leaves.0[..]) + .map_err(runtime_error_into_rpc_error)?; + + let decoded_proof = Decode::decode(&mut &proof.proof.0[..]) + .map_err(runtime_error_into_rpc_error)?; + + api.verify_proof_with_context( + &BlockId::hash(proof.block_hash), + sp_core::ExecutionContext::OffchainCall(None), + leaves, + decoded_proof, + ).map_err(runtime_error_into_rpc_error)? + .map_err(mmr_error_into_rpc_error)?; + + Ok(true) + } } /// Converts a mmr-specific error into a [`CallError`]. @@ -163,6 +197,21 @@ fn mmr_error_into_rpc_error(err: MmrError) -> CallError { "Error while generating the proof", Some(data), )), + MmrError::Verify => CallError::Custom(ErrorObject::owned( + VERIFY_PROOF_ERROR, + "Error while verifying the proof", + Some(data), + )), + MmrError::BlockNumToLeafIndex => CallError::Custom(ErrorObject::owned( + BLOCK_NUM_TO_LEAF_INDEX_ERROR, + "Error while converting block number to leaf index", + Some(data), + )), + MmrError::InvalidBestKnownBlock => CallError::Custom(ErrorObject::owned( + INVALID_BEST_KNOWN_BLOCK_ERROR, + "Invalid best known block", + Some(data), + )), _ => CallError::Custom(ErrorObject::owned(MMR_ERROR, "Unexpected MMR error", Some(data))), } } From 1c599ef8c6508c77b595eea767e366d6e7880b9e Mon Sep 17 00:00:00 2001 From: Robert Hambrock Date: Mon, 7 Nov 2022 00:20:40 +0100 Subject: [PATCH 12/21] document verify_proof --- frame/merkle-mountain-range/rpc/src/lib.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/frame/merkle-mountain-range/rpc/src/lib.rs b/frame/merkle-mountain-range/rpc/src/lib.rs index f376fb11347b6..4ef80afecf94e 100644 --- a/frame/merkle-mountain-range/rpc/src/lib.rs +++ b/frame/merkle-mountain-range/rpc/src/lib.rs @@ -104,8 +104,12 @@ pub trait MmrApi { at: Option, ) -> RpcResult>; - /// Verify a MMR proof for the given `leaves` - /// TODO: add docs + /// Verify an MMR `proof`. + /// + /// This method calls into a runtime with MMR pallet included and attempts to verify + /// a MMR proof. + /// + /// Returns `true` if the proof is valid, else returns the verification error. #[method(name = "mmr_verifyProof")] fn verify_proof( &self, From 159712ece53fa517706a286df209f9008c7e6978 Mon Sep 17 00:00:00 2001 From: Robert Hambrock Date: Mon, 7 Nov 2022 00:55:58 +0100 Subject: [PATCH 13/21] expose verify_proof_stateless rpc api --- frame/merkle-mountain-range/rpc/src/lib.rs | 56 ++++++++++++++++++++-- 1 file changed, 53 insertions(+), 3 deletions(-) diff --git a/frame/merkle-mountain-range/rpc/src/lib.rs b/frame/merkle-mountain-range/rpc/src/lib.rs index 4ef80afecf94e..2c15deda914e5 100644 --- a/frame/merkle-mountain-range/rpc/src/lib.rs +++ b/frame/merkle-mountain-range/rpc/src/lib.rs @@ -76,8 +76,11 @@ impl LeavesProof { /// MMR RPC methods. #[rpc(client, server)] -pub trait MmrApi { - /// Generate a MMR proof for the given `block_numbers`. +pub trait MmrApi { + /// Get the MMR root hash for the current best block. + #[method(name = "mmr_root")] + fn mmr_root(&self) -> RpcResult; + /// Generate an MMR proof for the given `block_numbers`. /// /// This method calls into a runtime with MMR pallet included and attempts to generate /// a MMR proof for the set of blocks that have the given `block_numbers` with MMR given the @@ -115,6 +118,19 @@ pub trait MmrApi { &self, proof: LeavesProof, ) -> RpcResult; + + /// Verify an MMR `proof` statelessly given an `mmr_root`. + /// + /// This method calls into a runtime with MMR pallet included and attempts to verify + /// a MMR proof against a provided mmr root. + /// + /// Returns `true` if the proof is valid, else returns the verification error. + #[method(name = "mmr_verifyProofStateless")] + fn verify_proof_stateless( + &self, + mmr_root: MmrHash, + proof: LeavesProof, + ) -> RpcResult; } /// MMR RPC methods. @@ -131,7 +147,7 @@ impl Mmr { } #[async_trait] -impl MmrApiServer<::Hash, NumberFor> +impl MmrApiServer<::Hash, NumberFor, MmrHash> for Mmr where Block: BlockT, @@ -139,6 +155,15 @@ where Client::Api: MmrRuntimeApi>, MmrHash: Codec + Send + Sync + 'static, { + fn mmr_root(&self) -> RpcResult { + let best_block_hash = self.client.info().best_hash; + let api = self.client.runtime_api(); + let mmr_root = api.mmr_root(&BlockId::Hash(best_block_hash)) + .map_err(runtime_error_into_rpc_error)? + .map_err(mmr_error_into_rpc_error)?; + Ok(mmr_root) + } + fn generate_proof( &self, block_numbers: Vec>, @@ -185,6 +210,31 @@ where Ok(true) } + + fn verify_proof_stateless( + &self, + mmr_root: MmrHash, + proof: LeavesProof<::Hash>, + ) -> RpcResult { + let api = self.client.runtime_api(); + + let leaves = + Decode::decode(&mut &proof.leaves.0[..]).map_err(runtime_error_into_rpc_error)?; + + let decoded_proof = + Decode::decode(&mut &proof.proof.0[..]).map_err(runtime_error_into_rpc_error)?; + + api.verify_proof_stateless( + &BlockId::hash(proof.block_hash), + mmr_root, + leaves, + decoded_proof, + ) + .map_err(runtime_error_into_rpc_error)? + .map_err(mmr_error_into_rpc_error)?; + + Ok(true) + } } /// Converts a mmr-specific error into a [`CallError`]. From d576d3aa73a0038a136a7c0639d6c5326ed88e1b Mon Sep 17 00:00:00 2001 From: Robert Hambrock Date: Mon, 7 Nov 2022 01:06:19 +0100 Subject: [PATCH 14/21] add optional BlockHash to mmr_root rpc api --- frame/merkle-mountain-range/rpc/src/lib.rs | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/frame/merkle-mountain-range/rpc/src/lib.rs b/frame/merkle-mountain-range/rpc/src/lib.rs index 2c15deda914e5..95d574fb06300 100644 --- a/frame/merkle-mountain-range/rpc/src/lib.rs +++ b/frame/merkle-mountain-range/rpc/src/lib.rs @@ -79,7 +79,8 @@ impl LeavesProof { pub trait MmrApi { /// Get the MMR root hash for the current best block. #[method(name = "mmr_root")] - fn mmr_root(&self) -> RpcResult; + fn mmr_root(&self, at: Option) -> RpcResult; + /// Generate an MMR proof for the given `block_numbers`. /// /// This method calls into a runtime with MMR pallet included and attempts to generate @@ -155,12 +156,15 @@ where Client::Api: MmrRuntimeApi>, MmrHash: Codec + Send + Sync + 'static, { - fn mmr_root(&self) -> RpcResult { - let best_block_hash = self.client.info().best_hash; + fn mmr_root(&self, at: Option<::Hash>) -> RpcResult { + let block_hash = at.unwrap_or_else(|| + // If the block hash is not supplied assume the best block. + self.client.info().best_hash); let api = self.client.runtime_api(); - let mmr_root = api.mmr_root(&BlockId::Hash(best_block_hash)) - .map_err(runtime_error_into_rpc_error)? - .map_err(mmr_error_into_rpc_error)?; + let mmr_root = api + .mmr_root(&BlockId::Hash(block_hash)) + .map_err(runtime_error_into_rpc_error)? + .map_err(mmr_error_into_rpc_error)?; Ok(mmr_root) } From 087c77e21a7aad7abbb8d9810989096a8cfd4610 Mon Sep 17 00:00:00 2001 From: Robert Hambrock Date: Mon, 7 Nov 2022 01:08:02 +0100 Subject: [PATCH 15/21] fixup! expose verify_proof rpc api --- frame/merkle-mountain-range/rpc/src/lib.rs | 25 +++++++++------------- 1 file changed, 10 insertions(+), 15 deletions(-) diff --git a/frame/merkle-mountain-range/rpc/src/lib.rs b/frame/merkle-mountain-range/rpc/src/lib.rs index 95d574fb06300..480cfc422ca34 100644 --- a/frame/merkle-mountain-range/rpc/src/lib.rs +++ b/frame/merkle-mountain-range/rpc/src/lib.rs @@ -22,7 +22,7 @@ use std::{marker::PhantomData, sync::Arc}; -use codec::{Codec, Encode, Decode}; +use codec::{Codec, Decode, Encode}; use jsonrpsee::{ core::{async_trait, RpcResult}, proc_macros::rpc, @@ -115,10 +115,7 @@ pub trait MmrApi { /// /// Returns `true` if the proof is valid, else returns the verification error. #[method(name = "mmr_verifyProof")] - fn verify_proof( - &self, - proof: LeavesProof, - ) -> RpcResult; + fn verify_proof(&self, proof: LeavesProof) -> RpcResult; /// Verify an MMR `proof` statelessly given an `mmr_root`. /// @@ -192,25 +189,23 @@ where Ok(LeavesProof::new(block_hash, leaves, proof)) } - fn verify_proof( - &self, - proof: LeavesProof<::Hash>, - ) -> RpcResult { + fn verify_proof(&self, proof: LeavesProof<::Hash>) -> RpcResult { let api = self.client.runtime_api(); - let leaves = Decode::decode(&mut &proof.leaves.0[..]) - .map_err(runtime_error_into_rpc_error)?; + let leaves = + Decode::decode(&mut &proof.leaves.0[..]).map_err(runtime_error_into_rpc_error)?; - let decoded_proof = Decode::decode(&mut &proof.proof.0[..]) - .map_err(runtime_error_into_rpc_error)?; + let decoded_proof = + Decode::decode(&mut &proof.proof.0[..]).map_err(runtime_error_into_rpc_error)?; api.verify_proof_with_context( &BlockId::hash(proof.block_hash), sp_core::ExecutionContext::OffchainCall(None), leaves, decoded_proof, - ).map_err(runtime_error_into_rpc_error)? - .map_err(mmr_error_into_rpc_error)?; + ) + .map_err(runtime_error_into_rpc_error)? + .map_err(mmr_error_into_rpc_error)?; Ok(true) } From 39f3676532bd06dc5ae56987af05f0696bf42f46 Mon Sep 17 00:00:00 2001 From: Robert Hambrock Date: Mon, 7 Nov 2022 09:55:06 +0100 Subject: [PATCH 16/21] fix documentation phrasing Co-authored-by: Adrian Catangiu --- frame/merkle-mountain-range/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frame/merkle-mountain-range/src/lib.rs b/frame/merkle-mountain-range/src/lib.rs index f5b8ff8265e84..91798ce657548 100644 --- a/frame/merkle-mountain-range/src/lib.rs +++ b/frame/merkle-mountain-range/src/lib.rs @@ -383,7 +383,7 @@ impl, I: 'static> Pallet { /// Generate a MMR proof for the given `block_numbers`. /// If `best_known_block_number = Some(n)`, this generates a historical proof for - /// the head of the chain was at height `n`. + /// the chain with head at height `n`. /// Else it generates a proof for the MMR at the current block height. /// /// Note this method can only be used from an off-chain context From 212161d5cddf041060025b8ded705cd266c51546 Mon Sep 17 00:00:00 2001 From: Robert Hambrock Date: Mon, 7 Nov 2022 23:55:11 +0100 Subject: [PATCH 17/21] documentation grammar Co-authored-by: Adrian Catangiu --- frame/merkle-mountain-range/rpc/src/lib.rs | 8 ++++---- frame/merkle-mountain-range/src/lib.rs | 8 ++++---- frame/merkle-mountain-range/src/mmr/mmr.rs | 2 +- frame/merkle-mountain-range/src/mmr/storage.rs | 2 +- primitives/beefy/src/mmr.rs | 2 +- primitives/merkle-mountain-range/src/lib.rs | 2 +- 6 files changed, 12 insertions(+), 12 deletions(-) diff --git a/frame/merkle-mountain-range/rpc/src/lib.rs b/frame/merkle-mountain-range/rpc/src/lib.rs index 480cfc422ca34..1985640cd20da 100644 --- a/frame/merkle-mountain-range/rpc/src/lib.rs +++ b/frame/merkle-mountain-range/rpc/src/lib.rs @@ -84,7 +84,7 @@ pub trait MmrApi { /// Generate an MMR proof for the given `block_numbers`. /// /// This method calls into a runtime with MMR pallet included and attempts to generate - /// a MMR proof for the set of blocks that have the given `block_numbers` with MMR given the + /// an MMR proof for the set of blocks that have the given `block_numbers` with the MMR root at /// `best_known_block_number`. `best_known_block_number` must be larger than all the /// `block_numbers` for the function to succeed. /// @@ -111,7 +111,7 @@ pub trait MmrApi { /// Verify an MMR `proof`. /// /// This method calls into a runtime with MMR pallet included and attempts to verify - /// a MMR proof. + /// an MMR proof. /// /// Returns `true` if the proof is valid, else returns the verification error. #[method(name = "mmr_verifyProof")] @@ -120,7 +120,7 @@ pub trait MmrApi { /// Verify an MMR `proof` statelessly given an `mmr_root`. /// /// This method calls into a runtime with MMR pallet included and attempts to verify - /// a MMR proof against a provided mmr root. + /// an MMR proof against a provided MMR root. /// /// Returns `true` if the proof is valid, else returns the verification error. #[method(name = "mmr_verifyProofStateless")] @@ -236,7 +236,7 @@ where } } -/// Converts a mmr-specific error into a [`CallError`]. +/// Converts an mmr-specific error into a [`CallError`]. fn mmr_error_into_rpc_error(err: MmrError) -> CallError { let data = format!("{:?}", err); match err { diff --git a/frame/merkle-mountain-range/src/lib.rs b/frame/merkle-mountain-range/src/lib.rs index 91798ce657548..a2d42417ae5dc 100644 --- a/frame/merkle-mountain-range/src/lib.rs +++ b/frame/merkle-mountain-range/src/lib.rs @@ -22,7 +22,7 @@ //! Details on Merkle Mountain Ranges (MMRs) can be found here: //! //! -//! The MMR pallet constructs a MMR from leaf data obtained on every block from +//! The MMR pallet constructs an MMR from leaf data obtained on every block from //! `LeafDataProvider`. MMR nodes are stored both in: //! - on-chain storage - hashes only; not full leaf content) //! - off-chain storage - via Indexing API we push full leaf content (and all internal nodes as @@ -50,7 +50,7 @@ //! //! Secondary use case is to archive historical data, but still be able to retrieve them on-demand //! if needed. For instance if parent block hashes are stored in the MMR it's possible at any point -//! in time to provide a MMR proof about some past block hash, while this data can be safely pruned +//! in time to provide an MMR proof about some past block hash, while this data can be safely pruned //! from on-chain storage. //! //! NOTE This pallet is experimental and not proven to work in production. @@ -103,7 +103,7 @@ pub trait WeightInfo { fn on_initialize(peaks: NodeIndex) -> Weight; } -/// A MMR specific to the pallet. +/// An MMR specific to the pallet. type ModuleMmr = mmr::Mmr>; /// Leaf data. @@ -381,7 +381,7 @@ impl, I: 'static> Pallet { Ok(leaf_idx) } - /// Generate a MMR proof for the given `block_numbers`. + /// Generate an MMR proof for the given `block_numbers`. /// If `best_known_block_number = Some(n)`, this generates a historical proof for /// the chain with head at height `n`. /// Else it generates a proof for the MMR at the current block height. diff --git a/frame/merkle-mountain-range/src/mmr/mmr.rs b/frame/merkle-mountain-range/src/mmr/mmr.rs index 078384486ae43..1f5a5bdae380b 100644 --- a/frame/merkle-mountain-range/src/mmr/mmr.rs +++ b/frame/merkle-mountain-range/src/mmr/mmr.rs @@ -60,7 +60,7 @@ where .map_err(|e| Error::Verify.log_debug(e)) } -/// A wrapper around a MMR library to expose limited functionality. +/// A wrapper around an MMR library to expose limited functionality. /// /// Available functions depend on the storage kind ([Runtime](crate::mmr::storage::RuntimeStorage) /// vs [Off-chain](crate::mmr::storage::OffchainStorage)). diff --git a/frame/merkle-mountain-range/src/mmr/storage.rs b/frame/merkle-mountain-range/src/mmr/storage.rs index 870ce81226bd2..d16ca8cf1e5c8 100644 --- a/frame/merkle-mountain-range/src/mmr/storage.rs +++ b/frame/merkle-mountain-range/src/mmr/storage.rs @@ -15,7 +15,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! A MMR storage implementations. +//! An MMR storage implementation. use codec::Encode; use frame_support::log::{debug, error, trace}; diff --git a/primitives/beefy/src/mmr.rs b/primitives/beefy/src/mmr.rs index 0edb8babd608e..35db07f294698 100644 --- a/primitives/beefy/src/mmr.rs +++ b/primitives/beefy/src/mmr.rs @@ -64,7 +64,7 @@ pub struct MmrLeaf { pub leaf_extra: ExtraData, } -/// A MMR leaf versioning scheme. +/// An MMR leaf versioning scheme. /// /// Version is a single byte that constist of two components: /// - `major` - 3 bits diff --git a/primitives/merkle-mountain-range/src/lib.rs b/primitives/merkle-mountain-range/src/lib.rs index 05a1a36c73f83..04761ef2fda89 100644 --- a/primitives/merkle-mountain-range/src/lib.rs +++ b/primitives/merkle-mountain-range/src/lib.rs @@ -341,7 +341,7 @@ impl_leaf_data_for_tuple!(A:0, B:1, C:2); impl_leaf_data_for_tuple!(A:0, B:1, C:2, D:3); impl_leaf_data_for_tuple!(A:0, B:1, C:2, D:3, E:4); -/// A MMR proof data for a group of leaves. +/// An MMR proof data for a group of leaves. #[derive(codec::Encode, codec::Decode, RuntimeDebug, Clone, PartialEq, Eq, TypeInfo)] pub struct Proof { /// The indices of the leaves the proof is for. From d5f4cf7de571e11701aeb8738b79df215cd916d4 Mon Sep 17 00:00:00 2001 From: Robert Hambrock Date: Tue, 8 Nov 2022 16:28:09 +0100 Subject: [PATCH 18/21] define mmr error msgs together with error enum Co-authored-by: Serban Iorga --- Cargo.lock | 1 + frame/merkle-mountain-range/rpc/src/lib.rs | 47 ++++++--------------- primitives/merkle-mountain-range/Cargo.toml | 1 + primitives/merkle-mountain-range/src/lib.rs | 13 +++++- 4 files changed, 27 insertions(+), 35 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 48205d9bd86da..d1ad4e397269f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -9816,6 +9816,7 @@ dependencies = [ "sp-debug-derive", "sp-runtime", "sp-std", + "thiserror", ] [[package]] diff --git a/frame/merkle-mountain-range/rpc/src/lib.rs b/frame/merkle-mountain-range/rpc/src/lib.rs index 1985640cd20da..250cb8d7bff89 100644 --- a/frame/merkle-mountain-range/rpc/src/lib.rs +++ b/frame/merkle-mountain-range/rpc/src/lib.rs @@ -40,11 +40,6 @@ pub use sp_mmr_primitives::MmrApi as MmrRuntimeApi; const RUNTIME_ERROR: i32 = 8000; const MMR_ERROR: i32 = 8010; -const LEAF_NOT_FOUND_ERROR: i32 = MMR_ERROR + 1; -const GENERATE_PROOF_ERROR: i32 = MMR_ERROR + 2; -const VERIFY_PROOF_ERROR: i32 = MMR_ERROR + 3; -const BLOCK_NUM_TO_LEAF_INDEX_ERROR: i32 = MMR_ERROR + 4; -const INVALID_BEST_KNOWN_BLOCK_ERROR: i32 = MMR_ERROR + 5; /// Retrieved MMR leaves and their proof. #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)] @@ -238,35 +233,19 @@ where /// Converts an mmr-specific error into a [`CallError`]. fn mmr_error_into_rpc_error(err: MmrError) -> CallError { - let data = format!("{:?}", err); - match err { - MmrError::LeafNotFound => CallError::Custom(ErrorObject::owned( - LEAF_NOT_FOUND_ERROR, - "Leaf was not found", - Some(data), - )), - MmrError::GenerateProof => CallError::Custom(ErrorObject::owned( - GENERATE_PROOF_ERROR, - "Error while generating the proof", - Some(data), - )), - MmrError::Verify => CallError::Custom(ErrorObject::owned( - VERIFY_PROOF_ERROR, - "Error while verifying the proof", - Some(data), - )), - MmrError::BlockNumToLeafIndex => CallError::Custom(ErrorObject::owned( - BLOCK_NUM_TO_LEAF_INDEX_ERROR, - "Error while converting block number to leaf index", - Some(data), - )), - MmrError::InvalidBestKnownBlock => CallError::Custom(ErrorObject::owned( - INVALID_BEST_KNOWN_BLOCK_ERROR, - "Invalid best known block", - Some(data), - )), - _ => CallError::Custom(ErrorObject::owned(MMR_ERROR, "Unexpected MMR error", Some(data))), - } + let error_code = MMR_ERROR + match err { + MmrError::LeafNotFound => 1, + MmrError::GenerateProof => 2, + MmrError::Verify => 3, + MmrError::BlockNumToLeafIndex => 4, + MmrError::InvalidBestKnownBlock => 5, + _ => 0, + }; + + CallError::Custom(ErrorObject::owned( + error_code, + err.to_string(), + Some(format!("{:?}", err)))) } /// Converts a runtime trap into a [`CallError`]. diff --git a/primitives/merkle-mountain-range/Cargo.toml b/primitives/merkle-mountain-range/Cargo.toml index 0be53132f3eec..e857974ba898c 100644 --- a/primitives/merkle-mountain-range/Cargo.toml +++ b/primitives/merkle-mountain-range/Cargo.toml @@ -21,6 +21,7 @@ sp-core = { version = "6.0.0", default-features = false, path = "../core" } sp-debug-derive = { version = "4.0.0", default-features = false, path = "../debug-derive" } sp-runtime = { version = "6.0.0", default-features = false, path = "../runtime" } sp-std = { version = "4.0.0", default-features = false, path = "../std" } +thiserror = "1.0" [dev-dependencies] array-bytes = "4.1" diff --git a/primitives/merkle-mountain-range/src/lib.rs b/primitives/merkle-mountain-range/src/lib.rs index 04761ef2fda89..d46cb73c3c5e8 100644 --- a/primitives/merkle-mountain-range/src/lib.rs +++ b/primitives/merkle-mountain-range/src/lib.rs @@ -353,27 +353,38 @@ pub struct Proof { } /// Merkle Mountain Range operation error. +#[cfg_attr(feature = "std", derive(thiserror::Error))] #[derive(RuntimeDebug, codec::Encode, codec::Decode, PartialEq, Eq)] pub enum Error { /// Error during translation of a block number into a leaf index. + #[cfg_attr(feature = "std", error("Error translation block number into leaf index"))] BlockNumToLeafIndex, /// Error while pushing new node. + #[cfg_attr(feature = "std", error("Error pushing new node"))] Push, /// Error getting the new root. + #[cfg_attr(feature = "std", error("Error getting new root"))] GetRoot, - /// Error commiting changes. + /// Error committing changes. + #[cfg_attr(feature = "std", error("Error committing changes"))] Commit, /// Error during proof generation. + #[cfg_attr(feature = "std", error("Error generating proof"))] GenerateProof, /// Proof verification error. + #[cfg_attr(feature = "std", error("Invalid proof"))] Verify, /// Leaf not found in the storage. + #[cfg_attr(feature = "std", error("Leaf was not found"))] LeafNotFound, /// Mmr Pallet not included in runtime + #[cfg_attr(feature = "std", error("MMR pallet not included in runtime"))] PalletNotIncluded, /// Cannot find the requested leaf index + #[cfg_attr(feature = "std", error("Requested leaf index invalid"))] InvalidLeafIndex, /// The provided best know block number is invalid. + #[cfg_attr(feature = "std", error("Provided best known block number invalid"))] InvalidBestKnownBlock, } From a7069fd6c907e16ea285f4c61ab20dd8ebaa3c8f Mon Sep 17 00:00:00 2001 From: Robert Hambrock Date: Tue, 8 Nov 2022 16:41:45 +0100 Subject: [PATCH 19/21] fixup! define mmr error msgs together with error enum --- frame/merkle-mountain-range/rpc/src/lib.rs | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/frame/merkle-mountain-range/rpc/src/lib.rs b/frame/merkle-mountain-range/rpc/src/lib.rs index 250cb8d7bff89..c86ba9251539d 100644 --- a/frame/merkle-mountain-range/rpc/src/lib.rs +++ b/frame/merkle-mountain-range/rpc/src/lib.rs @@ -233,19 +233,17 @@ where /// Converts an mmr-specific error into a [`CallError`]. fn mmr_error_into_rpc_error(err: MmrError) -> CallError { - let error_code = MMR_ERROR + match err { - MmrError::LeafNotFound => 1, - MmrError::GenerateProof => 2, - MmrError::Verify => 3, - MmrError::BlockNumToLeafIndex => 4, - MmrError::InvalidBestKnownBlock => 5, - _ => 0, - }; + let error_code = MMR_ERROR + + match err { + MmrError::LeafNotFound => 1, + MmrError::GenerateProof => 2, + MmrError::Verify => 3, + MmrError::BlockNumToLeafIndex => 4, + MmrError::InvalidBestKnownBlock => 5, + _ => 0, + }; - CallError::Custom(ErrorObject::owned( - error_code, - err.to_string(), - Some(format!("{:?}", err)))) + CallError::Custom(ErrorObject::owned(error_code, err.to_string(), Some(format!("{:?}", err)))) } /// Converts a runtime trap into a [`CallError`]. From 63d76941b0b96df31d8c11930a0149fd5d5dda9a Mon Sep 17 00:00:00 2001 From: Robert Hambrock Date: Tue, 8 Nov 2022 17:22:04 +0100 Subject: [PATCH 20/21] map decoding errors to CallError::InvalidParams Co-authored-by: Serban Iorga --- Cargo.lock | 1 + frame/merkle-mountain-range/rpc/Cargo.toml | 1 + frame/merkle-mountain-range/rpc/src/lib.rs | 8 ++++---- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d1ad4e397269f..458923616827c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5745,6 +5745,7 @@ dependencies = [ name = "pallet-mmr-rpc" version = "3.0.0" dependencies = [ + "anyhow", "jsonrpsee", "parity-scale-codec", "serde", diff --git a/frame/merkle-mountain-range/rpc/Cargo.toml b/frame/merkle-mountain-range/rpc/Cargo.toml index 3da6678a39bf2..eb2e1e8b53d9e 100644 --- a/frame/merkle-mountain-range/rpc/Cargo.toml +++ b/frame/merkle-mountain-range/rpc/Cargo.toml @@ -21,6 +21,7 @@ sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" sp-core = { version = "6.0.0", path = "../../../primitives/core" } sp-mmr-primitives = { version = "4.0.0-dev", path = "../../../primitives/merkle-mountain-range" } sp-runtime = { version = "6.0.0", path = "../../../primitives/runtime" } +anyhow = "1" [dev-dependencies] serde_json = "1.0.85" diff --git a/frame/merkle-mountain-range/rpc/src/lib.rs b/frame/merkle-mountain-range/rpc/src/lib.rs index c86ba9251539d..1ccd29fd462f0 100644 --- a/frame/merkle-mountain-range/rpc/src/lib.rs +++ b/frame/merkle-mountain-range/rpc/src/lib.rs @@ -188,10 +188,10 @@ where let api = self.client.runtime_api(); let leaves = - Decode::decode(&mut &proof.leaves.0[..]).map_err(runtime_error_into_rpc_error)?; + Decode::decode(&mut &proof.leaves.0[..]).map_err(|e| CallError::InvalidParams(anyhow::Error::new(e)))?; let decoded_proof = - Decode::decode(&mut &proof.proof.0[..]).map_err(runtime_error_into_rpc_error)?; + Decode::decode(&mut &proof.proof.0[..]).map_err(|e| CallError::InvalidParams(anyhow::Error::new(e)))?; api.verify_proof_with_context( &BlockId::hash(proof.block_hash), @@ -213,10 +213,10 @@ where let api = self.client.runtime_api(); let leaves = - Decode::decode(&mut &proof.leaves.0[..]).map_err(runtime_error_into_rpc_error)?; + Decode::decode(&mut &proof.leaves.0[..]).map_err(|e| CallError::InvalidParams(anyhow::Error::new(e)))?; let decoded_proof = - Decode::decode(&mut &proof.proof.0[..]).map_err(runtime_error_into_rpc_error)?; + Decode::decode(&mut &proof.proof.0[..]).map_err(|e| CallError::InvalidParams(anyhow::Error::new(e)))?; api.verify_proof_stateless( &BlockId::hash(proof.block_hash), From 95aa6892e69a2d5bccdefbdacb0de97c17778f40 Mon Sep 17 00:00:00 2001 From: Robert Hambrock Date: Tue, 8 Nov 2022 18:12:34 +0100 Subject: [PATCH 21/21] fixup! map decoding errors to CallError::InvalidParams --- frame/merkle-mountain-range/rpc/src/lib.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/frame/merkle-mountain-range/rpc/src/lib.rs b/frame/merkle-mountain-range/rpc/src/lib.rs index 1ccd29fd462f0..8476d82f3e70d 100644 --- a/frame/merkle-mountain-range/rpc/src/lib.rs +++ b/frame/merkle-mountain-range/rpc/src/lib.rs @@ -187,11 +187,11 @@ where fn verify_proof(&self, proof: LeavesProof<::Hash>) -> RpcResult { let api = self.client.runtime_api(); - let leaves = - Decode::decode(&mut &proof.leaves.0[..]).map_err(|e| CallError::InvalidParams(anyhow::Error::new(e)))?; + let leaves = Decode::decode(&mut &proof.leaves.0[..]) + .map_err(|e| CallError::InvalidParams(anyhow::Error::new(e)))?; - let decoded_proof = - Decode::decode(&mut &proof.proof.0[..]).map_err(|e| CallError::InvalidParams(anyhow::Error::new(e)))?; + let decoded_proof = Decode::decode(&mut &proof.proof.0[..]) + .map_err(|e| CallError::InvalidParams(anyhow::Error::new(e)))?; api.verify_proof_with_context( &BlockId::hash(proof.block_hash), @@ -212,11 +212,11 @@ where ) -> RpcResult { let api = self.client.runtime_api(); - let leaves = - Decode::decode(&mut &proof.leaves.0[..]).map_err(|e| CallError::InvalidParams(anyhow::Error::new(e)))?; + let leaves = Decode::decode(&mut &proof.leaves.0[..]) + .map_err(|e| CallError::InvalidParams(anyhow::Error::new(e)))?; - let decoded_proof = - Decode::decode(&mut &proof.proof.0[..]).map_err(|e| CallError::InvalidParams(anyhow::Error::new(e)))?; + let decoded_proof = Decode::decode(&mut &proof.proof.0[..]) + .map_err(|e| CallError::InvalidParams(anyhow::Error::new(e)))?; api.verify_proof_stateless( &BlockId::hash(proof.block_hash),