Fix sized messages (Follow-up on #2064) (#2103)

* Use wasm execution on millau and rialto

It's safer like this since here are some errors that aren't caught when
using native execution

* Revert "Revert "Fix max-size messages at test chains (#2064)" (#2077)"

This reverts commit 62f749e124fbcf074cdc9840690bb9049d4b3b99.

* Adjustments
This commit is contained in:
Serban Iorga
2023-05-03 10:44:06 +03:00
committed by Bastian Köcher
parent 49d11e9ce5
commit de918f8f3c
6 changed files with 161 additions and 32 deletions
+14
View File
@@ -159,7 +159,21 @@ pub enum CustomNetworkId {
RialtoParachain, RialtoParachain,
} }
impl TryFrom<bp_runtime::ChainId> for CustomNetworkId {
type Error = ();
fn try_from(chain: bp_runtime::ChainId) -> Result<Self, Self::Error> {
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 { impl CustomNetworkId {
/// Converts self to XCM' network id.
pub const fn as_network_id(&self) -> NetworkId { pub const fn as_network_id(&self) -> NetworkId {
match *self { match *self {
CustomNetworkId::Millau => NetworkId::Kusama, CustomNetworkId::Millau => NetworkId::Kusama,
+5 -2
View File
@@ -49,6 +49,9 @@ relay-utils = { path = "../utils" }
relay-westend-client = { path = "../client-westend" } relay-westend-client = { path = "../client-westend" }
relay-wococo-client = { path = "../client-wococo" } relay-wococo-client = { path = "../client-wococo" }
rialto-runtime = { path = "../../bin/rialto/runtime" } 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-relay-helper = { path = "../lib-substrate-relay" }
# Substrate Dependencies # 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-primitives = { git = "https://github.com/paritytech/polkadot", branch = "master" }
polkadot-runtime-common = { 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" } 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] [dev-dependencies]
bp-test-utils = { path = "../../primitives/test-utils" } bp-test-utils = { path = "../../primitives/test-utils" }
@@ -18,10 +18,38 @@
use crate::cli::{encode_message::CliEncodeMessage, CliChain}; use crate::cli::{encode_message::CliEncodeMessage, CliChain};
use bp_runtime::EncodedOrDecodedCall; use bp_runtime::EncodedOrDecodedCall;
use bridge_runtime_common::CustomNetworkId;
use relay_millau_client::Millau; use relay_millau_client::Millau;
use relay_substrate_client::SimpleRuntimeVersion; use relay_substrate_client::SimpleRuntimeVersion;
use xcm_executor::traits::ExportXcm;
impl CliEncodeMessage for Millau { impl CliEncodeMessage for Millau {
fn encode_wire_message(
target: xcm::v3::NetworkId,
at_target_xcm: xcm::v3::Xcm<()>,
) -> anyhow::Result<Vec<u8>> {
anyhow::ensure!(
[
CustomNetworkId::Rialto.as_network_id(),
CustomNetworkId::RialtoParachain.as_network_id()
]
.contains(&target),
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( fn encode_execute_xcm(
message: xcm::VersionedXcm<Self::Call>, message: xcm::VersionedXcm<Self::Call>,
) -> anyhow::Result<EncodedOrDecodedCall<Self::Call>> { ) -> anyhow::Result<EncodedOrDecodedCall<Self::Call>> {
@@ -18,10 +18,33 @@
use crate::cli::{encode_message::CliEncodeMessage, CliChain}; use crate::cli::{encode_message::CliEncodeMessage, CliChain};
use bp_runtime::EncodedOrDecodedCall; use bp_runtime::EncodedOrDecodedCall;
use bridge_runtime_common::CustomNetworkId;
use relay_rialto_client::Rialto; use relay_rialto_client::Rialto;
use relay_substrate_client::SimpleRuntimeVersion; use relay_substrate_client::SimpleRuntimeVersion;
use xcm_executor::traits::ExportXcm;
impl CliEncodeMessage for Rialto { impl CliEncodeMessage for Rialto {
fn encode_wire_message(
target: xcm::v3::NetworkId,
at_target_xcm: xcm::v3::Xcm<()>,
) -> anyhow::Result<Vec<u8>> {
anyhow::ensure!(
target == CustomNetworkId::Millau.as_network_id(),
anyhow::format_err!("Unsupported target chain: {:?}", 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( fn encode_execute_xcm(
message: xcm::VersionedXcm<Self::Call>, message: xcm::VersionedXcm<Self::Call>,
) -> anyhow::Result<EncodedOrDecodedCall<Self::Call>> { ) -> anyhow::Result<EncodedOrDecodedCall<Self::Call>> {
@@ -18,10 +18,33 @@
use crate::cli::{encode_message::CliEncodeMessage, CliChain}; use crate::cli::{encode_message::CliEncodeMessage, CliChain};
use bp_runtime::EncodedOrDecodedCall; use bp_runtime::EncodedOrDecodedCall;
use bridge_runtime_common::CustomNetworkId;
use relay_rialto_parachain_client::RialtoParachain; use relay_rialto_parachain_client::RialtoParachain;
use relay_substrate_client::SimpleRuntimeVersion; use relay_substrate_client::SimpleRuntimeVersion;
use xcm_executor::traits::ExportXcm;
impl CliEncodeMessage for RialtoParachain { impl CliEncodeMessage for RialtoParachain {
fn encode_wire_message(
target: xcm::v3::NetworkId,
at_target_xcm: xcm::v3::Xcm<()>,
) -> anyhow::Result<Vec<u8>> {
anyhow::ensure!(
target == CustomNetworkId::Millau.as_network_id(),
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( fn encode_execute_xcm(
message: xcm::VersionedXcm<Self::Call>, message: xcm::VersionedXcm<Self::Call>,
) -> anyhow::Result<EncodedOrDecodedCall<Self::Call>> { ) -> anyhow::Result<EncodedOrDecodedCall<Self::Call>> {
@@ -16,10 +16,12 @@
use crate::cli::{ExplicitOrMaximal, HexBytes}; use crate::cli::{ExplicitOrMaximal, HexBytes};
use bp_runtime::EncodedOrDecodedCall; use bp_runtime::EncodedOrDecodedCall;
use bridge_runtime_common::CustomNetworkId;
use codec::Encode; use codec::Encode;
use frame_support::weights::Weight; use frame_support::weights::Weight;
use relay_substrate_client::Chain; use relay_substrate_client::Chain;
use structopt::StructOpt; use structopt::StructOpt;
use xcm::latest::prelude::*;
/// All possible messages that may be delivered to generic Substrate chain. /// All possible messages that may be delivered to generic Substrate chain.
/// ///
@@ -43,6 +45,22 @@ pub enum Message {
pub type RawMessage = Vec<u8>; pub type RawMessage = Vec<u8>;
pub trait CliEncodeMessage: Chain { pub trait CliEncodeMessage: Chain {
/// Returns dummy `AccountId32` universal source given this network id.
fn dummy_universal_source() -> anyhow::Result<xcm::v3::Junctions> {
use xcm::v3::prelude::*;
let this_network = CustomNetworkId::try_from(Self::ID)
.map(|n| n.as_network_id())
.map_err(|_| anyhow::format_err!("Unsupported chain: {:?}", Self::ID))?;
Ok(X2(
GlobalConsensus(this_network),
AccountId32 { network: Some(this_network), id: [0u8; 32] },
))
}
/// 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: NetworkId, at_target_xcm: Xcm<()>) -> anyhow::Result<Vec<u8>>;
/// Encode an `execute` XCM call of the XCM pallet. /// Encode an `execute` XCM call of the XCM pallet.
fn encode_execute_xcm( fn encode_execute_xcm(
message: xcm::VersionedXcm<Self::Call>, message: xcm::VersionedXcm<Self::Call>,
@@ -56,41 +74,52 @@ pub trait CliEncodeMessage: Chain {
} }
/// Encode message payload passed through CLI flags. /// Encode message payload passed through CLI flags.
pub(crate) fn encode_message<Source: Chain, Target: Chain>( pub(crate) fn encode_message<Source: CliEncodeMessage, Target: Chain>(
message: &Message, message: &Message,
) -> anyhow::Result<RawMessage> { ) -> anyhow::Result<RawMessage> {
Ok(match message { Ok(match message {
Message::Raw { ref data } => data.0.clone(), Message::Raw { ref data } => data.0.clone(),
Message::Sized { ref size } => { Message::Sized { ref size } => {
let expected_xcm_size = match *size { 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::Explicit(size) => size,
ExplicitOrMaximal::Maximal => compute_maximal_message_size( ExplicitOrMaximal::Maximal => compute_maximal_message_size(
Source::max_extrinsic_size(), Source::max_extrinsic_size(),
Target::max_extrinsic_size(), Target::max_extrinsic_size(),
), ),
}; } as usize;
// there's no way to craft XCM of the given size - we'll be using `ExpectPallet` let at_target_xcm = vec![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, index: 0,
name: vec![42; current_vec_size as usize], name: vec![42; expected_size],
module_name: vec![], module_name: vec![],
crate_major: 0, crate_major: 0,
min_crate_minor: 0, min_crate_minor: 0,
}] }]
.into(), .into();
); let at_target_xcm_size =
if xcm.encode().len() <= expected_xcm_size as usize { Source::encode_wire_message(destination, at_target_xcm)?.encoded_size();
break xcm let at_target_xcm_overhead = at_target_xcm_size.saturating_sub(expected_size);
} let at_target_xcm = vec![ExpectPallet {
index: 0,
name: vec![42; expected_size.saturating_sub(at_target_xcm_overhead)],
module_name: vec![],
crate_major: 0,
min_crate_minor: 0,
}]
.into();
current_vec_size -= 1; xcm::VersionedXcm::<()>::V3(
}; vec![ExportMessage {
xcm.encode() network: destination,
destination: destination.into(),
xcm: at_target_xcm,
}]
.into(),
)
.encode()
}, },
}) })
} }
@@ -108,11 +137,7 @@ pub(crate) fn compute_maximal_message_size(
bridge_runtime_common::messages::target::maximal_incoming_message_size( bridge_runtime_common::messages::target::maximal_incoming_message_size(
maximal_target_extrinsic_size, maximal_target_extrinsic_size,
); );
if maximal_message_size > maximal_source_extrinsic_size { std::cmp::min(maximal_message_size, maximal_source_extrinsic_size)
maximal_source_extrinsic_size
} else {
maximal_message_size
}
} }
#[cfg(test)] #[cfg(test)]
@@ -123,13 +148,21 @@ mod tests {
use relay_millau_client::Millau; use relay_millau_client::Millau;
use relay_rialto_client::Rialto; use relay_rialto_client::Rialto;
fn approximate_message_size<Source: CliEncodeMessage>(xcm_msg_len: usize) -> usize {
xcm_msg_len + Source::dummy_universal_source().unwrap().encoded_size()
}
#[test] #[test]
fn encode_explicit_size_message_works() { fn encode_explicit_size_message_works() {
let msg = encode_message::<Rialto, Millau>(&Message::Sized { let msg = encode_message::<Rialto, Millau>(&Message::Sized {
size: ExplicitOrMaximal::Explicit(100), size: ExplicitOrMaximal::Explicit(100),
}) })
.unwrap(); .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::<Rialto>(msg.len()) as f64) / 100_f64).abs() < 0.1
);
// check that it decodes to valid xcm // check that it decodes to valid xcm
let _ = decode_xcm::<()>(msg).unwrap(); let _ = decode_xcm::<()>(msg).unwrap();
} }
@@ -144,7 +177,12 @@ mod tests {
let msg = let msg =
encode_message::<Rialto, Millau>(&Message::Sized { size: ExplicitOrMaximal::Maximal }) encode_message::<Rialto, Millau>(&Message::Sized { size: ExplicitOrMaximal::Maximal })
.unwrap(); .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::<Rialto>(msg.len()) as f64 / maximal_size as f64)
.abs() < 0.1
);
// check that it decodes to valid xcm // check that it decodes to valid xcm
let _ = decode_xcm::<()>(msg).unwrap(); let _ = decode_xcm::<()>(msg).unwrap();
} }