Skip to content

Commit efa3e97

Browse files
svyatonikbkchr
authored andcommitted
Encode and estimate Rococo/Wococo/Kusama/Polkadot messages (#1322)
* encode and estimate Rococo/Wococo/Kusama/Polkadot messages * allow send-message for non-bundled chains * weight -> dispatch-weight * fmt * fix spelling
1 parent 097a284 commit efa3e97

File tree

36 files changed

+518
-241
lines changed

36 files changed

+518
-241
lines changed

bridges/primitives/polkadot-core/src/lib.rs

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
#![cfg_attr(not(feature = "std"), no_std)]
1818

1919
use bp_messages::MessageNonce;
20-
use bp_runtime::Chain;
20+
use bp_runtime::{Chain, EncodedOrDecodedCall};
2121
use frame_support::{
2222
dispatch::Dispatchable,
2323
parameter_types,
@@ -228,8 +228,12 @@ pub type SignedBlock = generic::SignedBlock<Block>;
228228
pub type Balance = u128;
229229

230230
/// Unchecked Extrinsic type.
231-
pub type UncheckedExtrinsic<Call> =
232-
generic::UncheckedExtrinsic<AccountAddress, Call, Signature, SignedExtensions<Call>>;
231+
pub type UncheckedExtrinsic<Call> = generic::UncheckedExtrinsic<
232+
AccountAddress,
233+
EncodedOrDecodedCall<Call>,
234+
Signature,
235+
SignedExtensions<Call>,
236+
>;
233237

234238
/// Account address, used by the Polkadot-like chain.
235239
pub type Address = MultiAddress<AccountId, ()>;
@@ -336,12 +340,12 @@ where
336340

337341
fn pre_dispatch(
338342
self,
339-
who: &Self::AccountId,
340-
call: &Self::Call,
341-
info: &DispatchInfoOf<Self::Call>,
342-
len: usize,
343+
_who: &Self::AccountId,
344+
_call: &Self::Call,
345+
_info: &DispatchInfoOf<Self::Call>,
346+
_len: usize,
343347
) -> Result<Self::Pre, TransactionValidityError> {
344-
Ok(self.validate(who, call, info, len).map(|_| ())?)
348+
Ok(())
345349
}
346350
}
347351

bridges/primitives/runtime/src/chain.rs

Lines changed: 64 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
// You should have received a copy of the GNU General Public License
1515
// along with Parity Bridges Common. If not, see <http://www.gnu.org/licenses/>.
1616

17+
use codec::{Decode, Encode};
1718
use frame_support::{weights::Weight, Parameter};
1819
use num_traits::{AsPrimitive, Bounded, CheckedSub, Saturating, SaturatingAdd, Zero};
1920
use sp_runtime::{
@@ -23,7 +24,69 @@ use sp_runtime::{
2324
},
2425
FixedPointOperand,
2526
};
26-
use sp_std::{convert::TryFrom, fmt::Debug, hash::Hash, str::FromStr};
27+
use sp_std::{convert::TryFrom, fmt::Debug, hash::Hash, str::FromStr, vec, vec::Vec};
28+
29+
/// Chain call, that is either SCALE-encoded, or decoded.
30+
#[derive(Debug, Clone)]
31+
pub enum EncodedOrDecodedCall<ChainCall> {
32+
/// The call that is SCALE-encoded.
33+
///
34+
/// This variant is used when we the chain runtime is not bundled with the relay, but
35+
/// we still need the represent call in some RPC calls or transactions.
36+
Encoded(Vec<u8>),
37+
/// The decoded call.
38+
Decoded(ChainCall),
39+
}
40+
41+
impl<ChainCall: Clone + Decode> EncodedOrDecodedCall<ChainCall> {
42+
/// Returns decoded call.
43+
pub fn to_decoded(&self) -> Result<ChainCall, codec::Error> {
44+
match self {
45+
Self::Encoded(ref encoded_call) =>
46+
ChainCall::decode(&mut &encoded_call[..]).map_err(Into::into),
47+
Self::Decoded(ref decoded_call) => Ok(decoded_call.clone()),
48+
}
49+
}
50+
51+
/// Converts self to decoded call.
52+
pub fn into_decoded(self) -> Result<ChainCall, codec::Error> {
53+
match self {
54+
Self::Encoded(encoded_call) =>
55+
ChainCall::decode(&mut &encoded_call[..]).map_err(Into::into),
56+
Self::Decoded(decoded_call) => Ok(decoded_call),
57+
}
58+
}
59+
}
60+
61+
impl<ChainCall> From<ChainCall> for EncodedOrDecodedCall<ChainCall> {
62+
fn from(call: ChainCall) -> EncodedOrDecodedCall<ChainCall> {
63+
EncodedOrDecodedCall::Decoded(call)
64+
}
65+
}
66+
67+
impl<ChainCall: Decode> Decode for EncodedOrDecodedCall<ChainCall> {
68+
fn decode<I: codec::Input>(input: &mut I) -> Result<Self, codec::Error> {
69+
// having encoded version is better than decoded, because decoding isn't required
70+
// everywhere and for mocked calls it may lead to **unneeded** errors
71+
match input.remaining_len()? {
72+
Some(remaining_len) => {
73+
let mut encoded_call = vec![0u8; remaining_len];
74+
input.read(&mut encoded_call)?;
75+
Ok(EncodedOrDecodedCall::Encoded(encoded_call))
76+
},
77+
None => Ok(EncodedOrDecodedCall::Decoded(ChainCall::decode(input)?)),
78+
}
79+
}
80+
}
81+
82+
impl<ChainCall: Encode> Encode for EncodedOrDecodedCall<ChainCall> {
83+
fn encode(&self) -> Vec<u8> {
84+
match *self {
85+
Self::Encoded(ref encoded_call) => encoded_call.clone(),
86+
Self::Decoded(ref decoded_call) => decoded_call.encode(),
87+
}
88+
}
89+
}
2790

2891
/// Minimal Substrate-based chain representation that may be used from no_std environment.
2992
pub trait Chain: Send + Sync + 'static {

bridges/primitives/runtime/src/lib.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,8 @@ use sp_io::hashing::blake2_256;
2525
use sp_std::{convert::TryFrom, vec, vec::Vec};
2626

2727
pub use chain::{
28-
AccountIdOf, AccountPublicOf, BalanceOf, BlockNumberOf, Chain, HashOf, HasherOf, HeaderOf,
29-
IndexOf, SignatureOf, TransactionEraOf,
28+
AccountIdOf, AccountPublicOf, BalanceOf, BlockNumberOf, Chain, EncodedOrDecodedCall, HashOf,
29+
HasherOf, HeaderOf, IndexOf, SignatureOf, TransactionEraOf,
3030
};
3131
pub use frame_support::storage::storage_prefix as storage_value_final_key;
3232
pub use storage_proof::{Error as StorageProofError, StorageProofChecker};

bridges/relays/bin-substrate/src/chains/kusama.rs

Lines changed: 52 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -14,15 +14,20 @@
1414
// You should have received a copy of the GNU General Public License
1515
// along with Parity Bridges Common. If not, see <http://www.gnu.org/licenses/>.
1616

17+
use anyhow::anyhow;
18+
use bp_message_dispatch::{CallOrigin, MessagePayload};
19+
use bp_runtime::EncodedOrDecodedCall;
1720
use codec::Decode;
1821
use frame_support::weights::{DispatchClass, DispatchInfo, Pays, Weight};
1922
use relay_kusama_client::Kusama;
2023
use sp_version::RuntimeVersion;
2124

2225
use crate::cli::{
2326
bridge,
24-
encode_call::{Call, CliEncodeCall},
25-
encode_message, CliChain,
27+
encode_call::{self, Call, CliEncodeCall},
28+
encode_message,
29+
send_message::{self, DispatchFeePayment},
30+
CliChain,
2631
};
2732

2833
/// Weight of the `system::remark` call at Kusama.
@@ -32,13 +37,15 @@ use crate::cli::{
3237
pub(crate) const SYSTEM_REMARK_CALL_WEIGHT: Weight = 2 * 1_345_000;
3338

3439
impl CliEncodeCall for Kusama {
35-
fn encode_call(call: &Call) -> anyhow::Result<Self::Call> {
40+
fn encode_call(call: &Call) -> anyhow::Result<EncodedOrDecodedCall<Self::Call>> {
3641
Ok(match call {
42+
Call::Raw { data } => EncodedOrDecodedCall::Encoded(data.0.clone()),
3743
Call::Remark { remark_payload, .. } => relay_kusama_client::runtime::Call::System(
3844
relay_kusama_client::runtime::SystemCall::remark(
3945
remark_payload.as_ref().map(|x| x.0.clone()).unwrap_or_default(),
4046
),
41-
),
47+
)
48+
.into(),
4249
Call::BridgeSendMessage { lane, payload, fee, bridge_instance_index } =>
4350
match *bridge_instance_index {
4451
bridge::KUSAMA_TO_POLKADOT_INDEX => {
@@ -48,6 +55,7 @@ impl CliEncodeCall for Kusama {
4855
lane.0, payload, fee.0,
4956
),
5057
)
58+
.into()
5159
},
5260
_ => anyhow::bail!(
5361
"Unsupported target bridge pallet with instance index: {}",
@@ -58,13 +66,11 @@ impl CliEncodeCall for Kusama {
5866
})
5967
}
6068

61-
fn get_dispatch_info(
62-
call: &relay_kusama_client::runtime::Call,
63-
) -> anyhow::Result<DispatchInfo> {
69+
fn get_dispatch_info(call: &EncodedOrDecodedCall<Self::Call>) -> anyhow::Result<DispatchInfo> {
6470
match *call {
65-
relay_kusama_client::runtime::Call::System(
71+
EncodedOrDecodedCall::Decoded(relay_kusama_client::runtime::Call::System(
6672
relay_kusama_client::runtime::SystemCall::remark(_),
67-
) => Ok(DispatchInfo {
73+
)) => Ok(DispatchInfo {
6874
weight: crate::chains::kusama::SYSTEM_REMARK_CALL_WEIGHT,
6975
class: DispatchClass::Normal,
7076
pays_fee: Pays::Yes,
@@ -78,7 +84,12 @@ impl CliChain for Kusama {
7884
const RUNTIME_VERSION: RuntimeVersion = bp_kusama::VERSION;
7985

8086
type KeyPair = sp_core::sr25519::Pair;
81-
type MessagePayload = ();
87+
type MessagePayload = MessagePayload<
88+
bp_kusama::AccountId,
89+
bp_polkadot::AccountPublic,
90+
bp_polkadot::Signature,
91+
Vec<u8>,
92+
>;
8293

8394
fn ss58_format() -> u16 {
8495
sp_core::crypto::Ss58AddressFormat::from(
@@ -88,8 +99,37 @@ impl CliChain for Kusama {
8899
}
89100

90101
fn encode_message(
91-
_message: encode_message::MessagePayload,
102+
message: encode_message::MessagePayload,
92103
) -> anyhow::Result<Self::MessagePayload> {
93-
anyhow::bail!("Sending messages from Kusama is not yet supported.")
104+
match message {
105+
encode_message::MessagePayload::Raw { data } => MessagePayload::decode(&mut &*data.0)
106+
.map_err(|e| anyhow!("Failed to decode Kusama's MessagePayload: {:?}", e)),
107+
encode_message::MessagePayload::Call { mut call, mut sender, dispatch_weight } => {
108+
type Source = Kusama;
109+
type Target = relay_polkadot_client::Polkadot;
110+
111+
sender.enforce_chain::<Source>();
112+
let spec_version = Target::RUNTIME_VERSION.spec_version;
113+
let origin = CallOrigin::SourceAccount(sender.raw_id());
114+
encode_call::preprocess_call::<Source, Target>(
115+
&mut call,
116+
bridge::KUSAMA_TO_POLKADOT_INDEX,
117+
);
118+
let call = Target::encode_call(&call)?;
119+
let dispatch_weight = dispatch_weight.map(Ok).unwrap_or_else(|| {
120+
Err(anyhow::format_err!(
121+
"Please specify dispatch weight of the encoded Polkadot call"
122+
))
123+
})?;
124+
125+
Ok(send_message::message_payload(
126+
spec_version,
127+
dispatch_weight,
128+
origin,
129+
&call,
130+
DispatchFeePayment::AtSourceChain,
131+
))
132+
},
133+
}
94134
}
95135
}

bridges/relays/bin-substrate/src/chains/kusama_messages_to_polkadot.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ pub(crate) async fn update_polkadot_to_kusama_conversion_rate(
8282
let (spec_version, transaction_version) = client.simple_runtime_version().await?;
8383
client
8484
.submit_signed_extrinsic(signer_id, move |_, transaction_nonce| {
85-
Bytes(
85+
Ok(Bytes(
8686
Kusama::sign_transaction(SignParam {
8787
spec_version,
8888
transaction_version,
@@ -96,12 +96,12 @@ pub(crate) async fn update_polkadot_to_kusama_conversion_rate(
9696
sp_runtime::FixedU128::from_float(updated_rate),
9797
)
9898
)
99-
),
99+
).into(),
100100
transaction_nonce,
101101
),
102-
})
102+
})?
103103
.encode(),
104-
)
104+
))
105105
})
106106
.await
107107
.map(drop)

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

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -25,24 +25,27 @@ use crate::cli::{
2525
};
2626
use anyhow::anyhow;
2727
use bp_message_dispatch::{CallOrigin, MessagePayload};
28+
use bp_runtime::EncodedOrDecodedCall;
2829
use codec::Decode;
2930
use frame_support::weights::{DispatchInfo, GetDispatchInfo};
3031
use relay_millau_client::Millau;
3132
use sp_version::RuntimeVersion;
3233

3334
impl CliEncodeCall for Millau {
34-
fn encode_call(call: &Call) -> anyhow::Result<Self::Call> {
35+
fn encode_call(call: &Call) -> anyhow::Result<EncodedOrDecodedCall<Self::Call>> {
3536
Ok(match call {
36-
Call::Raw { data } => Decode::decode(&mut &*data.0)?,
37+
Call::Raw { data } => Self::Call::decode(&mut &*data.0)?.into(),
3738
Call::Remark { remark_payload, .. } =>
3839
millau_runtime::Call::System(millau_runtime::SystemCall::remark {
3940
remark: remark_payload.as_ref().map(|x| x.0.clone()).unwrap_or_default(),
40-
}),
41+
})
42+
.into(),
4143
Call::Transfer { recipient, amount } =>
4244
millau_runtime::Call::Balances(millau_runtime::BalancesCall::transfer {
4345
dest: recipient.raw_id(),
4446
value: amount.cast(),
45-
}),
47+
})
48+
.into(),
4649
Call::BridgeSendMessage { lane, payload, fee, bridge_instance_index } =>
4750
match *bridge_instance_index {
4851
bridge::MILLAU_TO_RIALTO_INDEX => {
@@ -54,6 +57,7 @@ impl CliEncodeCall for Millau {
5457
delivery_and_dispatch_fee: fee.cast(),
5558
},
5659
)
60+
.into()
5761
},
5862
_ => anyhow::bail!(
5963
"Unsupported target bridge pallet with instance index: {}",
@@ -63,8 +67,8 @@ impl CliEncodeCall for Millau {
6367
})
6468
}
6569

66-
fn get_dispatch_info(call: &millau_runtime::Call) -> anyhow::Result<DispatchInfo> {
67-
Ok(call.get_dispatch_info())
70+
fn get_dispatch_info(call: &EncodedOrDecodedCall<Self::Call>) -> anyhow::Result<DispatchInfo> {
71+
Ok(call.to_decoded()?.get_dispatch_info())
6872
}
6973
}
7074

@@ -90,7 +94,7 @@ impl CliChain for Millau {
9094
match message {
9195
encode_message::MessagePayload::Raw { data } => MessagePayload::decode(&mut &*data.0)
9296
.map_err(|e| anyhow!("Failed to decode Millau's MessagePayload: {:?}", e)),
93-
encode_message::MessagePayload::Call { mut call, mut sender } => {
97+
encode_message::MessagePayload::Call { mut call, mut sender, dispatch_weight } => {
9498
type Source = Millau;
9599
type Target = relay_rialto_client::Rialto;
96100

@@ -102,11 +106,13 @@ impl CliChain for Millau {
102106
bridge::MILLAU_TO_RIALTO_INDEX,
103107
);
104108
let call = Target::encode_call(&call)?;
105-
let weight = call.get_dispatch_info().weight;
109+
let dispatch_weight = dispatch_weight.map(Ok).unwrap_or_else(|| {
110+
call.to_decoded().map(|call| call.get_dispatch_info().weight)
111+
})?;
106112

107113
Ok(send_message::message_payload(
108114
spec_version,
109-
weight,
115+
dispatch_weight,
110116
origin,
111117
&call,
112118
DispatchFeePayment::AtSourceChain,

bridges/relays/bin-substrate/src/chains/millau_messages_to_rialto.rs

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -74,25 +74,24 @@ pub(crate) async fn update_rialto_to_millau_conversion_rate(
7474
let (spec_version, transaction_version) = client.simple_runtime_version().await?;
7575
client
7676
.submit_signed_extrinsic(signer_id, move |_, transaction_nonce| {
77-
Bytes(
77+
Ok(Bytes(
7878
Millau::sign_transaction(SignParam {
7979
spec_version,
8080
transaction_version,
8181
genesis_hash,
8282
signer,
8383
era: relay_substrate_client::TransactionEra::immortal(),
8484
unsigned: UnsignedTransaction::new(
85-
millau_runtime::MessagesCall::update_pallet_parameter {
85+
millau_runtime::Call::from(millau_runtime::MessagesCall::update_pallet_parameter {
8686
parameter: millau_runtime::rialto_messages::MillauToRialtoMessagesParameter::RialtoToMillauConversionRate(
8787
sp_runtime::FixedU128::from_float(updated_rate),
8888
),
89-
}
90-
.into(),
89+
}).into(),
9190
transaction_nonce,
9291
),
93-
})
92+
})?
9493
.encode(),
95-
)
94+
))
9695
})
9796
.await
9897
.map(drop)

0 commit comments

Comments
 (0)