Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
only refund if all bundled messages have been delivered
  • Loading branch information
svyatonik committed Apr 4, 2023
commit 76f07f262c3906fa1436b6d4416816f84ac7d7a7
17 changes: 12 additions & 5 deletions bin/runtime-common/src/messages_call_ext.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,11 @@ use sp_runtime::transaction_validity::TransactionValidity;
/// Generic info about a messages delivery/confirmation proof.
#[derive(PartialEq, RuntimeDebug)]
pub struct BaseMessagesProofInfo {
/// Message lane, used by the call.
pub lane_id: LaneId,
/// Nonce of the best message, included in the call.
pub best_bundled_nonce: MessageNonce,
/// Nonce of the best message, stored by this chain before the call is dispatched.
pub best_stored_nonce: MessageNonce,
}

Expand Down Expand Up @@ -58,19 +61,23 @@ pub struct CallHelper<T: Config<I>, I: 'static> {
}

impl<T: Config<I>, I: 'static> CallHelper<T, I> {
/// Check if a call delivered proof/confirmation for at least some of the messages that it
/// contained.
pub fn was_partially_successful(info: &CallInfo) -> bool {
/// Returns true if:
///
/// - call is `receive_messages_proof` and all messages have been delivered;
///
/// - call is `receive_messages_delivery_proof` and all messages confirmations have been
/// received.
pub fn was_successful(info: &CallInfo) -> bool {
match info {
CallInfo::ReceiveMessagesProof(info) => {
let inbound_lane_data =
pallet_bridge_messages::InboundLanes::<T, I>::get(info.0.lane_id);
inbound_lane_data.last_delivered_nonce() > info.0.best_stored_nonce
inbound_lane_data.last_delivered_nonce() == info.0.best_bundled_nonce
},
CallInfo::ReceiveMessagesDeliveryProof(info) => {
let outbound_lane_data =
pallet_bridge_messages::OutboundLanes::<T, I>::get(info.0.lane_id);
outbound_lane_data.latest_received_nonce > info.0.best_stored_nonce
outbound_lane_data.latest_received_nonce == info.0.best_bundled_nonce
},
}
}
Expand Down
59 changes: 56 additions & 3 deletions bin/runtime-common/src/refund_relayer_extension.rs
Original file line number Diff line number Diff line change
Expand Up @@ -344,6 +344,16 @@ where
finality_proof_info.block_number,
) {
// we only refund relayer if all calls have updated chain state
log::trace!(
target: "runtime::bridge",
"{} from parachain {} via {:?}: failed to refund relayer {:?}, because \
relay chain finality proof has not been accepted",
Self::IDENTIFIER,
Para::Id::get(),
Msgs::Id::get(),
relayer,
);

return Ok(())
}

Expand All @@ -366,15 +376,34 @@ where
para_proof_info,
) {
// we only refund relayer if all calls have updated chain state
log::trace!(
target: "runtime::bridge",
"{} from parachain {} via {:?}: failed to refund relayer {:?}, because \
parachain finality proof has not been accepted",
Self::IDENTIFIER,
Para::Id::get(),
Msgs::Id::get(),
relayer,
);

return Ok(())
}
}

// Check if the `ReceiveMessagesProof` call delivered at least some of the messages that
// Check if the `ReceiveMessagesProof` call delivered all the messages that
// it contained. If this happens, we consider the transaction "helpful" and refund it.
let msgs_call_info = call_info.messages_call_info();
if !MessagesCallHelper::<Runtime, Msgs::Instance>::was_partially_successful(msgs_call_info)
{
if !MessagesCallHelper::<Runtime, Msgs::Instance>::was_successful(msgs_call_info) {
log::trace!(
target: "runtime::bridge",
"{} from parachain {} via {:?}: failed to refund relayer {:?}, because \
some of messages have not been accepted",
Self::IDENTIFIER,
Para::Id::get(),
Msgs::Id::get(),
relayer,
);

return Ok(())
}

Expand Down Expand Up @@ -1032,6 +1061,30 @@ mod tests {
});
}

#[test]
fn post_dispatch_ignores_transaction_that_has_not_delivered_all_messages() {
run_test(|| {
initialize_environment(200, 200, Default::default(), 150);

assert_storage_noop!(run_post_dispatch(Some(all_finality_pre_dispatch_data()), Ok(())));
assert_storage_noop!(run_post_dispatch(
Some(parachain_finality_pre_dispatch_data()),
Ok(())
));
assert_storage_noop!(run_post_dispatch(Some(delivery_pre_dispatch_data()), Ok(())));

assert_storage_noop!(run_post_dispatch(
Some(all_finality_confirmation_pre_dispatch_data()),
Ok(())
));
assert_storage_noop!(run_post_dispatch(
Some(parachain_finality_confirmation_pre_dispatch_data()),
Ok(())
));
assert_storage_noop!(run_post_dispatch(Some(confirmation_pre_dispatch_data()), Ok(())));
});
}

#[test]
fn post_dispatch_refunds_relayer_in_all_finality_batch_with_extra_weight() {
run_test(|| {
Expand Down