diff --git a/Cargo.lock b/Cargo.lock index 333bc75..c269cf3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -14613,6 +14613,7 @@ name = "xcmp_relayer" version = "0.1.0" dependencies = [ "anyhow", + "cumulus-primitives-core", "directories 5.0.1", "env_logger 0.10.2", "futures", @@ -14627,6 +14628,7 @@ dependencies = [ "polkadot-parachain-primitives", "polkadot-runtime-parachains", "serde_json", + "sp-consensus-beefy", "sp-core", "sp-mmr-primitives", "sp-runtime", diff --git a/pallets/xcmp_message_stuffer/src/lib.rs b/pallets/xcmp_message_stuffer/src/lib.rs index d05be55..5d48323 100644 --- a/pallets/xcmp_message_stuffer/src/lib.rs +++ b/pallets/xcmp_message_stuffer/src/lib.rs @@ -31,19 +31,39 @@ pub trait XcmpMessageProvider { fn get_xcmp_messages(block_hash: Hash, para_id: ParaId) -> Self::XcmpMessages; } +#[derive(Debug, PartialEq, Eq, Clone, Encode, Decode, TypeInfo)] +pub struct ChannelMerkleProof { + pub root: H256, + pub proof: Vec, + pub num_leaves: u64, + pub leaf_index: u64, + pub leaf: H256, +} + +impl Default for ChannelMerkleProof { + fn default() -> Self { + ChannelMerkleProof { + root: H256::zero(), + proof: Vec::new(), + num_leaves: 0u64, + leaf_index: 0u64, + leaf: H256::zero(), + } + } +} + type XcmpMessages = <>::XcmpDataProvider as XcmpMessageProvider<::Hash>>::XcmpMessages; type MmrProof = Proof; 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), pub stage_2: ParaMerkleProof, - pub stage_3: BinaryMerkleProof, + pub stage_3: ChannelMerkleProof, pub stage_4: (MmrProof, Vec), } @@ -121,7 +141,6 @@ pub mod pallet { #[pallet::call] impl, I: 'static> Pallet { - // TODO: This will #[pallet::call_index(0)] #[pallet::weight(Weight::from_parts(10_000, 0) + T::DbWeight::get().writes(1))] pub fn submit_test_proof(origin: OriginFor, mmr_proof: MmrProof, leaves: Vec, channel_id: u64) -> DispatchResult { @@ -216,6 +235,7 @@ pub mod pallet { // 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; // These are different leaves they arent the MmrLeaves they are Binary Merkle Leaves @@ -306,4 +326,13 @@ impl, I: 'static> LeafDataProvider for Pallet { parent_number_and_hash: ParentNumberAndHash::::leaf_data(), } } +} + +sp_api::decl_runtime_apis! { + /// API useful for BEEFY light clients. + pub trait ChannelMerkleApi + { + /// Return BinaryMerkle Proof for a particular parachains inclusion in ParaHeader tree + fn get_xcmp_channels_proof(channel_id: u64) -> Option; + } } \ No newline at end of file diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs index 12ce62a..91b764e 100644 --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -27,7 +27,9 @@ use sp_runtime::{ use sp_consensus_beefy::mmr::MmrLeafVersion; -use parity_scale_codec::Encode; +use parity_scale_codec::{Encode, Decode}; + +use polkadot_runtime_parachains::paras::{ParaMerkleProof, ParaLeaf}; use sp_std::prelude::*; #[cfg(feature = "std")] @@ -505,6 +507,28 @@ impl CollectXcmpChannelMmrRoots for XcmpChannelRootCollector { } } +use pallet_xcmp_message_stuffer::ChannelMerkleProof; +pub struct ChannelMerkleProofGen; +impl ChannelMerkleProofGen { + // TODO: Allow the channel_id to select the appropriate MMR and index of leaf + pub fn gen_merkle_proof(_channel_id: u64) -> Option { + let index_to_prove = 0; + + let merkle_proof = binary_merkle_tree::merkle_proof::( + vec![MmrParaA::mmr_root_hash(), MmrParaB::mmr_root_hash()], + index_to_prove + ); + let result_proof = ChannelMerkleProof { + root: merkle_proof.root, + proof: merkle_proof.proof, + num_leaves: merkle_proof.number_of_leaves as u64, + leaf_index: merkle_proof.leaf_index as u64, + leaf: merkle_proof.leaf, + }; + Some(result_proof) + } +} + parameter_types! { /// Version of the produced MMR leaf. @@ -735,6 +759,12 @@ impl_runtime_apis! { } } + impl pallet_xcmp_message_stuffer::ChannelMerkleApi for Runtime { + fn get_xcmp_channels_proof(channel_id: u64) -> Option { + ChannelMerkleProofGen::gen_merkle_proof(channel_id) + } + } + #[api_version(3)] impl mmr::MmrApi for Runtime { fn mmr_root(mmr_id: u64) -> Result { diff --git a/xcmp_relayer/Cargo.toml b/xcmp_relayer/Cargo.toml index 18e7d86..d4e311f 100644 --- a/xcmp_relayer/Cargo.toml +++ b/xcmp_relayer/Cargo.toml @@ -11,6 +11,7 @@ runtime = { path = "../runtime", package = "parachain-template-runtime" } polkadot-runtime-parachains = { workspace = true } polkadot-parachain = { workspace = true } +cumulus-primitives-core = { workspace = true } serde_json = { workspace = true } parity-scale-codec = { workspace = true } jsonrpsee = { workspace = true } @@ -27,6 +28,7 @@ lazy_static = { workspace = true } sp-runtime = { workspace = true } sp-core = { workspace = true } sp-mmr-primitives = { workspace = true } +sp-consensus-beefy = { workspace = true } subxt = { workspace = true } subxt-signer = { workspace = true } diff --git a/xcmp_relayer/src/main.rs b/xcmp_relayer/src/main.rs index 7b03d99..c159def 100644 --- a/xcmp_relayer/src/main.rs +++ b/xcmp_relayer/src/main.rs @@ -3,12 +3,13 @@ use jsonrpsee::{ http_client::{HttpClient, HttpClientBuilder}, rpc_params, }; -use parity_scale_codec::Decode; -use runtime::{BlockNumber, Hash, Header}; +use parity_scale_codec::{Encode, Decode}; +use cumulus_primitives_core::xcmr_digest::extract_xcmp_channel_merkle_root; +use runtime::{pallet_xcmp_message_stuffer::ChannelMerkleProof, BlockNumber, Hash, Header}; +use sp_mmr_primitives::EncodableOpaqueLeaf; +use sp_consensus_beefy::mmr::{MmrLeafVersion, MmrLeaf}; use std::{ - collections::BTreeMap, - sync::Mutex, - time::Duration, + collections::BTreeMap, ops::Sub, sync::Mutex, time::Duration }; use lazy_static::lazy_static; @@ -30,7 +31,7 @@ pub mod polkadot { } pub mod relay { } use relay::runtime_types::polkadot_runtime_parachains::paras::{ - ParaMerkleProof as RelayParaMerkleProof, ParaLeaf as RelayParaLeaf, + ParaMerkleProof as RelayParaMerkleProof, ParaLeaf as RelayParaLeaf }; use relay::runtime_types::polkadot_parachain_primitives::primitives::Id as ParaId; @@ -39,7 +40,8 @@ use polkadot::runtime_types::{ pallet_xcmp_message_stuffer::XcmpProof, sp_mmr_primitives::Proof as XcmpProofType, polkadot_runtime_parachains::paras::{ParaMerkleProof, ParaLeaf}, - polkadot_parachain_primitives::primitives::Id as ParachainParaId + polkadot_parachain_primitives::primitives::Id as ParachainParaId, + pallet_xcmp_message_stuffer::ChannelMerkleProof as SubxtChannelMerkleProof, }; /// The default endpoints for each @@ -50,6 +52,8 @@ const DEFAULT_RPC_ENDPOINT_PARA_RECEIVER: &str = "http://localhost:54887"; const DEFAULT_ENDPOINT_RELAY: &str = "ws://localhost:54886"; const DEFAULT_RPC_ENDPOINT_RELAY: &str = "http://localhost:54886"; +const RECEIVER_CHANNEL_ID: u64 = 0; + #[derive(Clone, Debug)] pub struct MultiClient { pub subxt_client: OnlineClient, @@ -89,6 +93,30 @@ impl ClientType { } } +impl From for ChannelMerkleProof { + fn from(x: SubxtChannelMerkleProof) -> Self { + Self { + root: x.root, + proof: x.proof, + num_leaves: x.num_leaves, + leaf_index: x.leaf_index, + leaf: x.leaf + } + } +} + +impl From for SubxtChannelMerkleProof { + fn from(x: ChannelMerkleProof) -> Self { + Self { + root: x.root, + proof: x.proof, + num_leaves: x.num_leaves, + leaf_index: x.leaf_index, + leaf: x.leaf + } + } +} + impl From for ParaMerkleProof { fn from(x: RelayParaMerkleProof) -> Self { Self { @@ -128,6 +156,18 @@ impl Clone for RelayParaMerkleProof { } } +impl Clone for SubxtChannelMerkleProof { + fn clone(&self) -> Self { + Self { + root: self.root.clone(), + proof: self.proof.clone(), + num_leaves: self.num_leaves.clone(), + leaf_index: self.leaf_index.clone(), + leaf: self.leaf.clone(), + } + } +} + impl Clone for ParaId { fn clone(&self) -> Self { Self(self.0) @@ -147,8 +187,12 @@ type BeefyMmrRoot = H256; type RelayBlockIndex = u32; lazy_static! { - static ref BEEFY_MMR_MAP: Mutex)>> = Mutex::new(BTreeMap::new()); + // Mapping (ParaHeaderRoot, RelayBlockNum) -> (BeefyMmrRoot, Proof) + static ref LEAVES_BEEFY_MMR_MAP: Mutex)>> = Mutex::new(BTreeMap::new()); static ref PARA_HEADERS_MAP: Mutex> = Mutex::new(BTreeMap::new()); + static ref MSG_ROOT_MAP: Mutex>> = Mutex::new(BTreeMap::new()); + static ref MSG_ROOT_CHANNEL_MERKLE_MAP: Mutex> = Mutex::new(BTreeMap::new()); + static ref CHANNEL_ROOT_PROOF_MAP: Mutex> = Mutex::new(BTreeMap::new()); } #[tokio::main] @@ -161,23 +205,13 @@ async fn main() -> anyhow::Result<()> { let para_receiver_api = MultiClient::new(DEFAULT_ENDPOINT_PARA_RECEIVER, DEFAULT_RPC_ENDPOINT_PARA_RECEIVER).await?; let relay_api = MultiClient::new(DEFAULT_ENDPOINT_RELAY, DEFAULT_RPC_ENDPOINT_RELAY).await?; - // 1.) Collect all Beefy Mmr Roots from Relaychain into a HashMap (BeefyMmrRoot -> Relaychain Block number) - // Collect all ParaHeaders from sender in order to generate opening in - // 2.) ParaHeader Merkle tree (ParaId, ParaHeader(As HeadData)) let _ = collect_relay_data(&relay_api).await?; - - // TODO: Create mapping between Parablock Num -> Vec of all channel Mmr Roots for sender - // Keep track of Mmr Index which correspondings to the receiver.. - // let _ = collect_all_mmr_roots_for_sender(&sender_api).await?; - - // TODO: Add this as a RuntimeApi for generating this from the Relaychain directly - // since data is stored there and proof can easily be generated from Validator - // Then just Relay this over to receiver correctly in stage 2 of proof - // How to convert ParaHeader -> HeadData? Just encode the header as bytes?? + let _ = collect_para_data(¶_sender_api).await?; let _ = log_all_mmr_roots(¶_sender_api).await?; let _ = log_all_mmr_proofs(¶_sender_api).await?; - let _ = get_proof_and_verify(¶_sender_api, &relay_api).await?; + + let _ = get_proof_and_verify(¶_sender_api, &relay_api, ¶_receiver_api).await?; let _subscribe = log_all_blocks(&vec![para_sender_api, para_receiver_api, relay_api]).await?; @@ -205,12 +239,10 @@ async fn collect_relay_data(client: &MultiClient) -> anyhow::Result<()> { } }; - // let request: Option = client.rpc_client.request("mmr_root", params).await?; log::debug!("After relay beefy root request"); let root = request.ok_or(RelayerError::Default)?; log::debug!("Got Current Beefy Root from Relaychain {:?}", root); - // let request: Option = client.rpc_client.request("chain_getBlock", rpc_params![Option::::None]).await?; let request: Option
= match client.rpc_client.request("chain_getHeader", rpc_params![Option::::None]).await { Ok(block) => { block @@ -220,7 +252,7 @@ async fn collect_relay_data(client: &MultiClient) -> anyhow::Result<()> { None } }; - log::info!("After chain block request"); + log::debug!("After chain block request"); let rpc_header = request.ok_or(RelayerError::Default)?; if rpc_header.number != block.number() { log::error!( @@ -230,7 +262,7 @@ async fn collect_relay_data(client: &MultiClient) -> anyhow::Result<()> { ); } - let proof = try_generate_mmr_proof(&client, block.number().into(), Some(0u64)) + let proof = generate_mmr_proof(&client, block.number().into(), Some(RECEIVER_CHANNEL_ID), Some(block.hash())) .await .map_err(|e| { log::error!("Failed to generate big proof from Relaychain with error {:?}", e); @@ -238,16 +270,36 @@ async fn collect_relay_data(client: &MultiClient) -> anyhow::Result<()> { } )?; - match BEEFY_MMR_MAP.try_lock() { + // Decode Beefy proof leaves into MmrLeaf type get ParaHeaderRoot from extra_data field + // First go from EncodableOpaqueLeaf -> OpaqueLeaf -> MmrLeaf + let beefy_leaves: Vec = Decode::decode(&mut &proof.leaves.0[..]) + .map_err(|e| anyhow::Error::new(e))?; + + // Search through each leaf for the para_header_root from extra_data field + // the element should be one leaf since we only request leaves proof for one blocknum + if beefy_leaves.len() > 1 { + log::error!("Beefy leaves are greater than 1!!!!! issue storing"); + } + + let leaf = &beefy_leaves[0]; + let leaf = leaf.clone().into_opaque_leaf(); + + let mmr_leaf: MmrLeaf = Decode::decode(&mut &leaf.0[..]) + .map_err(|e| { + log::error!("COULD NOT DECODE LEAF!! WITH ERROR {:?}", e); + anyhow::Error::new(e) + })?; + + // Store as (ParaHeaderRoot, RelayBlockNum) -> (BeefyMmrRoot, Proof) + match LEAVES_BEEFY_MMR_MAP.try_lock() { Ok(mut s) => { - s.insert(root.clone(), (block.number(), proof)); log::debug!( - "Inserting into storage Beefy root {:?}, for relay block number {}", - root, - block.number() - ) + "Inserting into storage LEAVES_BEEFY_MMR_MAP for MMR_LEAF {:?}", + mmr_leaf + ); + s.insert((mmr_leaf.leaf_extra, block.number()), (root.clone(), proof.clone())); }, - Err(_) => log::error!("Could not lock BEEFY_MMR_MAP for writing") + Err(_) => log::error!("Could not lock LEAVES_BEEFY_MMR_MAP for writing") } let id = ParaId(1000u32); @@ -255,8 +307,7 @@ async fn collect_relay_data(client: &MultiClient) -> anyhow::Result<()> { let para_merkle_call = relay::apis().paras_api().get_para_heads_proof(id); let para_merkle_proof = match client.subxt_client .runtime_api() - .at_latest() - .await? + .at(block.reference()) .call(para_merkle_call) .await { Ok(opt_proof) => { @@ -273,6 +324,23 @@ async fn collect_relay_data(client: &MultiClient) -> anyhow::Result<()> { RelayerError::Default })?; + let para_header_root = match extract_xcmp_channel_root(para_merkle_proof.leaf.clone().into()).await { + Ok(root) => { + log::debug!("Can decode extract root from Header Digest XcmpChannelRoot is {:?}", root); + root + }, + Err(_) => { + log::error!("COULD not extract Digest IN EXTRACT function!!!"); + H256::zero() + } + }; + + if para_header_root == H256::zero() { + log::error!("ParaHeader root not extracted zero H256 value"); + return Err(RelayerError::Default.into()) + } + + // Now have the `para_header_root` which will be a leaf in the Beefy Mmr match PARA_HEADERS_MAP.try_lock() { Ok(mut s) => { log::debug!( @@ -280,7 +348,7 @@ async fn collect_relay_data(client: &MultiClient) -> anyhow::Result<()> { block.number(), para_merkle_proof.clone() ); - s.insert(root, para_merkle_proof.clone()); + s.insert(para_header_root, para_merkle_proof.clone()); }, Err(_) => log::error!("Could not lock PARA_HEADERS_MAP for writing") } @@ -293,82 +361,284 @@ async fn collect_relay_data(client: &MultiClient) -> anyhow::Result<()> { Ok(()) } -async fn generate_stage_xcmp_proof(client: &MultiClient, _relay_client: &MultiClient) -> anyhow::Result<()> { + + +async fn extract_xcmp_channel_root(leaf: ParaLeaf) -> anyhow::Result { + // First decode ParaLeaf.head_data into a ParaHeader + let header = Header::decode(&mut &leaf.head_data[..])?; + + 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(RelayerError::Default)?; + + // Extract the XcmpChannelBinaryMerkleRoot from the Digest + Ok(xcmp_channel_root) +} + +#[tokio::test] +async fn test_decode() { + let header = Header { + parent_hash: H256::zero(), + state_root: H256::zero(), + extrinsics_root: H256::zero(), + number: 0u32, + digest: Default::default(), + }; + let dummy_input = ParaLeaf { para_id: ParaId(1000).into(), head_data: header.encode() }; + let result = extract_xcmp_channel_root(dummy_input).await; + assert!(result.is_ok()); + assert_eq!(result.unwrap(), H256::zero()); +} + +async fn collect_para_data(client: &MultiClient) -> anyhow::Result<()> { + let client = client.clone(); + task::spawn(async move { + let mut blocks_sub = client.subxt_client.blocks().subscribe_best().await?; + while let Some(block) = blocks_sub.next().await { + let block = block?; + + let msg_root = generate_mmr_root(&client, Some(RECEIVER_CHANNEL_ID), Some(block.hash())).await?; + let msg_proof = generate_mmr_proof(&client, block.number().into(), Some(RECEIVER_CHANNEL_ID), Some(block.hash())).await?; + + match MSG_ROOT_MAP.try_lock() { + Ok(mut s) => { + s.insert(msg_root.clone(), msg_proof); + log::debug!( + "Inserting into storage Msg root {:?}", + msg_root + ); + }, + Err(_) => log::error!("Could not lock MSG_ROOT_MAP for writing") + } + + let channels_merkle_call = polkadot::apis().channel_merkle_api().get_xcmp_channels_proof(RECEIVER_CHANNEL_ID); + let channel_merkle_proof = match client.subxt_client + .runtime_api() + .at(block.reference()) + .call(channels_merkle_call) + .await { + Ok(proof) => { + log::debug!("Got channels merkle proof from 'get_xcmp_channels_proof' {:?}", proof); + proof + }, + Err(e) => { + log::debug!("Got error from trying to call `get_xcmp_channels_proof` {:?}", e); + None + } + }.ok_or_else(|| { + log::error!("error in generating stage 3 of proof exited generate_xcmp_proof"); + RelayerError::Default + })?; + + // For grabbing the channel merkle proofs by their respective root later + match CHANNEL_ROOT_PROOF_MAP.try_lock() { + Ok(mut s) => { + s.insert(channel_merkle_proof.root, channel_merkle_proof.clone().into()); + }, + Err(_) => { + log::error!("Could not lock Channel ROOT Proof MAP for writing") + } + } + + let roots_match = match MSG_ROOT_MAP.try_lock() { + Ok(mut s) => { + if s.contains_key(&channel_merkle_proof.leaf.clone()) { + true + } + else { + false + } + } + Err(_) => { + log::error!("Could not lock MSG_ROOT_MAP for writing"); + false + } + }; + + if !roots_match { + log::error!("Roots dont match between msg_mmr_root and channel_merkle_root!!@£!@£"); + continue; + } + + match MSG_ROOT_CHANNEL_MERKLE_MAP.try_lock() { + Ok(mut s) => { + s.insert(msg_root.clone(), channel_merkle_proof.into()); + log::debug!( + "Inserting into storage msg_root for channel_merkle_proof {:?}", + msg_root + ); + }, + Err(_) => log::error!("Could not lock MSG_ROOT_CHANNEL_MERKLE_MAP for writing") + } + + } + Ok::<(), anyhow::Error>(()) + }); + Ok(()) +} + +// TODO: Add documentation for this function and add helper functions for each step to make it smaller and +// easier to digest +async fn generate_xcmp_proof(client: &MultiClient, _relay_client: &MultiClient, recv_client: &MultiClient) -> anyhow::Result<()> { log::info!("Entered generate xcmp proof"); let client = client.clone(); - // 1.) For each para block on receiver get the current Beefy Root on chain via RPC or subxt - let beefy_api_call = polkadot::apis().messaging_api().get_current_beefy_root(); - let beefy_root = match client.subxt_client - .runtime_api() - .at_latest() - .await? - .call(beefy_api_call) - .await { - Ok(root) => { - log::info!("Got root from `get_current_beefy_root` {:?}", root); - root + let recv_client = recv_client.clone(); + + let block = client.subxt_client.blocks().at_latest().await?; + + let (stage_4_root, stage_4_proof) = match MSG_ROOT_MAP.try_lock() { + Ok(s) => { + s.iter().next().map(|(key, value)| (key.clone(), value.clone())) + }, + Err(_) => { + log::error!("Could not lock MSG_ROOT_MAP for reading"); + None + } + }.ok_or_else(|| { + log::error!("Could not read stage_4_root and stage_4_proof from MSG_ROOT_MAP"); + RelayerError::Default + } + )?; + + let roots_match = match MSG_ROOT_CHANNEL_MERKLE_MAP.try_lock() { + Ok(s) => { + if s.contains_key(&stage_4_root) { + true + } + else { + false + } + } + Err(_) => { + log::error!("Could not lock MSG_ROOT_CHANNEL_MERKLE_MAP for writing"); + false + } + }; + + if !roots_match { + log::error!("Stage 4 root doesnt exist yet for stage 3 generation proof generation failed.."); + match MSG_ROOT_CHANNEL_MERKLE_MAP.lock() { + Ok(s) => { + log::error!("Couldnt find stage_4_root: {:?}, in MSG_ROOT_CHANNEL_MERKLE_MAP {:?}", stage_4_root, s); }, Err(e) => { - log::info!("Got error from trying to call `get_current_beefy_root` {:?}", e); - H256::zero() + log::error!("Could not lock MSG_ROOT_CHANNEL_MERKLE_MAP for PRINTING") } - }; - log::info!("Beefy Root obtained in generate_stage_xcmp_proof: {:?}", beefy_root); + } + return Err(RelayerError::Default.into()) + } + + let stage_4_leaves = Decode::decode(&mut &stage_4_proof.leaves.0[..]) + .map_err(|e| anyhow::Error::new(e))?; + let stage_4_decoded_proof: XcmpProofType = Decode::decode(&mut &stage_4_proof.proof.0[..]) + .map_err(|e| anyhow::Error::new(e))?; + - // 2.) Then call RPC to generate mmr_proof for Relay block number corresponding to this Beefy Root - let (relay_block_num, proof) = match BEEFY_MMR_MAP.try_lock() { + let stage_3_proof = match MSG_ROOT_CHANNEL_MERKLE_MAP.try_lock() { Ok(s) => { - s.get(&beefy_root).cloned() + s.get(&stage_4_root).cloned() }, Err(_) => { - log::info!("Could not lock BEEFY_MMR_MAP for reading"); + log::error!("Could not lock MSG_ROOT_CHANNEL_MERKLE_MAP for reading"); None } }.ok_or_else(|| { - log::info!("Could not read relay_block_num and proof from BEEFY_MMR_MAP"); + log::error!("Could not read stage_3_root and stage_3_proof from MSG_ROOT_CHANNEL_MERKLE_MAP"); RelayerError::Default } )?; - let merkle_proof = match PARA_HEADERS_MAP.try_lock() { + let stage_2_proof = match PARA_HEADERS_MAP.try_lock() { Ok(s) => { - s.get(&beefy_root).cloned() + s.get(&stage_3_proof.root.clone()).cloned() }, Err(_) => { - log::info!("Could not lock PARA_HEADERS_MAP for reading"); + log::error!("Could not lock PARA_HEADERS_MAP for reading"); + None + }, + }.ok_or_else(|| { + log::error!("Could not read stage_2_root and stage_2 proof from PARA_HEADERS_MAP for stage 3 root {:?}", stage_3_proof.leaf); + RelayerError::Default + })?; + + // Lookup in `LEAVES_BEEFY_MMR_MAP` all values for keys (state_2_proof.root, _) collect into a vec + // Log size of this + // If size is 1 then place the proof and root into the stage_1 proof if not log error and take last entry + let beefy_entries = match LEAVES_BEEFY_MMR_MAP.try_lock() { + Ok(mut s) => { + s.iter() + .filter(|((root, _), _)| *root == stage_2_proof.root) + .map(|(_, value)| value.clone()) + .collect::>() + }, + Err(_) => { + log::error!("Could not lock PARA_HEADERS_MAP for reading"); + Vec::new() + } + }; + + if beefy_entries.is_empty() { + log::error!("Beefy entries vec is empty.. issue with LOCK or lookup!"); + return Err(RelayerError::Default.into()) + } + + if beefy_entries.len() > 1 { + log::error!("Multiple Beefy Entries for same para_header_root taking the last!!!"); + } + + let stage_1_beefy_root = &beefy_entries[beefy_entries.len() - 1].0; + let stage_1_proof = &beefy_entries[beefy_entries.len() - 1].1; + + let stage_1_leaves = Decode::decode(&mut &stage_1_proof.leaves.0[..]) + .map_err(|e| anyhow::Error::new(e))?; + let stage_1_decoded_proof: XcmpProofType = Decode::decode(&mut &stage_1_proof.proof.0[..]) + .map_err(|e| anyhow::Error::new(e))?; + + match MSG_ROOT_MAP.try_lock() { + Ok(mut s) => { + s.remove(&stage_4_root) + }, + Err(_) => { + log::error!("Could not lock MSG_ROOT_MAP for reading"); None } }.ok_or_else(|| { - log::info!("Could not read proof from PARA_HEADERS_MAP"); + log::error!("Could not read stage_4_root and stage_4_proof from MSG_ROOT_MAP"); RelayerError::Default } )?; - let leaves = Decode::decode(&mut &proof.leaves.0[..]) - .map_err(|e| anyhow::Error::new(e))?; - let decoded_proof: XcmpProofType = Decode::decode(&mut &proof.proof.0[..]) - .map_err(|e| anyhow::Error::new(e))?; + // Checking which is the current beefy root on chain for logging + let beefy_api_call = polkadot::apis().messaging_api().get_current_beefy_root(); + let beefy_root = match client.subxt_client + .runtime_api() + .at_latest() + .await? + .call(beefy_api_call) + .await { + Ok(root) => { + log::debug!("Got root from `get_current_beefy_root` {:?}", root); + root + }, + Err(e) => { + log::error!("Got error from trying to call `get_current_beefy_root` {:?}", e); + H256::zero() + } + }; - let dummy_proof: XcmpProofType = XcmpProofType:: { - leaf_indices: Vec::new(), - leaf_count: 0u64, - items: Vec::new(), - }; + log::info!("Beefy Root on Parachain {:?} Beefy Root needed to verify proof is {:?}", beefy_root, stage_1_beefy_root); let xcmp_proof = XcmpProof { - stage_1: (decoded_proof, leaves), - stage_2: merkle_proof.into(), - // TODO: Implement - stage_3: (), - // TODO: Implement - stage_4: (dummy_proof, Vec::new()), + stage_1: (stage_1_decoded_proof, stage_1_leaves), + stage_2: stage_2_proof.into(), + stage_3: stage_3_proof.into(), + stage_4: (stage_4_decoded_proof, stage_4_leaves), }; - log::info!("Got Relayblock Num {} for Beefy Root {:?}", relay_block_num, beefy_root); - // 3.) Send transaction to chain for proof log::info!("calling submit_xcmp_proof"); - submit_xcmp_proof(&client, xcmp_proof, beefy_root).await?; + submit_xcmp_proof(&client, xcmp_proof, *stage_1_beefy_root).await?; Ok(()) } @@ -383,19 +653,20 @@ async fn update_root(client: &MultiClient, root: H256) -> anyhow::Result<()> { match tx_progress.wait_for_in_block().await { Ok(tx_in_block) => { match tx_in_block.wait_for_success().await { - Ok(events) => { log::info!("Got the tx in a block and it succeeded! {:?}", events); }, - Err(e) => { log::info!("Was not successful extrinsic ERROR:: {:?}", e); } + Ok(events) => { log::debug!("Got the tx in a block and it succeeded! {:?}", events); }, + Err(e) => { log::error!("Was not successful extrinsic ERROR:: {:?}", e); } } }, Err(e) => { - log::info!("Tx didnt get in a block error {:?}", e); + log::debug!("Tx didnt get in a block error {:?}", e); } } - log::info!("Hash of update_root: {:?}", hash_tx); + log::debug!("Hash of update_root: {:?}", hash_tx); Ok(()) } async fn submit_xcmp_proof(client: &MultiClient, xcmp_proof: XcmpProof, beefy_root: H256) -> anyhow::Result<()> { + log::info!("Entering `submit_xcmp_proof`"); let signer = dev::charlie(); let tx = crate::polkadot::tx().msg_stuffer_para_a().submit_xcmp_proof(xcmp_proof, beefy_root); @@ -425,49 +696,51 @@ async fn submit_proof(client: &MultiClient, proof: LeavesProof) -> anyhow: let leaves = Decode::decode(&mut &proof.leaves.0[..]) .map_err(|e| anyhow::Error::new(e))?; - log::info!("Decoded leaves {:?}", leaves); + log::debug!("Decoded leaves {:?}", leaves); let decoded_proof = Decode::decode(&mut &proof.proof.0[..]) .map_err(|e| anyhow::Error::new(e))?; - log::info!("Decoded proof {:?}", decoded_proof); + log::debug!("Decoded proof {:?}", decoded_proof); let tx = crate::polkadot::tx().msg_stuffer_para_a().submit_test_proof(decoded_proof, leaves, channel_id); let tx_progress = client.subxt_client.tx().sign_and_submit_then_watch_default(&tx, &signer).await?; let hash_tx = tx_progress.extrinsic_hash(); - log::info!("Got After submitting submit_test_proof"); + log::debug!("Got After submitting submit_test_proof"); match tx_progress.wait_for_in_block().await { Ok(tx_in_block) => { match tx_in_block.wait_for_success().await { - Ok(events) => { log::info!("Got the tx in a block and it succeeded! {:?}", events); }, - Err(e) => { log::info!("Was not successful extrinsic ERROR:: {:?}", e); } + Ok(events) => { log::debug!("Got the tx in a block and it succeeded! {:?}", events); }, + Err(e) => { log::debug!("Was not successful extrinsic ERROR:: {:?}", e); } } }, Err(e) => { - log::info!("Tx didnt get in a block error {:?}", e); + log::debug!("Tx didnt get in a block error {:?}", e); } } - log::info!("Hash of test_proof_submission: {:?}", hash_tx); + log::debug!("Hash of test_proof_submission: {:?}", hash_tx); Ok(()) } -async fn get_proof_and_verify(client: &MultiClient, relay_client: &MultiClient) -> anyhow::Result<()> { +async fn get_proof_and_verify(client: &MultiClient, relay_client: &MultiClient, recv_client: &MultiClient) -> anyhow::Result<()> { let client = client.clone(); let relay_client = relay_client.clone(); - let mut root = generate_mmr_root(&client, Some(0)).await?; - let mut proof = generate_mmr_proof(&client, 1u64, Some(0)).await?; + let recv_client = recv_client.clone(); + let mut root = generate_mmr_root(&client, Some(RECEIVER_CHANNEL_ID), None).await?; + let mut proof = generate_mmr_proof(&client, 1u64, Some(RECEIVER_CHANNEL_ID), None).await?; let params = rpc_params![root, proof.clone()]; let request: Option = client.rpc_client.request("mmr_verifyProofStateless", params).await?; let verification = request.ok_or(RelayerError::Default)?; - log::info!("Was proof verified? Answer:: {}", verification); + log::debug!("Was proof verified? Answer:: {}", verification); task::spawn(async move { let mut blocks_sub = client.subxt_client.blocks().subscribe_best().await?; - while let Some(_block) = blocks_sub.next().await { + while let Some(block) = blocks_sub.next().await { + let block = block?; // check if current on chain root is equal to the original root to submit proof let onchain_root_query = crate::polkadot::storage().msg_stuffer_para_a().xcmp_channel_roots(0); @@ -488,24 +761,24 @@ async fn get_proof_and_verify(client: &MultiClient, relay_client: &MultiClient) }, Err(e) => format!("Cant update root on chain yet {:?}", e), }; - log::info!("{}", update_root_string); + log::debug!("{}", update_root_string); - let _ = generate_stage_xcmp_proof(&client, &relay_client).await; + let _ = generate_xcmp_proof(&client, &relay_client, &recv_client).await; if onchain_root == root { - log::info!("onchain_root matches!!! submitting now!!"); + log::debug!("onchain_root matches!!! submitting now!!"); let submit_proof_string = match submit_proof(&client, proof.clone()).await { Ok(_) => { - root = generate_mmr_root(&client, Some(0)).await?; - proof = generate_mmr_proof(&client, 1u64, Some(0)).await?; + root = generate_mmr_root(&client, Some(RECEIVER_CHANNEL_ID), None).await?; + proof = generate_mmr_proof(&client, 1u64, Some(RECEIVER_CHANNEL_ID), None).await?; "Submit proof successfully submitted".to_string() }, Err(e) => format!("Cant submit proof on chain yet {:?}", e), }; - log::info!("{}", submit_proof_string); + log::debug!("{}", submit_proof_string); } else { - log::info!("Root on chain {:?} still doesnt match original root {:?}", onchain_root, root); + log::debug!("Root on chain {:?} still doesnt match original root {:?}", onchain_root, root); } } log::info!("EXITING!!!!!"); @@ -547,7 +820,7 @@ async fn log_all_mmr_roots(client: &MultiClient) -> anyhow::Result<()> { let params = rpc_params![Option::::None, para_id]; let request: Option = client.rpc_client.request("mmr_root", params).await?; let hash = request.ok_or(RelayerError::Default)?; - log::info!("Mmr root for block_hash {:?}, block_number {:?} root {:?}", block.hash(), block.number(), hash); + log::debug!("Mmr root for block_hash {:?}, block_number {:?} root {:?}", block.hash(), block.number(), hash); } Ok::<(), anyhow::Error>(()) @@ -583,8 +856,8 @@ async fn log_all_mmr_proofs(client: &MultiClient) -> anyhow::Result<()> { let curr_proof_size = proof.proof.len() as u64; proof_sizes.push(curr_proof_size); let mean = do_mean(&proof_sizes).await?; - log::info!("num of mmr blocks: {}, counter value: {}, proof_size: {}, curr_avg_proof_size: {}", mmr_blocks_to_query.len(), mmr_blocks_benchmark_counter, curr_proof_size, mean); - log::info!("Mmr proof for block_hash {:?}, block_number {:?}, proof {:?}", block.hash(), block.number(), proof); + log::debug!("num of mmr blocks: {}, counter value: {}, proof_size: {}, curr_avg_proof_size: {}", mmr_blocks_to_query.len(), mmr_blocks_benchmark_counter, curr_proof_size, mean); + log::debug!("Mmr proof for block_hash {:?}, block_number {:?}, proof {:?}", block.hash(), block.number(), proof); } Ok::<(), anyhow::Error>(()) @@ -611,7 +884,7 @@ async fn try_generate_mmr_proof( let mut attempts = 0u32; loop { - log::info!("Entering generate_mmr_proof block_num {}", block_num); + log::debug!("Entering generate_mmr_proof block_num {}", block_num); let params = match channel_id { Some(id) => rpc_params![vec![block_num], Option::::None, Option::::None, id], @@ -620,7 +893,7 @@ async fn try_generate_mmr_proof( match client.rpc_client.request::>, _>("mmr_generateProof", params).await { Ok(opt_proof) => { - log::info!("MMR proof obtained for block_num {}", block_num); + log::debug!("MMR proof obtained for block_num {}", block_num); return opt_proof.ok_or(anyhow::anyhow!("Proof was None")) }, Err(e) if attempts < MAX_ATTEMPTS => { @@ -638,44 +911,45 @@ async fn try_generate_mmr_proof( async fn generate_mmr_proof( client: &MultiClient, block_num: u64, - channel_id: Option + channel_id: Option, + block_hash: Option ) -> anyhow::Result> { - log::info!("Entering generate_mmr_proof block_num {}", block_num); + log::debug!("Entering generate_mmr_proof block_num {}", block_num); let params = if let Some(id) = channel_id { - rpc_params![vec![block_num], Option::::None, Option::::None, id] + rpc_params![vec![block_num], Option::::None, block_hash, id] } else { - rpc_params![vec![block_num], Option::::None, Option::::None] + rpc_params![vec![block_num], Option::::None, block_hash] }; let request: Option> = match client.rpc_client.request("mmr_generateProof", params).await { Ok(opt_proof) => { - log::info!("Got proof from request.. block_num {}", block_num); + log::debug!("Got proof from request.. block_num {}", block_num); opt_proof }, Err(e) => { - log::info!("Couldnt Get MMR request error {:?}", e); + log::error!("Couldnt Get MMR request error {:?}", e); None } }; let proof = request.ok_or(RelayerError::Default)?; - log::info!("Proof obtained:: {:?}", proof); + log::debug!("Proof obtained:: {:?}", proof); Ok(proof) } // Call generate mmr proof for sender -async fn generate_mmr_root(client: &MultiClient, channel_id: Option) -> anyhow::Result { +async fn generate_mmr_root(client: &MultiClient, channel_id: Option, block_hash: Option) -> anyhow::Result { let params = if let Some(id) = channel_id { - rpc_params![Option::::None, id] + rpc_params![block_hash, id] } else { - rpc_params![Option::::None] + rpc_params![block_hash] }; let request: Option = client.rpc_client.request("mmr_root", params).await?; let root = request.ok_or(RelayerError::Default)?; - log::info!("root obtained:: {:?}", root); + log::debug!("root obtained:: {:?}", root); Ok(root) }