Skip to content

adding in verification of stage 1 and mapping of rest of stages #118

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

Merged
merged 7 commits into from
Feb 22, 2024
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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