Skip to content

Commit c0eef51

Browse files
authored
Fix max-size messages at test chains (#2064)
* fix max-size messages submit for test chains * impl review suggestions
1 parent 3a658e3 commit c0eef51

File tree

7 files changed

+164
-33
lines changed

7 files changed

+164
-33
lines changed

Cargo.lock

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

bin/runtime-common/src/lib.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,21 @@ pub enum CustomNetworkId {
159159
RialtoParachain,
160160
}
161161

162+
impl TryFrom<bp_runtime::ChainId> for CustomNetworkId {
163+
type Error = ();
164+
165+
fn try_from(chain: bp_runtime::ChainId) -> Result<Self, Self::Error> {
166+
Ok(match chain {
167+
bp_runtime::MILLAU_CHAIN_ID => Self::Millau,
168+
bp_runtime::RIALTO_CHAIN_ID => Self::Rialto,
169+
bp_runtime::RIALTO_PARACHAIN_CHAIN_ID => Self::RialtoParachain,
170+
_ => return Err(()),
171+
})
172+
}
173+
}
174+
162175
impl CustomNetworkId {
176+
/// Converts self to XCM' network id.
163177
pub const fn as_network_id(&self) -> NetworkId {
164178
match *self {
165179
CustomNetworkId::Millau => NetworkId::Kusama,

relays/bin-substrate/Cargo.toml

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,9 @@ relay-utils = { path = "../utils" }
4949
relay-westend-client = { path = "../client-westend" }
5050
relay-wococo-client = { path = "../client-wococo" }
5151
rialto-runtime = { path = "../../bin/rialto/runtime" }
52+
# we are not using this runtime to craft callsour transactions, but we still need it
53+
# to prepare large XCM messages
54+
rialto-parachain-runtime = { path = "../../bin/rialto-parachain/runtime" }
5255
substrate-relay-helper = { path = "../lib-substrate-relay" }
5356

5457
# Substrate Dependencies
@@ -62,8 +65,8 @@ polkadot-parachain = { git = "https://github.com/paritytech/polkadot", branch =
6265
polkadot-primitives = { git = "https://github.com/paritytech/polkadot", branch = "master" }
6366
polkadot-runtime-common = { git = "https://github.com/paritytech/polkadot", branch = "master" }
6467
polkadot-runtime-parachains = { git = "https://github.com/paritytech/polkadot", branch = "master" }
65-
xcm = { git = "https://github.com/paritytech/polkadot", branch = "master", default-features = false }
66-
68+
xcm = { git = "https://github.com/paritytech/polkadot", branch = "master" }
69+
xcm-executor = { git = "https://github.com/paritytech/polkadot", branch = "master" }
6770

6871
[dev-dependencies]
6972
bp-test-utils = { path = "../../primitives/test-utils" }

relays/bin-substrate/src/chains/millau.rs

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,36 @@
1717
//! Millau chain specification for CLI.
1818
1919
use crate::cli::{encode_message::CliEncodeMessage, CliChain};
20-
use bp_runtime::EncodedOrDecodedCall;
20+
use bp_runtime::{ChainId, EncodedOrDecodedCall, RIALTO_CHAIN_ID, RIALTO_PARACHAIN_CHAIN_ID};
21+
use bridge_runtime_common::CustomNetworkId;
2122
use relay_millau_client::Millau;
2223
use relay_substrate_client::SimpleRuntimeVersion;
24+
use xcm_executor::traits::ExportXcm;
2325

2426
impl CliEncodeMessage for Millau {
27+
fn encode_wire_message(
28+
target: ChainId,
29+
at_target_xcm: xcm::v3::Xcm<()>,
30+
) -> anyhow::Result<Vec<u8>> {
31+
let target = match target {
32+
RIALTO_CHAIN_ID => CustomNetworkId::Rialto.as_network_id(),
33+
RIALTO_PARACHAIN_CHAIN_ID => CustomNetworkId::RialtoParachain.as_network_id(),
34+
_ => return Err(anyhow::format_err!("Unsupported target chain: {:?}", target)),
35+
};
36+
37+
Ok(millau_runtime::xcm_config::ToRialtoOrRialtoParachainSwitchExporter::validate(
38+
target,
39+
0,
40+
&mut Some(Self::dummy_universal_source()?),
41+
&mut Some(target.into()),
42+
&mut Some(at_target_xcm),
43+
)
44+
.map_err(|e| anyhow::format_err!("Failed to prepare outbound message: {:?}", e))?
45+
.0
46+
.1
47+
.0)
48+
}
49+
2550
fn encode_execute_xcm(
2651
message: xcm::VersionedXcm<Self::Call>,
2752
) -> anyhow::Result<EncodedOrDecodedCall<Self::Call>> {

relays/bin-substrate/src/chains/rialto.rs

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,34 @@
1717
//! Rialto chain specification for CLI.
1818
1919
use crate::cli::{encode_message::CliEncodeMessage, CliChain};
20-
use bp_runtime::EncodedOrDecodedCall;
20+
use bp_runtime::{ChainId, EncodedOrDecodedCall, MILLAU_CHAIN_ID};
21+
use bridge_runtime_common::CustomNetworkId;
2122
use relay_rialto_client::Rialto;
2223
use relay_substrate_client::SimpleRuntimeVersion;
24+
use xcm_executor::traits::ExportXcm;
2325

2426
impl CliEncodeMessage for Rialto {
27+
fn encode_wire_message(
28+
target: ChainId,
29+
at_target_xcm: xcm::v3::Xcm<()>,
30+
) -> anyhow::Result<Vec<u8>> {
31+
let target = match target {
32+
MILLAU_CHAIN_ID => CustomNetworkId::Millau.as_network_id(),
33+
_ => return Err(anyhow::format_err!("Unsupported target chian: {:?}", target)),
34+
};
35+
36+
Ok(rialto_runtime::millau_messages::ToMillauBlobExporter::validate(
37+
target,
38+
0,
39+
&mut Some(Self::dummy_universal_source()?),
40+
&mut Some(target.into()),
41+
&mut Some(at_target_xcm),
42+
)
43+
.map_err(|e| anyhow::format_err!("Failed to prepare outbound message: {:?}", e))?
44+
.0
45+
.0)
46+
}
47+
2548
fn encode_execute_xcm(
2649
message: xcm::VersionedXcm<Self::Call>,
2750
) -> anyhow::Result<EncodedOrDecodedCall<Self::Call>> {

relays/bin-substrate/src/chains/rialto_parachain.rs

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,34 @@
1717
//! Rialto parachain specification for CLI.
1818
1919
use crate::cli::{encode_message::CliEncodeMessage, CliChain};
20-
use bp_runtime::EncodedOrDecodedCall;
20+
use bp_runtime::{ChainId, EncodedOrDecodedCall, MILLAU_CHAIN_ID};
21+
use bridge_runtime_common::CustomNetworkId;
2122
use relay_rialto_parachain_client::RialtoParachain;
2223
use relay_substrate_client::SimpleRuntimeVersion;
24+
use xcm_executor::traits::ExportXcm;
2325

2426
impl CliEncodeMessage for RialtoParachain {
27+
fn encode_wire_message(
28+
target: ChainId,
29+
at_target_xcm: xcm::v3::Xcm<()>,
30+
) -> anyhow::Result<Vec<u8>> {
31+
let target = match target {
32+
MILLAU_CHAIN_ID => CustomNetworkId::Millau.as_network_id(),
33+
_ => return Err(anyhow::format_err!("Unsupported target chain: {:?}", target)),
34+
};
35+
36+
Ok(rialto_parachain_runtime::millau_messages::ToMillauBlobExporter::validate(
37+
target,
38+
0,
39+
&mut Some(Self::dummy_universal_source()?),
40+
&mut Some(target.into()),
41+
&mut Some(at_target_xcm),
42+
)
43+
.map_err(|e| anyhow::format_err!("Failed to prepare outbound message: {:?}", e))?
44+
.0
45+
.0)
46+
}
47+
2548
fn encode_execute_xcm(
2649
message: xcm::VersionedXcm<Self::Call>,
2750
) -> anyhow::Result<EncodedOrDecodedCall<Self::Call>> {

relays/bin-substrate/src/cli/encode_message.rs

Lines changed: 69 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,13 @@
1515
// along with Parity Bridges Common. If not, see <http://www.gnu.org/licenses/>.
1616

1717
use crate::cli::{ExplicitOrMaximal, HexBytes};
18-
use bp_runtime::EncodedOrDecodedCall;
18+
use bp_runtime::{ChainId, EncodedOrDecodedCall};
19+
use bridge_runtime_common::CustomNetworkId;
1920
use codec::Encode;
2021
use frame_support::weights::Weight;
2122
use relay_substrate_client::Chain;
2223
use structopt::StructOpt;
24+
use xcm::latest::prelude::*;
2325

2426
/// All possible messages that may be delivered to generic Substrate chain.
2527
///
@@ -43,6 +45,31 @@ pub enum Message {
4345
pub type RawMessage = Vec<u8>;
4446

4547
pub trait CliEncodeMessage: Chain {
48+
/// Returns dummy `AccountId32` universal source given this network id.
49+
fn dummy_universal_source() -> anyhow::Result<xcm::v3::Junctions> {
50+
use xcm::v3::prelude::*;
51+
52+
let this_network = CustomNetworkId::try_from(Self::ID)
53+
.map(|n| n.as_network_id())
54+
.map_err(|_| anyhow::format_err!("Unsupported chain: {:?}", Self::ID))?;
55+
let this_location: InteriorMultiLocation = this_network.into();
56+
57+
let origin = MultiLocation {
58+
parents: 0,
59+
interior: X1(AccountId32 { network: Some(this_network), id: [0u8; 32] }),
60+
};
61+
let universal_source = this_location
62+
.within_global(origin)
63+
.map_err(|e| anyhow::format_err!("Invalid location: {:?}", e))?;
64+
65+
Ok(universal_source)
66+
}
67+
/// Returns XCM blob that is passed to the `send_message` function of the messages pallet
68+
/// and then is sent over the wire.
69+
fn encode_wire_message(
70+
target: ChainId,
71+
at_target_xcm: xcm::v3::Xcm<()>,
72+
) -> anyhow::Result<Vec<u8>>;
4673
/// Encode an `execute` XCM call of the XCM pallet.
4774
fn encode_execute_xcm(
4875
message: xcm::VersionedXcm<Self::Call>,
@@ -56,41 +83,42 @@ pub trait CliEncodeMessage: Chain {
5683
}
5784

5885
/// Encode message payload passed through CLI flags.
59-
pub(crate) fn encode_message<Source: Chain, Target: Chain>(
86+
pub(crate) fn encode_message<Source: CliEncodeMessage, Target: Chain>(
6087
message: &Message,
6188
) -> anyhow::Result<RawMessage> {
6289
Ok(match message {
6390
Message::Raw { ref data } => data.0.clone(),
6491
Message::Sized { ref size } => {
65-
let expected_xcm_size = match *size {
92+
let destination = CustomNetworkId::try_from(Target::ID)
93+
.map(|n| n.as_network_id())
94+
.map_err(|_| anyhow::format_err!("Unsupported target chain: {:?}", Target::ID))?;
95+
let expected_size = match *size {
6696
ExplicitOrMaximal::Explicit(size) => size,
6797
ExplicitOrMaximal::Maximal => compute_maximal_message_size(
6898
Source::max_extrinsic_size(),
6999
Target::max_extrinsic_size(),
70100
),
71-
};
72-
73-
// there's no way to craft XCM of the given size - we'll be using `ExpectPallet`
74-
// instruction, which has byte vector inside
75-
let mut current_vec_size = expected_xcm_size;
76-
let xcm = loop {
77-
let xcm = xcm::VersionedXcm::<()>::V3(
78-
vec![xcm::v3::Instruction::ExpectPallet {
79-
index: 0,
80-
name: vec![42; current_vec_size as usize],
81-
module_name: vec![],
82-
crate_major: 0,
83-
min_crate_minor: 0,
84-
}]
85-
.into(),
86-
);
87-
if xcm.encode().len() <= expected_xcm_size as usize {
88-
break xcm
89-
}
90-
91-
current_vec_size -= 1;
92-
};
93-
xcm.encode()
101+
} as usize;
102+
103+
let at_target_xcm = vec![xcm::v3::Instruction::ClearOrigin; expected_size].into();
104+
let at_target_xcm_size =
105+
Source::encode_wire_message(Target::ID, at_target_xcm)?.encoded_size();
106+
let at_target_xcm_overhead = at_target_xcm_size.saturating_sub(expected_size);
107+
let at_target_xcm = vec![
108+
xcm::v3::Instruction::ClearOrigin;
109+
expected_size.saturating_sub(at_target_xcm_overhead)
110+
]
111+
.into();
112+
113+
xcm::VersionedXcm::<()>::V3(
114+
vec![ExportMessage {
115+
network: destination,
116+
destination: destination.into(),
117+
xcm: at_target_xcm,
118+
}]
119+
.into(),
120+
)
121+
.encode()
94122
},
95123
})
96124
}
@@ -123,13 +151,21 @@ mod tests {
123151
use relay_millau_client::Millau;
124152
use relay_rialto_client::Rialto;
125153

154+
fn approximate_message_size<Source: CliEncodeMessage>(xcm_msg_len: usize) -> usize {
155+
xcm_msg_len + Source::dummy_universal_source().unwrap().encoded_size()
156+
}
157+
126158
#[test]
127159
fn encode_explicit_size_message_works() {
128160
let msg = encode_message::<Rialto, Millau>(&Message::Sized {
129161
size: ExplicitOrMaximal::Explicit(100),
130162
})
131163
.unwrap();
132-
assert_eq!(msg.len(), 100);
164+
// since it isn't the returned XCM what is sent over the wire, we can only check if
165+
// it is close to what we need
166+
assert!(
167+
(1f64 - (approximate_message_size::<Rialto>(msg.len()) as f64) / 100_f64).abs() < 0.1
168+
);
133169
// check that it decodes to valid xcm
134170
let _ = decode_xcm::<()>(msg).unwrap();
135171
}
@@ -144,7 +180,12 @@ mod tests {
144180
let msg =
145181
encode_message::<Rialto, Millau>(&Message::Sized { size: ExplicitOrMaximal::Maximal })
146182
.unwrap();
147-
assert_eq!(msg.len(), maximal_size as usize);
183+
// since it isn't the returned XCM what is sent over the wire, we can only check if
184+
// it is close to what we need
185+
assert!(
186+
(1f64 - approximate_message_size::<Rialto>(msg.len()) as f64 / maximal_size as f64)
187+
.abs() < 0.1
188+
);
148189
// check that it decodes to valid xcm
149190
let _ = decode_xcm::<()>(msg).unwrap();
150191
}

0 commit comments

Comments
 (0)