From 94fb90bf300eaf825ed0dc029dd8d5a0c3e14a56 Mon Sep 17 00:00:00 2001 From: Svyatoslav Nikolsky Date: Mon, 24 Apr 2023 13:04:48 +0300 Subject: [PATCH 1/2] fix max-size messages submit for test chains --- Cargo.lock | 2 + bin/runtime-common/src/lib.rs | 11 ++ relays/bin-substrate/Cargo.toml | 7 +- relays/bin-substrate/src/chains/millau.rs | 27 ++++- relays/bin-substrate/src/chains/rialto.rs | 25 ++++- .../src/chains/rialto_parachain.rs | 25 ++++- .../bin-substrate/src/cli/encode_message.rs | 102 +++++++++++++----- 7 files changed, 166 insertions(+), 33 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2e26ef4fb6..383a0cb8d9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -13074,6 +13074,7 @@ dependencies = [ "relay-utils", "relay-westend-client", "relay-wococo-client", + "rialto-parachain-runtime", "rialto-runtime", "signal-hook", "signal-hook-async-std", @@ -13085,6 +13086,7 @@ dependencies = [ "substrate-relay-helper", "tempfile", "xcm", + "xcm-executor", ] [[package]] diff --git a/bin/runtime-common/src/lib.rs b/bin/runtime-common/src/lib.rs index e8a2d2470f..3ed12ab92f 100644 --- a/bin/runtime-common/src/lib.rs +++ b/bin/runtime-common/src/lib.rs @@ -160,6 +160,17 @@ pub enum CustomNetworkId { } impl CustomNetworkId { + /// Tries to create self from bridges chain id. + pub const fn try_from_chain_id(chain: bp_runtime::ChainId) -> Option { + match chain { + bp_runtime::MILLAU_CHAIN_ID => Some(Self::Millau), + bp_runtime::RIALTO_CHAIN_ID => Some(Self::Rialto), + bp_runtime::RIALTO_PARACHAIN_CHAIN_ID => Some(Self::RialtoParachain), + _ => None, + } + } + + /// Converts self to XCM' network id. pub const fn as_network_id(&self) -> NetworkId { match *self { CustomNetworkId::Millau => NetworkId::Kusama, diff --git a/relays/bin-substrate/Cargo.toml b/relays/bin-substrate/Cargo.toml index 7853b9cb59..0a31503504 100644 --- a/relays/bin-substrate/Cargo.toml +++ b/relays/bin-substrate/Cargo.toml @@ -49,6 +49,9 @@ relay-utils = { path = "../utils" } relay-westend-client = { path = "../client-westend" } relay-wococo-client = { path = "../client-wococo" } rialto-runtime = { path = "../../bin/rialto/runtime" } +# we are not using this runtime to craft callsour transactions, but we still need it +# to prepare large XCM messages +rialto-parachain-runtime = { path = "../../bin/rialto-parachain/runtime" } substrate-relay-helper = { path = "../lib-substrate-relay" } # Substrate Dependencies @@ -62,8 +65,8 @@ polkadot-parachain = { git = "https://github.com/paritytech/polkadot", branch = polkadot-primitives = { git = "https://github.com/paritytech/polkadot", branch = "master" } polkadot-runtime-common = { git = "https://github.com/paritytech/polkadot", branch = "master" } polkadot-runtime-parachains = { git = "https://github.com/paritytech/polkadot", branch = "master" } -xcm = { git = "https://github.com/paritytech/polkadot", branch = "master", default-features = false } - +xcm = { git = "https://github.com/paritytech/polkadot", branch = "master" } +xcm-executor = { git = "https://github.com/paritytech/polkadot", branch = "master" } [dev-dependencies] bp-test-utils = { path = "../../primitives/test-utils" } diff --git a/relays/bin-substrate/src/chains/millau.rs b/relays/bin-substrate/src/chains/millau.rs index 44416195c6..9249958c28 100644 --- a/relays/bin-substrate/src/chains/millau.rs +++ b/relays/bin-substrate/src/chains/millau.rs @@ -17,11 +17,36 @@ //! Millau chain specification for CLI. use crate::cli::{encode_message::CliEncodeMessage, CliChain}; -use bp_runtime::EncodedOrDecodedCall; +use bp_runtime::{ChainId, EncodedOrDecodedCall, RIALTO_CHAIN_ID, RIALTO_PARACHAIN_CHAIN_ID}; +use bridge_runtime_common::CustomNetworkId; use relay_millau_client::Millau; use relay_substrate_client::SimpleRuntimeVersion; +use xcm_executor::traits::ExportXcm; impl CliEncodeMessage for Millau { + fn encode_wire_message( + target: ChainId, + at_target_xcm: xcm::v3::Xcm<()>, + ) -> anyhow::Result> { + let target = match target { + RIALTO_CHAIN_ID => CustomNetworkId::Rialto.as_network_id(), + RIALTO_PARACHAIN_CHAIN_ID => CustomNetworkId::RialtoParachain.as_network_id(), + _ => return Err(anyhow::format_err!("Unsupported target chain: {:?}", target)), + }; + + Ok(millau_runtime::xcm_config::ToRialtoOrRialtoParachainSwitchExporter::validate( + target, + 0, + &mut Some(Self::dummy_universal_source()?), + &mut Some(target.into()), + &mut Some(at_target_xcm), + ) + .map_err(|e| anyhow::format_err!("Failed to prepare outbound message: {:?}", e))? + .0 + .1 + .0) + } + fn encode_execute_xcm( message: xcm::VersionedXcm, ) -> anyhow::Result> { diff --git a/relays/bin-substrate/src/chains/rialto.rs b/relays/bin-substrate/src/chains/rialto.rs index 34a448ae4c..fb3003b30d 100644 --- a/relays/bin-substrate/src/chains/rialto.rs +++ b/relays/bin-substrate/src/chains/rialto.rs @@ -17,11 +17,34 @@ //! Rialto chain specification for CLI. use crate::cli::{encode_message::CliEncodeMessage, CliChain}; -use bp_runtime::EncodedOrDecodedCall; +use bp_runtime::{ChainId, EncodedOrDecodedCall, MILLAU_CHAIN_ID}; +use bridge_runtime_common::CustomNetworkId; use relay_rialto_client::Rialto; use relay_substrate_client::SimpleRuntimeVersion; +use xcm_executor::traits::ExportXcm; impl CliEncodeMessage for Rialto { + fn encode_wire_message( + target: ChainId, + at_target_xcm: xcm::v3::Xcm<()>, + ) -> anyhow::Result> { + let target = match target { + MILLAU_CHAIN_ID => CustomNetworkId::Millau.as_network_id(), + _ => return Err(anyhow::format_err!("Unsupported target chian: {:?}", target)), + }; + + Ok(rialto_runtime::millau_messages::ToMillauBlobExporter::validate( + target, + 0, + &mut Some(Self::dummy_universal_source()?), + &mut Some(target.into()), + &mut Some(at_target_xcm), + ) + .map_err(|e| anyhow::format_err!("Failed to prepare outbound message: {:?}", e))? + .0 + .0) + } + fn encode_execute_xcm( message: xcm::VersionedXcm, ) -> anyhow::Result> { diff --git a/relays/bin-substrate/src/chains/rialto_parachain.rs b/relays/bin-substrate/src/chains/rialto_parachain.rs index 8ea2c1ffd4..f1de10b5c5 100644 --- a/relays/bin-substrate/src/chains/rialto_parachain.rs +++ b/relays/bin-substrate/src/chains/rialto_parachain.rs @@ -17,11 +17,34 @@ //! Rialto parachain specification for CLI. use crate::cli::{encode_message::CliEncodeMessage, CliChain}; -use bp_runtime::EncodedOrDecodedCall; +use bp_runtime::{ChainId, EncodedOrDecodedCall, MILLAU_CHAIN_ID}; +use bridge_runtime_common::CustomNetworkId; use relay_rialto_parachain_client::RialtoParachain; use relay_substrate_client::SimpleRuntimeVersion; +use xcm_executor::traits::ExportXcm; impl CliEncodeMessage for RialtoParachain { + fn encode_wire_message( + target: ChainId, + at_target_xcm: xcm::v3::Xcm<()>, + ) -> anyhow::Result> { + let target = match target { + MILLAU_CHAIN_ID => CustomNetworkId::Millau.as_network_id(), + _ => return Err(anyhow::format_err!("Unsupported target chain: {:?}", target)), + }; + + Ok(rialto_parachain_runtime::millau_messages::ToMillauBlobExporter::validate( + target, + 0, + &mut Some(Self::dummy_universal_source()?), + &mut Some(target.into()), + &mut Some(at_target_xcm), + ) + .map_err(|e| anyhow::format_err!("Failed to prepare outbound message: {:?}", e))? + .0 + .0) + } + fn encode_execute_xcm( message: xcm::VersionedXcm, ) -> anyhow::Result> { diff --git a/relays/bin-substrate/src/cli/encode_message.rs b/relays/bin-substrate/src/cli/encode_message.rs index 9abf8b2df6..c7f7bf6203 100644 --- a/relays/bin-substrate/src/cli/encode_message.rs +++ b/relays/bin-substrate/src/cli/encode_message.rs @@ -15,11 +15,15 @@ // along with Parity Bridges Common. If not, see . use crate::cli::{ExplicitOrMaximal, HexBytes}; -use bp_runtime::EncodedOrDecodedCall; +use bp_runtime::{ + ChainId, EncodedOrDecodedCall, MILLAU_CHAIN_ID, RIALTO_CHAIN_ID, RIALTO_PARACHAIN_CHAIN_ID, +}; +use bridge_runtime_common::CustomNetworkId; use codec::Encode; use frame_support::weights::Weight; use relay_substrate_client::Chain; use structopt::StructOpt; +use xcm::latest::prelude::*; /// All possible messages that may be delivered to generic Substrate chain. /// @@ -43,6 +47,31 @@ pub enum Message { pub type RawMessage = Vec; pub trait CliEncodeMessage: Chain { + /// Returns dummy `AccountId32` universal source given this network id. + fn dummy_universal_source() -> anyhow::Result { + use xcm::v3::prelude::*; + + let this_network = CustomNetworkId::try_from_chain_id(Self::ID) + .map(|n| n.as_network_id()) + .ok_or_else(|| anyhow::format_err!("Unsupported chain: {:?}", Self::ID))?; + let this_location: InteriorMultiLocation = this_network.into(); + + let origin = MultiLocation { + parents: 0, + interior: X1(AccountId32 { network: Some(this_network), id: [0u8; 32] }), + }; + let universal_source = this_location + .within_global(origin) + .map_err(|e| anyhow::format_err!("Invalid location: {:?}", e))?; + + Ok(universal_source) + } + /// Returns XCM blob that is passed to the `send_message` function of the messages pallet + /// and then is sent over the wire. + fn encode_wire_message( + target: ChainId, + at_target_xcm: xcm::v3::Xcm<()>, + ) -> anyhow::Result>; /// Encode an `execute` XCM call of the XCM pallet. fn encode_execute_xcm( message: xcm::VersionedXcm, @@ -56,41 +85,45 @@ pub trait CliEncodeMessage: Chain { } /// Encode message payload passed through CLI flags. -pub(crate) fn encode_message( +pub(crate) fn encode_message( message: &Message, ) -> anyhow::Result { Ok(match message { Message::Raw { ref data } => data.0.clone(), Message::Sized { ref size } => { - let expected_xcm_size = match *size { + let destination = match Target::ID { + MILLAU_CHAIN_ID => CustomNetworkId::Millau.as_network_id(), + RIALTO_CHAIN_ID => CustomNetworkId::RialtoParachain.as_network_id(), + RIALTO_PARACHAIN_CHAIN_ID => CustomNetworkId::RialtoParachain.as_network_id(), + _ => return Err(anyhow::format_err!("Unsupported target chain: {:?}", Target::ID)), + }; + let expected_size = match *size { ExplicitOrMaximal::Explicit(size) => size, ExplicitOrMaximal::Maximal => compute_maximal_message_size( Source::max_extrinsic_size(), Target::max_extrinsic_size(), ), - }; - - // there's no way to craft XCM of the given size - we'll be using `ExpectPallet` - // instruction, which has byte vector inside - let mut current_vec_size = expected_xcm_size; - let xcm = loop { - let xcm = xcm::VersionedXcm::<()>::V3( - vec![xcm::v3::Instruction::ExpectPallet { - index: 0, - name: vec![42; current_vec_size as usize], - module_name: vec![], - crate_major: 0, - min_crate_minor: 0, - }] - .into(), - ); - if xcm.encode().len() <= expected_xcm_size as usize { - break xcm - } - - current_vec_size -= 1; - }; - xcm.encode() + } as usize; + + let at_target_xcm = vec![xcm::v3::Instruction::ClearOrigin; expected_size].into(); + let at_target_xcm_size = + Source::encode_wire_message(Target::ID, at_target_xcm)?.encoded_size(); + let at_target_xcm_overhead = at_target_xcm_size.saturating_sub(expected_size); + let at_target_xcm = vec![ + xcm::v3::Instruction::ClearOrigin; + expected_size.saturating_sub(at_target_xcm_overhead) + ] + .into(); + + xcm::VersionedXcm::<()>::V3( + vec![ExportMessage { + network: destination, + destination: destination.into(), + xcm: at_target_xcm, + }] + .into(), + ) + .encode() }, }) } @@ -123,13 +156,21 @@ mod tests { use relay_millau_client::Millau; use relay_rialto_client::Rialto; + fn approximate_message_size(xcm_msg_len: usize) -> usize { + xcm_msg_len + Source::dummy_universal_source().unwrap().encoded_size() + } + #[test] fn encode_explicit_size_message_works() { let msg = encode_message::(&Message::Sized { size: ExplicitOrMaximal::Explicit(100), }) .unwrap(); - assert_eq!(msg.len(), 100); + // since it isn't the returned XCM what is sent over the wire, we can only check if + // it is close to what we need + assert!( + (1f64 - (approximate_message_size::(msg.len()) as f64) / 100_f64).abs() < 0.1 + ); // check that it decodes to valid xcm let _ = decode_xcm::<()>(msg).unwrap(); } @@ -144,7 +185,12 @@ mod tests { let msg = encode_message::(&Message::Sized { size: ExplicitOrMaximal::Maximal }) .unwrap(); - assert_eq!(msg.len(), maximal_size as usize); + // since it isn't the returned XCM what is sent over the wire, we can only check if + // it is close to what we need + assert!( + (1f64 - approximate_message_size::(msg.len()) as f64 / maximal_size as f64) + .abs() < 0.1 + ); // check that it decodes to valid xcm let _ = decode_xcm::<()>(msg).unwrap(); } From d7c8f772ceda10b5b78f3cead032e8197d88370d Mon Sep 17 00:00:00 2001 From: Svyatoslav Nikolsky Date: Wed, 26 Apr 2023 08:43:39 +0300 Subject: [PATCH 2/2] impl review suggestions --- bin/runtime-common/src/lib.rs | 21 +++++++++++-------- .../bin-substrate/src/cli/encode_message.rs | 17 ++++++--------- 2 files changed, 18 insertions(+), 20 deletions(-) diff --git a/bin/runtime-common/src/lib.rs b/bin/runtime-common/src/lib.rs index 3ed12ab92f..12b096492c 100644 --- a/bin/runtime-common/src/lib.rs +++ b/bin/runtime-common/src/lib.rs @@ -159,17 +159,20 @@ pub enum CustomNetworkId { RialtoParachain, } -impl CustomNetworkId { - /// Tries to create self from bridges chain id. - pub const fn try_from_chain_id(chain: bp_runtime::ChainId) -> Option { - match chain { - bp_runtime::MILLAU_CHAIN_ID => Some(Self::Millau), - bp_runtime::RIALTO_CHAIN_ID => Some(Self::Rialto), - bp_runtime::RIALTO_PARACHAIN_CHAIN_ID => Some(Self::RialtoParachain), - _ => None, - } +impl TryFrom for CustomNetworkId { + type Error = (); + + fn try_from(chain: bp_runtime::ChainId) -> Result { + Ok(match chain { + bp_runtime::MILLAU_CHAIN_ID => Self::Millau, + bp_runtime::RIALTO_CHAIN_ID => Self::Rialto, + bp_runtime::RIALTO_PARACHAIN_CHAIN_ID => Self::RialtoParachain, + _ => return Err(()), + }) } +} +impl CustomNetworkId { /// Converts self to XCM' network id. pub const fn as_network_id(&self) -> NetworkId { match *self { diff --git a/relays/bin-substrate/src/cli/encode_message.rs b/relays/bin-substrate/src/cli/encode_message.rs index c7f7bf6203..25231a970b 100644 --- a/relays/bin-substrate/src/cli/encode_message.rs +++ b/relays/bin-substrate/src/cli/encode_message.rs @@ -15,9 +15,7 @@ // along with Parity Bridges Common. If not, see . use crate::cli::{ExplicitOrMaximal, HexBytes}; -use bp_runtime::{ - ChainId, EncodedOrDecodedCall, MILLAU_CHAIN_ID, RIALTO_CHAIN_ID, RIALTO_PARACHAIN_CHAIN_ID, -}; +use bp_runtime::{ChainId, EncodedOrDecodedCall}; use bridge_runtime_common::CustomNetworkId; use codec::Encode; use frame_support::weights::Weight; @@ -51,9 +49,9 @@ pub trait CliEncodeMessage: Chain { fn dummy_universal_source() -> anyhow::Result { use xcm::v3::prelude::*; - let this_network = CustomNetworkId::try_from_chain_id(Self::ID) + let this_network = CustomNetworkId::try_from(Self::ID) .map(|n| n.as_network_id()) - .ok_or_else(|| anyhow::format_err!("Unsupported chain: {:?}", Self::ID))?; + .map_err(|_| anyhow::format_err!("Unsupported chain: {:?}", Self::ID))?; let this_location: InteriorMultiLocation = this_network.into(); let origin = MultiLocation { @@ -91,12 +89,9 @@ pub(crate) fn encode_message( Ok(match message { Message::Raw { ref data } => data.0.clone(), Message::Sized { ref size } => { - let destination = match Target::ID { - MILLAU_CHAIN_ID => CustomNetworkId::Millau.as_network_id(), - RIALTO_CHAIN_ID => CustomNetworkId::RialtoParachain.as_network_id(), - RIALTO_PARACHAIN_CHAIN_ID => CustomNetworkId::RialtoParachain.as_network_id(), - _ => return Err(anyhow::format_err!("Unsupported target chain: {:?}", Target::ID)), - }; + let destination = CustomNetworkId::try_from(Target::ID) + .map(|n| n.as_network_id()) + .map_err(|_| anyhow::format_err!("Unsupported target chain: {:?}", Target::ID))?; let expected_size = match *size { ExplicitOrMaximal::Explicit(size) => size, ExplicitOrMaximal::Maximal => compute_maximal_message_size(