Skip to content

Commit 0b7ddae

Browse files
svyatoniktomusdrw
andauthored
pay dispatch fee at target chain (paritytech#911)
* pay dispatch fee at target chain * refund unspent dispatch weight to messages relayer * test that transfer actually happens * pay-at-target-cchain benchmarks + fix previous benchmarks (invalid signature) * include/exclude pay-dispatch-fee weight from delivery_and_dispatch_fee/delivery tx cost * remvoe some redundant traces * enum DispatchFeePayment {} * typo * update docs * (revert removal of valid check) * Update modules/messages/src/benchmarking.rs Co-authored-by: Tomasz Drwięga <[email protected]> * Update modules/messages/src/benchmarking.rs Co-authored-by: Tomasz Drwięga <[email protected]> * Update modules/messages/src/benchmarking.rs Co-authored-by: Tomasz Drwięga <[email protected]> * Update modules/messages/src/benchmarking.rs Co-authored-by: Tomasz Drwięga <[email protected]> Co-authored-by: Tomasz Drwięga <[email protected]> Co-authored-by: Tomasz Drwięga <[email protected]>
1 parent 4882bfa commit 0b7ddae

27 files changed

Lines changed: 1052 additions & 278 deletions

File tree

bridges/bin/millau/runtime/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -686,6 +686,7 @@ mod tests {
686686
bp_millau::DEFAULT_MESSAGE_DELIVERY_TX_WEIGHT,
687687
bp_millau::ADDITIONAL_MESSAGE_BYTE_DELIVERY_WEIGHT,
688688
bp_millau::MAX_SINGLE_MESSAGE_DELIVERY_CONFIRMATION_TX_WEIGHT,
689+
bp_millau::PAY_INBOUND_DISPATCH_FEE_WEIGHT,
689690
);
690691

691692
let max_incoming_message_proof_size = bp_rialto::EXTRA_STORAGE_PROOF_SIZE.saturating_add(

bridges/bin/millau/runtime/src/rialto_messages.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ type ToRialtoMessagesDeliveryProof = messages::source::FromBridgedChainMessagesD
6464
pub type FromRialtoMessageDispatch = messages::target::FromBridgedChainMessageDispatch<
6565
WithRialtoMessageBridge,
6666
crate::Runtime,
67+
pallet_balances::Pallet<Runtime>,
6768
pallet_bridge_dispatch::DefaultInstance,
6869
>;
6970

@@ -172,6 +173,7 @@ impl messages::BridgedChainWithMessages for Rialto {
172173

173174
fn estimate_delivery_transaction(
174175
message_payload: &[u8],
176+
include_pay_dispatch_fee_cost: bool,
175177
message_dispatch_weight: Weight,
176178
) -> MessageTransaction<Weight> {
177179
let message_payload_len = u32::try_from(message_payload.len()).unwrap_or(u32::MAX);
@@ -182,6 +184,11 @@ impl messages::BridgedChainWithMessages for Rialto {
182184
dispatch_weight: extra_bytes_in_payload
183185
.saturating_mul(bp_rialto::ADDITIONAL_MESSAGE_BYTE_DELIVERY_WEIGHT)
184186
.saturating_add(bp_rialto::DEFAULT_MESSAGE_DELIVERY_TX_WEIGHT)
187+
.saturating_sub(if include_pay_dispatch_fee_cost {
188+
0
189+
} else {
190+
bp_rialto::PAY_INBOUND_DISPATCH_FEE_WEIGHT
191+
})
185192
.saturating_add(message_dispatch_weight),
186193
size: message_payload_len
187194
.saturating_add(bp_millau::EXTRA_STORAGE_PROOF_SIZE)

bridges/bin/rialto/runtime/src/lib.rs

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -862,6 +862,7 @@ impl_runtime_apis! {
862862
}
863863

864864
use crate::millau_messages::{ToMillauMessagePayload, WithMillauMessageBridge};
865+
use bp_runtime::messages::DispatchFeePayment;
865866
use bridge_runtime_common::messages;
866867
use pallet_bridge_messages::benchmarking::{
867868
Pallet as MessagesBench,
@@ -905,6 +906,7 @@ impl_runtime_apis! {
905906
weight: params.size as _,
906907
origin: dispatch_origin,
907908
call: message_payload,
909+
dispatch_fee_payment: DispatchFeePayment::AtSourceChain,
908910
};
909911
(message, pallet_bridge_messages::benchmarking::MESSAGE_FEE.into())
910912
}
@@ -921,7 +923,7 @@ impl_runtime_apis! {
921923
use codec::Encode;
922924
use frame_support::weights::GetDispatchInfo;
923925
use pallet_bridge_messages::storage_keys;
924-
use sp_runtime::traits::Header;
926+
use sp_runtime::traits::{Header, IdentifyAccount};
925927

926928
let remark = match params.size {
927929
MessagesProofSize::Minimal(ref size) => vec![0u8; *size as _],
@@ -934,12 +936,19 @@ impl_runtime_apis! {
934936
let (rialto_raw_public, rialto_raw_signature) = ed25519_sign(
935937
&call,
936938
&millau_account_id,
939+
VERSION.spec_version,
940+
bp_runtime::MILLAU_CHAIN_ID,
941+
bp_runtime::RIALTO_CHAIN_ID,
937942
);
938943
let rialto_public = MultiSigner::Ed25519(sp_core::ed25519::Public::from_raw(rialto_raw_public));
939944
let rialto_signature = MultiSignature::Ed25519(sp_core::ed25519::Signature::from_raw(
940945
rialto_raw_signature,
941946
));
942947

948+
if params.dispatch_fee_payment == DispatchFeePayment::AtTargetChain {
949+
Self::endow_account(&rialto_public.clone().into_account());
950+
}
951+
943952
let make_millau_message_key = |message_key: MessageKey| storage_keys::message_key::<
944953
Runtime,
945954
<Millau as ChainWithMessages>::MessagesInstance,
@@ -960,6 +969,7 @@ impl_runtime_apis! {
960969
Default::default(),
961970
);
962971

972+
let dispatch_fee_payment = params.dispatch_fee_payment.clone();
963973
prepare_message_proof::<WithMillauMessageBridge, bp_millau::Hasher, Runtime, (), _, _, _>(
964974
params,
965975
make_millau_message_key,
@@ -978,6 +988,7 @@ impl_runtime_apis! {
978988
rialto_public,
979989
rialto_signature,
980990
),
991+
dispatch_fee_payment,
981992
call: call.encode(),
982993
}.encode(),
983994
)
@@ -1010,6 +1021,18 @@ impl_runtime_apis! {
10101021
),
10111022
)
10121023
}
1024+
1025+
fn is_message_dispatched(nonce: bp_messages::MessageNonce) -> bool {
1026+
frame_system::Pallet::<Runtime>::events()
1027+
.into_iter()
1028+
.map(|event_record| event_record.event)
1029+
.any(|event| matches!(
1030+
event,
1031+
Event::pallet_bridge_dispatch(pallet_bridge_dispatch::Event::<Runtime, _>::MessageDispatched(
1032+
_, ([0, 0, 0, 0], nonce_from_event), _,
1033+
)) if nonce_from_event == nonce
1034+
))
1035+
}
10131036
}
10141037

10151038
add_benchmark!(
@@ -1105,6 +1128,7 @@ mod tests {
11051128
bp_rialto::DEFAULT_MESSAGE_DELIVERY_TX_WEIGHT,
11061129
bp_rialto::ADDITIONAL_MESSAGE_BYTE_DELIVERY_WEIGHT,
11071130
bp_rialto::MAX_SINGLE_MESSAGE_DELIVERY_CONFIRMATION_TX_WEIGHT,
1131+
bp_rialto::PAY_INBOUND_DISPATCH_FEE_WEIGHT,
11081132
);
11091133

11101134
let max_incoming_message_proof_size = bp_millau::EXTRA_STORAGE_PROOF_SIZE.saturating_add(

bridges/bin/rialto/runtime/src/millau_messages.rs

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ pub type FromMillauEncodedCall = messages::target::FromBridgedChainEncodedMessag
5858
pub type FromMillauMessageDispatch = messages::target::FromBridgedChainMessageDispatch<
5959
WithMillauMessageBridge,
6060
crate::Runtime,
61+
pallet_balances::Pallet<Runtime>,
6162
pallet_bridge_dispatch::DefaultInstance,
6263
>;
6364

@@ -172,6 +173,7 @@ impl messages::BridgedChainWithMessages for Millau {
172173

173174
fn estimate_delivery_transaction(
174175
message_payload: &[u8],
176+
include_pay_dispatch_fee_cost: bool,
175177
message_dispatch_weight: Weight,
176178
) -> MessageTransaction<Weight> {
177179
let message_payload_len = u32::try_from(message_payload.len()).unwrap_or(u32::MAX);
@@ -182,6 +184,11 @@ impl messages::BridgedChainWithMessages for Millau {
182184
dispatch_weight: extra_bytes_in_payload
183185
.saturating_mul(bp_millau::ADDITIONAL_MESSAGE_BYTE_DELIVERY_WEIGHT)
184186
.saturating_add(bp_millau::DEFAULT_MESSAGE_DELIVERY_TX_WEIGHT)
187+
.saturating_sub(if include_pay_dispatch_fee_cost {
188+
0
189+
} else {
190+
bp_millau::PAY_INBOUND_DISPATCH_FEE_WEIGHT
191+
})
185192
.saturating_add(message_dispatch_weight),
186193
size: message_payload_len
187194
.saturating_add(bp_rialto::EXTRA_STORAGE_PROOF_SIZE)
@@ -258,3 +265,87 @@ impl MessagesParameter for RialtoToMillauMessagesParameter {
258265
}
259266
}
260267
}
268+
269+
#[cfg(test)]
270+
mod tests {
271+
use super::*;
272+
use crate::{AccountId, Call, ExistentialDeposit, Runtime, SystemCall, SystemConfig, VERSION};
273+
use bp_message_dispatch::CallOrigin;
274+
use bp_messages::{
275+
target_chain::{DispatchMessage, DispatchMessageData, MessageDispatch},
276+
MessageKey,
277+
};
278+
use bp_runtime::{derive_account_id, messages::DispatchFeePayment, SourceAccount};
279+
use bridge_runtime_common::messages::target::{FromBridgedChainEncodedMessageCall, FromBridgedChainMessagePayload};
280+
use frame_support::{
281+
traits::Currency,
282+
weights::{GetDispatchInfo, WeightToFeePolynomial},
283+
};
284+
use sp_runtime::traits::Convert;
285+
286+
#[test]
287+
fn transfer_happens_when_dispatch_fee_is_paid_at_target_chain() {
288+
// this test actually belongs to the `bridge-runtime-common` crate, but there we have no
289+
// mock runtime. Making another one there just for this test, given that both crates
290+
// live n single repo is an overkill
291+
let mut ext: sp_io::TestExternalities = SystemConfig::default().build_storage::<Runtime>().unwrap().into();
292+
ext.execute_with(|| {
293+
let bridge = MILLAU_CHAIN_ID;
294+
let call: Call = SystemCall::remark(vec![]).into();
295+
let dispatch_weight = call.get_dispatch_info().weight;
296+
let dispatch_fee = <Runtime as pallet_transaction_payment::Config>::WeightToFee::calc(&dispatch_weight);
297+
assert!(dispatch_fee > 0);
298+
299+
// create relayer account with minimal balance
300+
let relayer_account: AccountId = [1u8; 32].into();
301+
let initial_amount = ExistentialDeposit::get();
302+
let _ = <pallet_balances::Pallet<Runtime> as Currency<AccountId>>::deposit_creating(
303+
&relayer_account,
304+
initial_amount,
305+
);
306+
307+
// create dispatch account with minimal balance + dispatch fee
308+
let dispatch_account = derive_account_id::<<Runtime as pallet_bridge_dispatch::Config>::SourceChainAccountId>(
309+
bridge,
310+
SourceAccount::Root,
311+
);
312+
let dispatch_account =
313+
<Runtime as pallet_bridge_dispatch::Config>::AccountIdConverter::convert(dispatch_account);
314+
let _ = <pallet_balances::Pallet<Runtime> as Currency<AccountId>>::deposit_creating(
315+
&dispatch_account,
316+
initial_amount + dispatch_fee,
317+
);
318+
319+
// dispatch message with intention to pay dispatch fee at the target chain
320+
FromMillauMessageDispatch::dispatch(
321+
&relayer_account,
322+
DispatchMessage {
323+
key: MessageKey {
324+
lane_id: Default::default(),
325+
nonce: 0,
326+
},
327+
data: DispatchMessageData {
328+
payload: Ok(FromBridgedChainMessagePayload::<WithMillauMessageBridge> {
329+
spec_version: VERSION.spec_version,
330+
weight: dispatch_weight,
331+
origin: CallOrigin::SourceRoot,
332+
dispatch_fee_payment: DispatchFeePayment::AtTargetChain,
333+
call: FromBridgedChainEncodedMessageCall::new(call.encode()),
334+
}),
335+
fee: 1,
336+
},
337+
},
338+
);
339+
340+
// ensure that fee has been transferred from dispatch to relayer account
341+
assert_eq!(
342+
<pallet_balances::Pallet<Runtime> as Currency<AccountId>>::free_balance(&relayer_account),
343+
initial_amount + dispatch_fee,
344+
);
345+
assert_eq!(
346+
<pallet_balances::Pallet<Runtime> as Currency<AccountId>>::free_balance(&dispatch_account),
347+
initial_amount,
348+
);
349+
});
350+
}
351+
}

bridges/bin/runtime-common/Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ pallet-bridge-messages = { path = "../../modules/messages", default-features = f
2424
# Substrate dependencies
2525

2626
frame-support = { git = "https://github.com/paritytech/substrate", branch = "master" , default-features = false }
27+
pallet-transaction-payment = { git = "https://github.com/paritytech/substrate", branch = "master" , default-features = false }
2728
sp-core = { git = "https://github.com/paritytech/substrate", branch = "master" , default-features = false }
2829
sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "master" , default-features = false }
2930
sp-state-machine = { git = "https://github.com/paritytech/substrate", branch = "master" , default-features = false, optional = true }
@@ -42,6 +43,7 @@ std = [
4243
"pallet-bridge-dispatch/std",
4344
"pallet-bridge-grandpa/std",
4445
"pallet-bridge-messages/std",
46+
"pallet-transaction-payment/std",
4547
"sp-core/std",
4648
"sp-runtime/std",
4749
"sp-state-machine/std",

bridges/bin/runtime-common/README.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,9 @@ This trait represents this chain from bridge point of view. Let's review every m
102102
have declared dispatch weight larger than 50% of the maximal bridged extrinsic weight.
103103

104104
- `MessageBridge::estimate_delivery_transaction`: you will need to return estimated dispatch weight and
105-
size of the delivery transaction that delivers a given message to the target chain.
105+
size of the delivery transaction that delivers a given message to the target chain. The transaction
106+
weight must or must not include the weight of pay-dispatch-fee operation, depending on the value
107+
of `include_pay_dispatch_fee_cost` argument.
106108

107109
- `MessageBridge::transaction_payment`: you'll need to return fee that the submitter
108110
must pay for given transaction on bridged chain. The best case is when you have the same conversion

0 commit comments

Comments
 (0)