-
Notifications
You must be signed in to change notification settings - Fork 248
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Stateless mmr proof for the consensus chain #2687
Changes from all commits
0951576
2cda1c7
5ded104
bde4d7b
1846c6b
75d47e9
19f3d3a
ff17a5f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -28,6 +28,7 @@ pub use runtime_interface::{domain_mmr_runtime_interface, subspace_mmr_runtime_i | |
|
||
use codec::{Codec, Decode, Encode}; | ||
use scale_info::TypeInfo; | ||
use sp_mmr_primitives::{EncodableOpaqueLeaf, Proof as MmrProof}; | ||
use sp_runtime::generic::OpaqueDigestItemId; | ||
use sp_runtime::DigestItem; | ||
|
||
|
@@ -81,3 +82,49 @@ impl<MmrRootHash: Codec> MmrDigest<MmrRootHash> for DigestItem { | |
} | ||
} | ||
} | ||
|
||
/// Consensus chain MMR leaf and its Proof at specific block. | ||
/// | ||
/// The verifier is not required to contains any the MMR offchain data but this proof | ||
/// will be expired after `N` blocks where `N` is the number of MMR root stored in the | ||
// consensus chain runtime. | ||
#[derive(Debug, Encode, Decode, Eq, PartialEq, TypeInfo)] | ||
pub struct ConsensusChainMmrLeafProof<CBlockNumber, CBlockHash, MmrHash> { | ||
/// Consensus block info from which this proof was generated. | ||
pub consensus_block_number: CBlockNumber, | ||
pub consensus_block_hash: CBlockHash, | ||
/// Encoded MMR leaf | ||
pub opaque_mmr_leaf: EncodableOpaqueLeaf, | ||
/// MMR proof for the leaf above. | ||
pub proof: MmrProof<MmrHash>, | ||
} | ||
|
||
// TODO: update upstream `EncodableOpaqueLeaf` to derive clone. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please send a PR upstream right away in such cases: paritytech/polkadot-sdk#5442 |
||
impl<CBlockNumber: Clone, CBlockHash: Clone, MmrHash: Clone> Clone | ||
for ConsensusChainMmrLeafProof<CBlockNumber, CBlockHash, MmrHash> | ||
{ | ||
fn clone(&self) -> Self { | ||
Self { | ||
consensus_block_number: self.consensus_block_number.clone(), | ||
consensus_block_hash: self.consensus_block_hash.clone(), | ||
opaque_mmr_leaf: EncodableOpaqueLeaf(self.opaque_mmr_leaf.0.clone()), | ||
proof: self.proof.clone(), | ||
} | ||
} | ||
} | ||
|
||
/// Trait to verify MMR proofs | ||
pub trait MmrProofVerifier<MmrHash, CBlockNumber, CBlockHash> { | ||
/// Returns consensus state root if the given MMR proof is valid | ||
fn verify_proof_and_extract_consensus_state_root( | ||
mmr_leaf_proof: ConsensusChainMmrLeafProof<CBlockNumber, CBlockHash, MmrHash>, | ||
) -> Option<CBlockHash>; | ||
} | ||
|
||
impl<MmrHash, CBlockNumber, CBlockHash> MmrProofVerifier<MmrHash, CBlockNumber, CBlockHash> for () { | ||
fn verify_proof_and_extract_consensus_state_root( | ||
_mmr_leaf_proof: ConsensusChainMmrLeafProof<CBlockNumber, CBlockHash, MmrHash>, | ||
) -> Option<CBlockHash> { | ||
None | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -23,8 +23,10 @@ use sp_domains::{BundleValidity, DomainId, DomainsApi, ExecutionReceipt, HeaderH | |
use sp_domains_fraud_proof::fraud_proof::{FraudProof, ValidBundleProof}; | ||
use sp_domains_fraud_proof::FraudProofApi; | ||
use sp_messenger::MessengerApi; | ||
use sp_mmr_primitives::MmrApi; | ||
use sp_runtime::traits::{Block as BlockT, Header as HeaderT, NumberFor, One, Zero}; | ||
use sp_runtime::{Digest, Saturating}; | ||
use sp_subspace_mmr::ConsensusChainMmrLeafProof; | ||
use std::cmp::Ordering; | ||
use std::collections::VecDeque; | ||
use std::str::FromStr; | ||
|
@@ -977,6 +979,58 @@ where | |
} | ||
} | ||
|
||
/// Generate MMR proof for the block `to_prove` in the current best fork. The returned proof | ||
/// can be later used to verify stateless (without query offchain MMR leaf) and extract the state | ||
/// root at `to_prove`. | ||
// TODO: remove `dead_code` after it is used in fraud proof generation | ||
#[allow(dead_code)] | ||
pub(crate) fn generate_mmr_proof<CClient, CBlock>( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. will we be using this in the relayer while generating MMR prrofs for XDM ? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We can use this for generating MMR proofs for the consensus XDM, but there are some slight differences between the proof of the consensus chain and the domain chain, so we still need to keep 2 versions of this anyway, I just distinguish them as XDM vs FP instead of consensus vs domain. |
||
consensus_client: &Arc<CClient>, | ||
to_prove: NumberFor<CBlock>, | ||
) -> sp_blockchain::Result<ConsensusChainMmrLeafProof<NumberFor<CBlock>, CBlock::Hash, H256>> | ||
where | ||
CBlock: BlockT, | ||
CClient: HeaderBackend<CBlock> + ProvideRuntimeApi<CBlock> + 'static, | ||
CClient::Api: MmrApi<CBlock, H256, NumberFor<CBlock>>, | ||
{ | ||
let api = consensus_client.runtime_api(); | ||
let prove_at_hash = consensus_client.info().best_hash; | ||
let prove_at_number = consensus_client.info().best_number; | ||
|
||
if to_prove >= prove_at_number { | ||
return Err(sp_blockchain::Error::Application(Box::from(format!( | ||
"Can't generate MMR proof for block {to_prove:?} >= best block {prove_at_number:?}" | ||
)))); | ||
} | ||
|
||
let (mut leaves, proof) = api | ||
// NOTE: the mmr leaf data is added in the next block so to generate the MMR proof of | ||
// block `to_prove` we need to use `to_prove + 1` here. | ||
.generate_proof( | ||
prove_at_hash, | ||
vec![to_prove + One::one()], | ||
Some(prove_at_number), | ||
)? | ||
.map_err(|err| { | ||
sp_blockchain::Error::Application(Box::from(format!( | ||
"Failed to generate MMR proof: {err}" | ||
))) | ||
})?; | ||
debug_assert!(leaves.len() == 1, "should always be of length 1"); | ||
let leaf = leaves | ||
.pop() | ||
.ok_or(sp_blockchain::Error::Application(Box::from( | ||
"Unexpected missing mmr leaf".to_string(), | ||
)))?; | ||
|
||
Ok(ConsensusChainMmrLeafProof { | ||
consensus_block_number: prove_at_number, | ||
consensus_block_hash: prove_at_hash, | ||
opaque_mmr_leaf: leaf, | ||
proof, | ||
}) | ||
} | ||
|
||
#[cfg(test)] | ||
mod tests { | ||
use super::*; | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
maybe we should remove this per our discussion since this is unneeded at this time
cc: @nazar-pc
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note that in case we already deployed runtime with it (IDK) removing corresponding enum variant will be a breaking change.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe this is already deployed to 3h so will leave a TODO for now.