Skip to content
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

Verifying full xcmp proof #136

Merged
merged 12 commits into from
Mar 22, 2024
1 change: 1 addition & 0 deletions Cargo.lock

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

2 changes: 2 additions & 0 deletions pallets/xcmp_message_stuffer/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ sp-core = { workspace = true, default-features = false }
sp-runtime = { workspace = true, default-features = false }
sp-mmr-primitives = { workspace = true }
sp-api = { workspace = true }
binary-merkle-tree = { workspace = true }

# Polkadot
polkadot-runtime-parachains = { workspace = true }
Expand Down Expand Up @@ -56,6 +57,7 @@ runtime-benchmarks = ["frame-benchmarking/runtime-benchmarks"]
std = [
"parity-scale-codec/std",
"polkadot-runtime-parachains/std",
"binary-merkle-tree/std",
"cumulus-pallet-parachain-system/std",
"cumulus-primitives-core/std",
"frame-benchmarking/std",
Expand Down
174 changes: 122 additions & 52 deletions pallets/xcmp_message_stuffer/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,17 @@

pub use pallet::*;
use pallet_mmr::{LeafDataProvider, ParentNumberAndHash, verify_leaves_proof};
use sp_consensus_beefy::mmr::MmrLeafVersion;

use frame_support::{dispatch::{DispatchResult}, pallet_prelude::*, WeakBoundedVec};
use frame_system::pallet_prelude::*;
use cumulus_primitives_core::{ParaId, GetBeefyRoot};
use cumulus_primitives_core::{ParaId, GetBeefyRoot, xcmr_digest::extract_xcmp_channel_merkle_root};
use sp_runtime::traits::{Hash as HashT, Keccak256};
use sp_core::H256;
use polkadot_runtime_parachains::paras::ParaMerkleProof;
use polkadot_runtime_parachains::paras::{ParaMerkleProof, ParaLeaf};
use binary_merkle_tree::Leaf;

use sp_mmr_primitives::{Proof, EncodableOpaqueLeaf, DataOrHash};
use sp_consensus_beefy::mmr::{MmrLeafVersion, MmrLeaf as BeefyMmrLeaf};
use scale_info::prelude::vec::Vec;

#[cfg(test)]
Expand Down Expand Up @@ -55,7 +56,10 @@ impl Default for ChannelMerkleProof {
type XcmpMessages<T, I> = <<T as crate::Config<I>>::XcmpDataProvider as XcmpMessageProvider<<T as frame_system::Config>::Hash>>::XcmpMessages;
type MmrProof = Proof<H256>;
type ChannelId = u64;
<<<<<<< HEAD
=======
type BinaryMerkleProof = ();
>>>>>>> main

#[derive(Debug, PartialEq, Eq, Clone, Encode, Decode, TypeInfo)]
pub struct XcmpProof {
Expand Down Expand Up @@ -119,6 +123,16 @@ pub mod pallet {
XcmpProofLeavesNotValid,
XcmpNoChannelRootForChannelId,
XcmpBeefyRootTargetedNeverSeen,
XcmpStage1LeavesTooLarge,
XcmpStage1ProofDoesntVerify,
XcmpStage2RootDoesntMatch,
XcmpStage2LeafDoesntDecode,
XcmpStage2ProofDoesntVerify,
XcmpStage3HeaderDoesntDecode,
XcmpStage3CannotBeExtracted,
XcmpStage3RootDoesntMatch,
XcmpStage3ProofDoesntVerify,
XcmpStage4ProofDoesntVerify,
}

#[pallet::hooks]
Expand Down Expand Up @@ -184,7 +198,7 @@ pub mod pallet {
}

/// TODO: This is just for testing relayer for now. The root should be updated by checking
/// the relaychain updated XCMPTrie
/// the relaychain updated XCMPTrie remove
#[pallet::call_index(1)]
#[pallet::weight(Weight::from_parts(10_000, 0) + T::DbWeight::get().writes(1))]
pub fn update_root(origin: OriginFor<T>, root: H256, channel_id: u64) -> DispatchResult {
Expand Down Expand Up @@ -225,65 +239,104 @@ pub mod pallet {
.collect();

// TODO: Replace this error with an Error that specifies stage_1 of proof verification failed
verify_leaves_proof(beefy_root_targeted.into(), nodes, stage_1_proof).map_err(|_| Error::<T, I>::XcmpProofNotValid)?;
verify_leaves_proof(beefy_root_targeted.into(), nodes, stage_1_proof).map_err(|_| Error::<T, I>::XcmpStage1ProofDoesntVerify)?;

log::info!(
target: LOG_TARGET,
"Verified Stage 1 Big XCMP Proof Successfully!!!",
"Verified Stage 1 XCMP Proof Successfully!!!",
);

<<<<<<< HEAD
if stage_1_leaves.len() > 1 {
log::error!("stage_1_leaves length too long {}", stage_1_leaves.len());
return Err(Error::<T, I>::XcmpStage1LeavesTooLarge.into())
}
=======
// Verify stage 2..
// grab ParaHeader root from stage_1_proof
// let para_header_root = Decode::decode(stage_1_leaves)
// Take Last leaf element as the para_header_root selected
// let (stage_2_proof, stage_2_leaves) = xcmp_proof.stage_2;
>>>>>>> main

let stage_1_leaf = &stage_1_leaves[0];
let stage_1_leaf = stage_1_leaf.clone().into_opaque_leaf();

let stage_2_leaf: BeefyMmrLeaf<BlockNumberFor<T>, H256, H256, H256> = Decode::decode(&mut &stage_1_leaf.0[..])
.map_err(|e| {
log::error!("COULD NOT DECODE LEAF!! WITH ERROR {:?}", e);
Error::<T, I>::XcmpStage2LeafDoesntDecode
})?;

let stage_2_root_from_proof = xcmp_proof.stage_2.root;
let stage_2_root = stage_2_leaf.leaf_extra;

if stage_2_root != stage_2_root_from_proof {
log::error!("Stage_2 Root no match failed to verify Proof!");
return Err(Error::<T, I>::XcmpStage2RootDoesntMatch.into())
}

let stage_2_result = binary_merkle_tree::verify_proof::<Keccak256, _, _>(
&xcmp_proof.stage_2.root,
xcmp_proof.stage_2.proof,
xcmp_proof.stage_2.num_leaves.try_into().unwrap(),
xcmp_proof.stage_2.leaf_index.try_into().unwrap(),
Leaf::Value(&xcmp_proof.stage_2.leaf.encode()),
);

if !stage_2_result {
log::error!("Stage 2 proof doesnt verify!!!!!!");
return Err(Error::<T, I>::XcmpStage2ProofDoesntVerify.into())
}

log::info!(
target: LOG_TARGET,
"Verified Stage 2 XCMP Proof Successfully!!!",
);

let stage_3_root = Self::extract_xcmp_channel_root(xcmp_proof.stage_2.leaf.clone())?;

if stage_3_root != xcmp_proof.stage_3.root {
log::error!("Stage_3 Root no match failed to verify Proof!");
return Err(Error::<T, I>::XcmpStage3RootDoesntMatch.into())
}

let stage_3_result = binary_merkle_tree::verify_proof::<Keccak256, _, _>(
&xcmp_proof.stage_3.root,
xcmp_proof.stage_3.proof,
xcmp_proof.stage_3.num_leaves.try_into().unwrap(),
xcmp_proof.stage_3.leaf_index.try_into().unwrap(),
&xcmp_proof.stage_3.leaf,
);

if !stage_3_result {
log::error!("Stage 3 proof doesnt verify!!!!!!");
return Err(Error::<T, I>::XcmpStage3ProofDoesntVerify.into())
}

log::info!(
target: LOG_TARGET,
"Verified Stage 3 XCMP Proof Successfully!!!",
);

let stage_4_root = xcmp_proof.stage_3.leaf;

let (stage_4_proof, stage_4_leaves) = xcmp_proof.stage_4;

let nodes: Vec<_> = stage_4_leaves
.clone()
.into_iter()
.map(|leaf|DataOrHash::<Keccak256, _>::Data(leaf.into_opaque_leaf()))
.collect();

verify_leaves_proof(stage_4_root.into(), nodes, stage_4_proof).map_err(|_| Error::<T, I>::XcmpStage4ProofDoesntVerify)?;

// These are different leaves they arent the MmrLeaves they are Binary Merkle Leaves
// This will be a bit different but same rough idea as the Mmr
// let nodes: Vec<_> = stage_2_leaves
// .clone()
// .into_iter()
// .map(|leaf|DataOrHash::<Keccak256, _>::Data(leaf.into_opaque_leaf()))
// .collect();

// binary merkle proof verification of para_header_root against stage_2_proof(leaves are (para_id, para_header))
// verify_proof(root, nodes, stage_2_proof);

// let (para_id, para_header) = Decode::decode(stage_2_leaves);
// Check channels storage to make sure this ParaId is someone that we support
// if !XcmpChannels::<T>::exists(para_id) {
// return Error::<T>::XcmpProofNoChannelWithSender
// }

// Verify stage 3..
// extract xcmp_root from paraheader..
// let xcmp_root = extract(para_header)
// let (stage_3_proof, stage_3_leaves) = xcmp_proof.stage_3;

// These are different leaves they arent the MmrLeaves they are Binary Merkle Leaves
// This will be a bit different but same rough idea as the Mmr
// let nodes: Vec<_> = stage_3_leaves
// .clone()
// .into_iter()
// .map(|leaf|DataOrHash::<Keccak256, _>::Data(leaf.into_opaque_leaf()))
// .collect();

// binary merkle proof verification of xcmp_root against stage_3_proof(mmr_root_from_sender)
// verify_proof(xcmp_root, nodes, stage_3_proof)?;

// Verify stage 4..
// let mmr_root = Decode::decode(stage_3_leaves);
// let (stage_4_proof, stage_4_leaves) = xcmp_proof.stage_4;

// let nodes: Vec<_> = stage_4_leaves
// .clone()
// .into_iter()
// .map(|leaf|DataOrHash::<Keccak256, _>::Data(leaf.into_opaque_leaf()))
// .collect();

// TODO: Replace this error with an Error that specifies stage_4 of proof verification failed
// verify_leaves_proof(mmr_root.into(), nodes, stage_4_proof).map_err(|_| Error::<T, I>::XcmpProofNotValid)?;
log::info!(
target: LOG_TARGET,
"Verified Stage 4 XCMP Proof Successfully!!!",
);

// TODO:
// Now process messages upstream
// let xcmp_messages = Decode::decode(stage_4_leaves);
// Send Xcmp Messages upstream to be decoded to XCM messages and processed
Expand All @@ -297,7 +350,24 @@ pub mod pallet {

}

// TODO: Add Inherent which can update the current `XcmpChannelRoots` against the current BeefyMmrRoot

impl<T: Config<I>, I: 'static> Pallet<T, I> {

fn extract_xcmp_channel_root(leaf: ParaLeaf) -> Result<H256, Error<T,I>> {
// First decode ParaLeaf.head_data into a ParaHeader
let header: sp_runtime::generic::Header<u32, sp_runtime::traits::BlakeTwo256> =
sp_runtime::generic::Header::decode(&mut &leaf.head_data[..])
.map_err(|_e| Error::<T, I>::XcmpStage3HeaderDoesntDecode)?;

log::debug!("EXTRACTED AND DECODED HEADERRR DANKEEEE!!!!!!{:?}", header);

// extracting root from digest
let xcmp_channel_root: H256 = extract_xcmp_channel_merkle_root(&header.digest).ok_or(Error::<T, I>::XcmpStage3CannotBeExtracted)?;

// Extract the XcmpChannelBinaryMerkleRoot from the Digest
Ok(xcmp_channel_root)
}
}

pub struct OnNewRootSatisfier<T>(PhantomData<T>);

Expand Down
Loading