Skip to content

Commit

Permalink
adding in verification of stage 1 and mapping of rest of stages (#118)
Browse files Browse the repository at this point in the history
* adding in verification of stage 1 and mapping of rest of stages

* starting proof generation

* constructing part 1 proof subxt issue

* submiting big proof stage1 needs verification now

* closer to generating stage 1 proof

* can now match up roots but proof is not passing

* made beefy map change to fix race issue with proof and root
  • Loading branch information
coax1d authored Feb 22, 2024
1 parent 9840dda commit bf8863a
Show file tree
Hide file tree
Showing 8 changed files with 794 additions and 364 deletions.
714 changes: 373 additions & 341 deletions Cargo.lock

Large diffs are not rendered by default.

5 changes: 3 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ parity-scale-codec = { version = "3.0.0", default-features = false, features = [
parity-util-mem = "0.12.0"
scale-info = { version = "2.2.0", default-features = false, features = ["derive"] }
serde = "1.0"
lazy_static = "1.4"

# Procedural macro dependencies
proc-macro2 = "1.0.67"
Expand Down Expand Up @@ -87,8 +88,8 @@ sp-timestamp = { default_features = false, git = "https://github.com/coax1d/polk
sp-transaction-pool = { default_features = false, git = "https://github.com/coax1d/polkadot-sdk", branch = "xcmp_customized_sdk" }
sp-version = { default-features = false, git = "https://github.com/coax1d/polkadot-sdk", branch = "xcmp_customized_sdk" }

subxt = { git = 'https://github.com/paritytech/subxt', branch = "master" }
subxt-signer = { git = 'https://github.com/paritytech/subxt', branch = "master", features = ["subxt"] }
subxt = { git = 'https://github.com/paritytech/subxt', rev = "d44941fb1bdb1b46ef8537dd7511654facc3f763" }
subxt-signer = { git = 'https://github.com/paritytech/subxt', rev = "d44941fb1bdb1b46ef8537dd7511654facc3f763", features = ["subxt"] }

# Node Deps
frame-benchmarking-cli = { git = "https://github.com/coax1d/polkadot-sdk", branch = "xcmp_customized_sdk" }
Expand Down
1 change: 1 addition & 0 deletions pallets/xcmp_message_stuffer/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ sp-consensus-beefy = { workspace = true, default-features = false }
sp-core = { workspace = true, default-features = false }
sp-runtime = { workspace = true, default-features = false }
sp-mmr-primitives = { workspace = true }
sp-api = { workspace = true }

# Cumulus
cumulus-primitives-core = { workspace = true, default-features = false }
Expand Down
139 changes: 136 additions & 3 deletions pallets/xcmp_message_stuffer/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ pub use pallet::*;
use pallet_mmr::{LeafDataProvider, ParentNumberAndHash, verify_leaves_proof};
use sp_consensus_beefy::mmr::MmrLeafVersion;

use frame_support::{dispatch::{DispatchResult}, pallet_prelude::*,};
use frame_support::{dispatch::{DispatchResult}, pallet_prelude::*, WeakBoundedVec};
use frame_system::pallet_prelude::*;
use cumulus_primitives_core::{ParaId, GetBeefyRoot};
use sp_runtime::traits::{Hash as HashT, Keccak256};
Expand Down Expand Up @@ -34,6 +34,18 @@ type XcmpMessages<T, I> = <<T as crate::Config<I>>::XcmpDataProvider as XcmpMess
type MmrProof = Proof<H256>;
type LeafOf<T, I> = <crate::Pallet<T, I> as LeafDataProvider>::LeafData;
type ChannelId = u64;
type BinaryMerkleProof = ();


#[derive(Debug, PartialEq, Eq, Clone, Encode, Decode, TypeInfo)]
pub struct XcmpProof {
// TODO: Probably should rename each of these stages to some fancy name
// TODO: Remove tuples
pub stage_1: (MmrProof, Vec<EncodableOpaqueLeaf>),
pub stage_2: BinaryMerkleProof,
pub stage_3: BinaryMerkleProof,
pub stage_4: (MmrProof, Vec<EncodableOpaqueLeaf>),
}

#[frame_support::pallet]
pub mod pallet {
Expand All @@ -48,6 +60,7 @@ pub mod pallet {
type RelayerOrigin: EnsureOrigin<Self::RuntimeOrigin>;
/// This is used when updating the current `XcmpChannelRoots`
type BeefyRootProvider: GetBeefyRoot;
type MaxBeefyRootsKept: Get<u32>;
}

#[pallet::pallet]
Expand All @@ -58,6 +71,14 @@ pub mod pallet {
#[pallet::getter(fn xcmp_channel_roots)]
pub type XcmpChannelRoots<T: Config<I>, I: 'static = ()> = StorageMap<_, Identity, ChannelId, H256, OptionQuery>;

#[pallet::storage]
#[pallet::getter(fn seen_beefy_roots)]
pub type SeenBeefyRoots<T: Config<I>, I: 'static = ()> = StorageMap<_, Identity, H256, BlockNumberFor<T>, OptionQuery>;

#[pallet::storage]
#[pallet::getter(fn seen_beefy_roots_order)]
pub type SeenBeefyRootsOrder<T: Config<I>, I: 'static = ()> = StorageValue<_, WeakBoundedVec<H256, T::MaxBeefyRootsKept>, ValueQuery>;

#[pallet::event]
#[pallet::generate_deposit(pub(super) fn deposit_event)]
pub enum Event<T: Config<I>, I: 'static = ()> {
Expand All @@ -77,13 +98,30 @@ pub mod pallet {
XcmpProofAccepted,
XcmpProofLeavesNotValid,
XcmpNoChannelRootForChannelId,
XcmpBeefyRootTargetedNeverSeen,
}

#[pallet::hooks]
impl<T: Config<I>, I: 'static> Hooks<BlockNumberFor<T>> for Pallet<T, I> {
fn on_initialize(n: BlockNumberFor<T>) -> Weight {
// TODO: Remove Temporary.. change from unwrapping default..
let beefy_root = T::BeefyRootProvider::get_root().unwrap_or_default();
SeenBeefyRoots::<T, I>::insert(&beefy_root.clone().into(), n);

let mut order = SeenBeefyRootsOrder::<T, I>::get().into_inner();
order.push(beefy_root.into());

let item = WeakBoundedVec::force_from(order, None);
SeenBeefyRootsOrder::<T, I>::put(item);

T::DbWeight::get().writes(3)
}
}

#[pallet::call]
impl<T: Config<I>, I: 'static> Pallet<T, I> {

// TODO: Retrieve latest valid MmrChannelRoots from Relaychain (Perhaps this is done in on_initialize)

// TODO: This will
#[pallet::call_index(0)]
#[pallet::weight(Weight::from_parts(10_000, 0) + T::DbWeight::get().writes(1))]
pub fn submit_xcmp_proof(origin: OriginFor<T>, mmr_proof: MmrProof, leaves: Vec<EncodableOpaqueLeaf>, channel_id: u64) -> DispatchResult {
Expand Down Expand Up @@ -140,6 +178,101 @@ pub mod pallet {
);
Ok(())
}

/// For now there is just one leaf in each membership proof
/// TODO: Change to support multiple leaves..
#[pallet::call_index(2)]
#[pallet::weight(Weight::from_parts(10_000, 0) + T::DbWeight::get().writes(1))]
pub fn submit_big_proof(origin: OriginFor<T>, xcmp_proof: XcmpProof, beefy_root_targeted: H256) -> DispatchResult {
ensure_signed(origin)?;

log::info!(
target: LOG_TARGET,
"Called submit big proof, targeting BEEFY_ROOT {:?}",
beefy_root_targeted
);

if !SeenBeefyRoots::<T, I>::contains_key(&beefy_root_targeted) {
return Err(Error::<T, I>::XcmpBeefyRootTargetedNeverSeen.into())
}

// Verify stage 1 via grabbing Beefy Root and checking against stage 1
let (stage_1_proof, stage_1_leaves) = xcmp_proof.stage_1;

let nodes: Vec<_> = stage_1_leaves
.clone()
.into_iter()
.map(|leaf|DataOrHash::<Keccak256, _>::Data(leaf.into_opaque_leaf()))
.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)?;

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

// Verify stage 2..
// grab ParaHeader root from stage_1_proof
// let para_header_root = Decode::decode(stage_1_leaves)
// let (stage_2_proof, stage_2_leaves) = xcmp_proof.stage_2;

// 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)?;

// Now process messages upstream
// let xcmp_messages = Decode::decode(stage_4_leaves);
// Send Xcmp Messages upstream to be decoded to XCM messages and processed
// T::ProcessXcmpMessages(xcmp_messages);

// Log Event..

Ok(())
}
}

}
Expand Down
13 changes: 12 additions & 1 deletion runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ mod weights;
pub mod xcm_config;

use cumulus_primitives_core::{
ParaId, CollectXcmpChannelMmrRoots,
ParaId, CollectXcmpChannelMmrRoots, GetBeefyRoot
};
use sp_core::Hasher;

Expand Down Expand Up @@ -523,6 +523,7 @@ parameter_types! {
pub LeafVersion: MmrLeafVersion = MmrLeafVersion::new(0, 0);

pub ParaAIdentifier: ParaId = ParaId::from(1u32);
pub MaxBeefyRootsKept: u32 = 64000u32;
}

type ParaAChannel = pallet_xcmp_message_stuffer::Instance1;
Expand All @@ -533,6 +534,7 @@ impl pallet_xcmp_message_stuffer::Config<ParaAChannel> for Runtime {
type XcmpDataProvider = XcmpDataProvider;
type RelayerOrigin = EnsureRoot<AccountId>;
type BeefyRootProvider = ParachainSystem;
type MaxBeefyRootsKept = MaxBeefyRootsKept;
}

type ParaAMmr = pallet_mmr::Instance1;
Expand All @@ -556,6 +558,7 @@ impl pallet_xcmp_message_stuffer::Config<ParaBChannel> for Runtime {
type XcmpDataProvider = XcmpDataProvider;
type RelayerOrigin = EnsureRoot<AccountId>;
type BeefyRootProvider = ParachainSystem;
type MaxBeefyRootsKept = MaxBeefyRootsKept;
}

type ParaBMmr = pallet_mmr::Instance2;
Expand Down Expand Up @@ -724,6 +727,14 @@ impl_runtime_apis! {
}
}

impl cumulus_pallet_parachain_system::MessagingApi<Block, ParachainSystem> for Runtime {
fn get_current_beefy_root() -> <ParachainSystem as GetBeefyRoot>::Root {
// TODO: For now if there is no root just return H256::zero() Remove! for better error handling
<ParachainSystem as GetBeefyRoot>::get_root().unwrap_or(
sp_core::H256::from(&[1; 32]))
}
}

#[api_version(3)]
impl mmr::MmrApi<Block, mmr::Hash, BlockNumber> for Runtime {
fn mmr_root(mmr_id: u64) -> Result<mmr::Hash, mmr::Error> {
Expand Down
3 changes: 2 additions & 1 deletion xcmp_relayer/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ license = "Apache-2.0"
description = "Relayer for XCMP"

[dependencies]
runtime = { path = "../runtime", package = "parachain-template-runtime"}
runtime = { path = "../runtime", package = "parachain-template-runtime" }

serde_json = { workspace = true }
parity-scale-codec = { workspace = true }
Expand All @@ -20,6 +20,7 @@ directories = { workspace = true }
futures = { workspace = true }
env_logger = { workspace = true }
log = { workspace = true }
lazy_static = { workspace = true }

sp-runtime = { workspace = true }
sp-core = { workspace = true }
Expand Down
Loading

0 comments on commit bf8863a

Please sign in to comment.