mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-05-30 22:11:02 +00:00
Signed extension for rejecting obsolete messages pallet transactions (#1446)
* BridgeRejectObsoleteMessages * add obsolete confirmations verification to the BridgeRejectObsoleteMessages * move tests where they belong
This commit is contained in:
committed by
Bastian Köcher
parent
ee5b692f72
commit
19c73ce0b7
@@ -67,6 +67,9 @@ use sp_std::prelude::*;
|
|||||||
use sp_version::NativeVersion;
|
use sp_version::NativeVersion;
|
||||||
use sp_version::RuntimeVersion;
|
use sp_version::RuntimeVersion;
|
||||||
|
|
||||||
|
// to be able to use Millau runtime in `bridge-runtime-common` tests
|
||||||
|
pub use bridge_runtime_common;
|
||||||
|
|
||||||
// A few exports that help ease life for downstream crates.
|
// A few exports that help ease life for downstream crates.
|
||||||
pub use frame_support::{
|
pub use frame_support::{
|
||||||
construct_runtime, parameter_types,
|
construct_runtime, parameter_types,
|
||||||
@@ -570,6 +573,12 @@ pallet_bridge_parachains::declare_bridge_reject_obsolete_parachain_header! {
|
|||||||
Call::BridgeRialtoParachains => WithRialtoParachainsInstance
|
Call::BridgeRialtoParachains => WithRialtoParachainsInstance
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bridge_runtime_common::declare_bridge_reject_obsolete_messages! {
|
||||||
|
Runtime,
|
||||||
|
Call::BridgeRialtoMessages => WithRialtoMessagesInstance,
|
||||||
|
Call::BridgeRialtoParachainMessages => WithRialtoParachainMessagesInstance
|
||||||
|
}
|
||||||
|
|
||||||
/// The address format for describing accounts.
|
/// The address format for describing accounts.
|
||||||
pub type Address = AccountId;
|
pub type Address = AccountId;
|
||||||
/// Block header type as expected by this runtime.
|
/// Block header type as expected by this runtime.
|
||||||
@@ -592,6 +601,7 @@ pub type SignedExtra = (
|
|||||||
pallet_transaction_payment::ChargeTransactionPayment<Runtime>,
|
pallet_transaction_payment::ChargeTransactionPayment<Runtime>,
|
||||||
BridgeRejectObsoleteGrandpaHeader,
|
BridgeRejectObsoleteGrandpaHeader,
|
||||||
BridgeRejectObsoleteParachainHeader,
|
BridgeRejectObsoleteParachainHeader,
|
||||||
|
BridgeRejectObsoleteMessages,
|
||||||
);
|
);
|
||||||
/// The payload being signed in transactions.
|
/// The payload being signed in transactions.
|
||||||
pub type SignedPayload = generic::SignedPayload<Call, SignedExtra>;
|
pub type SignedPayload = generic::SignedPayload<Call, SignedExtra>;
|
||||||
|
|||||||
@@ -46,6 +46,9 @@ xcm = { git = "https://github.com/paritytech/polkadot", branch = "gav-xcm-v3", d
|
|||||||
xcm-builder = { git = "https://github.com/paritytech/polkadot", branch = "gav-xcm-v3", default-features = false }
|
xcm-builder = { git = "https://github.com/paritytech/polkadot", branch = "gav-xcm-v3", default-features = false }
|
||||||
xcm-executor = { git = "https://github.com/paritytech/polkadot", branch = "gav-xcm-v3", default-features = false }
|
xcm-executor = { git = "https://github.com/paritytech/polkadot", branch = "gav-xcm-v3", default-features = false }
|
||||||
|
|
||||||
|
[dev-dependencies]
|
||||||
|
millau-runtime = { path = "../millau/runtime" }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["std"]
|
default = ["std"]
|
||||||
std = [
|
std = [
|
||||||
|
|||||||
@@ -21,6 +21,7 @@
|
|||||||
pub mod messages;
|
pub mod messages;
|
||||||
pub mod messages_api;
|
pub mod messages_api;
|
||||||
pub mod messages_benchmarking;
|
pub mod messages_benchmarking;
|
||||||
|
pub mod messages_extension;
|
||||||
pub mod parachains_benchmarking;
|
pub mod parachains_benchmarking;
|
||||||
|
|
||||||
#[cfg(feature = "integrity-test")]
|
#[cfg(feature = "integrity-test")]
|
||||||
|
|||||||
@@ -197,9 +197,6 @@ pub fn transaction_payment<Balance: AtLeast32BitUnsigned + FixedPointOperand>(
|
|||||||
pub mod source {
|
pub mod source {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
/// Encoded Call of the Bridged chain. We never try to decode it on This chain.
|
|
||||||
pub type BridgedChainOpaqueCall = Vec<u8>;
|
|
||||||
|
|
||||||
/// Message payload for This -> Bridged chain messages.
|
/// Message payload for This -> Bridged chain messages.
|
||||||
pub type FromThisChainMessagePayload = Vec<u8>;
|
pub type FromThisChainMessagePayload = Vec<u8>;
|
||||||
|
|
||||||
@@ -523,6 +520,7 @@ pub mod target {
|
|||||||
pub bridged_header_hash: BridgedHeaderHash,
|
pub bridged_header_hash: BridgedHeaderHash,
|
||||||
/// A storage trie proof of messages being delivered.
|
/// A storage trie proof of messages being delivered.
|
||||||
pub storage_proof: RawStorageProof,
|
pub storage_proof: RawStorageProof,
|
||||||
|
/// Messages in this proof are sent over this lane.
|
||||||
pub lane: LaneId,
|
pub lane: LaneId,
|
||||||
/// Nonce of the first message being delivered.
|
/// Nonce of the first message being delivered.
|
||||||
pub nonces_start: MessageNonce,
|
pub nonces_start: MessageNonce,
|
||||||
|
|||||||
@@ -0,0 +1,261 @@
|
|||||||
|
// Copyright 2021 Parity Technologies (UK) Ltd.
|
||||||
|
// This file is part of Parity Bridges Common.
|
||||||
|
|
||||||
|
// Parity Bridges Common is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
|
||||||
|
// Parity Bridges Common is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Parity Bridges Common. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
/// Declares a runtime-specific `BridgeRejectObsoleteMessages` and
|
||||||
|
/// `BridgeRejectObsoleteMessageConfirmations` signed extensions.
|
||||||
|
///
|
||||||
|
/// ## Example
|
||||||
|
///
|
||||||
|
/// ```nocompile
|
||||||
|
/// bridge_runtime_common::declare_bridge_reject_obsolete_messages!{
|
||||||
|
/// Runtime,
|
||||||
|
/// Call::BridgeRialtoMessages => WithRialtoMessagesInstance,
|
||||||
|
/// Call::BridgeRialtoParachainMessages => WithRialtoParachainMessagesInstance,
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// The goal of this extension is to avoid "mining" messages delivery and delivery confirmation
|
||||||
|
/// transactions, that are delivering outdated messages/confirmations. Without that extension,
|
||||||
|
/// even honest relayers may lose their funds if there are multiple relays running and submitting
|
||||||
|
/// the same messages/confirmations.
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! declare_bridge_reject_obsolete_messages {
|
||||||
|
($runtime:ident, $($call:path => $instance:ty),*) => {
|
||||||
|
/// Transaction-with-obsolete-messages check that will reject transaction if
|
||||||
|
/// it submits obsolete messages/confirmations.
|
||||||
|
#[derive(Clone, codec::Decode, codec::Encode, Eq, PartialEq, frame_support::RuntimeDebug, scale_info::TypeInfo)]
|
||||||
|
pub struct BridgeRejectObsoleteMessages;
|
||||||
|
|
||||||
|
impl sp_runtime::traits::SignedExtension for BridgeRejectObsoleteMessages {
|
||||||
|
const IDENTIFIER: &'static str = "BridgeRejectObsoleteMessages";
|
||||||
|
type AccountId = <$runtime as frame_system::Config>::AccountId;
|
||||||
|
type Call = <$runtime as frame_system::Config>::Call;
|
||||||
|
type AdditionalSigned = ();
|
||||||
|
type Pre = ();
|
||||||
|
|
||||||
|
fn additional_signed(&self) -> sp_std::result::Result<
|
||||||
|
(),
|
||||||
|
sp_runtime::transaction_validity::TransactionValidityError,
|
||||||
|
> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn validate(
|
||||||
|
&self,
|
||||||
|
_who: &Self::AccountId,
|
||||||
|
call: &Self::Call,
|
||||||
|
_info: &sp_runtime::traits::DispatchInfoOf<Self::Call>,
|
||||||
|
_len: usize,
|
||||||
|
) -> sp_runtime::transaction_validity::TransactionValidity {
|
||||||
|
match *call {
|
||||||
|
$(
|
||||||
|
$call(pallet_bridge_messages::Call::<$runtime, $instance>::receive_messages_proof {
|
||||||
|
ref proof,
|
||||||
|
..
|
||||||
|
}) => {
|
||||||
|
let nonces_end = proof.nonces_end;
|
||||||
|
|
||||||
|
let inbound_lane_data = pallet_bridge_messages::InboundLanes::<$runtime, $instance>::get(&proof.lane);
|
||||||
|
if proof.nonces_end <= inbound_lane_data.last_delivered_nonce() {
|
||||||
|
return sp_runtime::transaction_validity::InvalidTransaction::Stale.into();
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(sp_runtime::transaction_validity::ValidTransaction::default())
|
||||||
|
},
|
||||||
|
$call(pallet_bridge_messages::Call::<$runtime, $instance>::receive_messages_delivery_proof {
|
||||||
|
ref proof,
|
||||||
|
ref relayers_state,
|
||||||
|
..
|
||||||
|
}) => {
|
||||||
|
let latest_delivered_nonce = relayers_state.last_delivered_nonce;
|
||||||
|
|
||||||
|
let outbound_lane_data = pallet_bridge_messages::OutboundLanes::<$runtime, $instance>::get(&proof.lane);
|
||||||
|
if latest_delivered_nonce <= outbound_lane_data.latest_received_nonce {
|
||||||
|
return sp_runtime::transaction_validity::InvalidTransaction::Stale.into();
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(sp_runtime::transaction_validity::ValidTransaction::default())
|
||||||
|
}
|
||||||
|
)*
|
||||||
|
_ => Ok(sp_runtime::transaction_validity::ValidTransaction::default()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn pre_dispatch(
|
||||||
|
self,
|
||||||
|
who: &Self::AccountId,
|
||||||
|
call: &Self::Call,
|
||||||
|
info: &sp_runtime::traits::DispatchInfoOf<Self::Call>,
|
||||||
|
len: usize,
|
||||||
|
) -> Result<Self::Pre, sp_runtime::transaction_validity::TransactionValidityError> {
|
||||||
|
self.validate(who, call, info, len).map(drop)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn post_dispatch(
|
||||||
|
_maybe_pre: Option<Self::Pre>,
|
||||||
|
_info: &sp_runtime::traits::DispatchInfoOf<Self::Call>,
|
||||||
|
_post_info: &sp_runtime::traits::PostDispatchInfoOf<Self::Call>,
|
||||||
|
_len: usize,
|
||||||
|
_result: &sp_runtime::DispatchResult,
|
||||||
|
) -> Result<(), sp_runtime::transaction_validity::TransactionValidityError> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use bp_messages::UnrewardedRelayersState;
|
||||||
|
use frame_support::weights::{DispatchClass, DispatchInfo, Pays};
|
||||||
|
use millau_runtime::{
|
||||||
|
bridge_runtime_common::messages::{
|
||||||
|
source::FromBridgedChainMessagesDeliveryProof, target::FromBridgedChainMessagesProof,
|
||||||
|
},
|
||||||
|
BridgeRejectObsoleteMessages, Call, Runtime, WithRialtoMessagesInstance,
|
||||||
|
};
|
||||||
|
use sp_runtime::traits::SignedExtension;
|
||||||
|
|
||||||
|
fn deliver_message_10() {
|
||||||
|
pallet_bridge_messages::InboundLanes::<Runtime, WithRialtoMessagesInstance>::insert(
|
||||||
|
[0, 0, 0, 0],
|
||||||
|
bp_messages::InboundLaneData { relayers: Default::default(), last_confirmed_nonce: 10 },
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn validate_message_delivery(
|
||||||
|
nonces_start: bp_messages::MessageNonce,
|
||||||
|
nonces_end: bp_messages::MessageNonce,
|
||||||
|
) -> bool {
|
||||||
|
BridgeRejectObsoleteMessages
|
||||||
|
.validate(
|
||||||
|
&[0u8; 32].into(),
|
||||||
|
&Call::BridgeRialtoMessages(pallet_bridge_messages::Call::<
|
||||||
|
Runtime,
|
||||||
|
WithRialtoMessagesInstance,
|
||||||
|
>::receive_messages_proof {
|
||||||
|
relayer_id_at_bridged_chain: [0u8; 32].into(),
|
||||||
|
messages_count: (nonces_end - nonces_start + 1) as u32,
|
||||||
|
dispatch_weight: 0,
|
||||||
|
proof: FromBridgedChainMessagesProof {
|
||||||
|
bridged_header_hash: Default::default(),
|
||||||
|
storage_proof: vec![],
|
||||||
|
lane: [0, 0, 0, 0],
|
||||||
|
nonces_start,
|
||||||
|
nonces_end,
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
&DispatchInfo { weight: 0, class: DispatchClass::Operational, pays_fee: Pays::Yes },
|
||||||
|
0,
|
||||||
|
)
|
||||||
|
.is_ok()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn extension_rejects_obsolete_messages() {
|
||||||
|
sp_io::TestExternalities::new(Default::default()).execute_with(|| {
|
||||||
|
// when current best delivered is message#10 and we're trying to deliver message#5 => tx
|
||||||
|
// is rejected
|
||||||
|
deliver_message_10();
|
||||||
|
assert!(!validate_message_delivery(8, 9));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn extension_rejects_same_message() {
|
||||||
|
sp_io::TestExternalities::new(Default::default()).execute_with(|| {
|
||||||
|
// when current best delivered is message#10 and we're trying to import message#10 => tx
|
||||||
|
// is rejected
|
||||||
|
deliver_message_10();
|
||||||
|
assert!(!validate_message_delivery(8, 10));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn extension_accepts_new_message() {
|
||||||
|
sp_io::TestExternalities::new(Default::default()).execute_with(|| {
|
||||||
|
// when current best delivered is message#10 and we're trying to deliver message#15 =>
|
||||||
|
// tx is accepted
|
||||||
|
deliver_message_10();
|
||||||
|
assert!(validate_message_delivery(10, 15));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
fn confirm_message_10() {
|
||||||
|
pallet_bridge_messages::OutboundLanes::<Runtime, WithRialtoMessagesInstance>::insert(
|
||||||
|
[0, 0, 0, 0],
|
||||||
|
bp_messages::OutboundLaneData {
|
||||||
|
oldest_unpruned_nonce: 0,
|
||||||
|
latest_received_nonce: 10,
|
||||||
|
latest_generated_nonce: 10,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn validate_message_confirmation(last_delivered_nonce: bp_messages::MessageNonce) -> bool {
|
||||||
|
BridgeRejectObsoleteMessages
|
||||||
|
.validate(
|
||||||
|
&[0u8; 32].into(),
|
||||||
|
&Call::BridgeRialtoMessages(pallet_bridge_messages::Call::<
|
||||||
|
Runtime,
|
||||||
|
WithRialtoMessagesInstance,
|
||||||
|
>::receive_messages_delivery_proof {
|
||||||
|
proof: FromBridgedChainMessagesDeliveryProof {
|
||||||
|
bridged_header_hash: Default::default(),
|
||||||
|
storage_proof: Vec::new(),
|
||||||
|
lane: [0, 0, 0, 0],
|
||||||
|
},
|
||||||
|
relayers_state: UnrewardedRelayersState {
|
||||||
|
last_delivered_nonce,
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
&DispatchInfo { weight: 0, class: DispatchClass::Operational, pays_fee: Pays::Yes },
|
||||||
|
0,
|
||||||
|
)
|
||||||
|
.is_ok()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn extension_rejects_obsolete_confirmations() {
|
||||||
|
sp_io::TestExternalities::new(Default::default()).execute_with(|| {
|
||||||
|
// when current best confirmed is message#10 and we're trying to confirm message#5 => tx
|
||||||
|
// is rejected
|
||||||
|
confirm_message_10();
|
||||||
|
assert!(!validate_message_confirmation(5));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn extension_rejects_same_confirmation() {
|
||||||
|
sp_io::TestExternalities::new(Default::default()).execute_with(|| {
|
||||||
|
// when current best confirmed is message#10 and we're trying to confirm message#10 =>
|
||||||
|
// tx is rejected
|
||||||
|
confirm_message_10();
|
||||||
|
assert!(!validate_message_confirmation(10));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn extension_accepts_new_confirmation() {
|
||||||
|
sp_io::TestExternalities::new(Default::default()).execute_with(|| {
|
||||||
|
// when current best confirmed is message#10 and we're trying to confirm message#15 =>
|
||||||
|
// tx is accepted
|
||||||
|
confirm_message_10();
|
||||||
|
assert!(validate_message_confirmation(15));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -493,6 +493,7 @@ benchmarks_instance_pallet! {
|
|||||||
unrewarded_relayer_entries: 1,
|
unrewarded_relayer_entries: 1,
|
||||||
messages_in_oldest_entry: 1,
|
messages_in_oldest_entry: 1,
|
||||||
total_messages: 1,
|
total_messages: 1,
|
||||||
|
last_delivered_nonce: 1,
|
||||||
};
|
};
|
||||||
let proof = T::prepare_message_delivery_proof(MessageDeliveryProofParams {
|
let proof = T::prepare_message_delivery_proof(MessageDeliveryProofParams {
|
||||||
lane: T::bench_lane_id(),
|
lane: T::bench_lane_id(),
|
||||||
@@ -534,6 +535,7 @@ benchmarks_instance_pallet! {
|
|||||||
unrewarded_relayer_entries: 1,
|
unrewarded_relayer_entries: 1,
|
||||||
messages_in_oldest_entry: 2,
|
messages_in_oldest_entry: 2,
|
||||||
total_messages: 2,
|
total_messages: 2,
|
||||||
|
last_delivered_nonce: 2,
|
||||||
};
|
};
|
||||||
let mut delivered_messages = DeliveredMessages::new(1, true);
|
let mut delivered_messages = DeliveredMessages::new(1, true);
|
||||||
delivered_messages.note_dispatched_message(true);
|
delivered_messages.note_dispatched_message(true);
|
||||||
@@ -576,6 +578,7 @@ benchmarks_instance_pallet! {
|
|||||||
unrewarded_relayer_entries: 2,
|
unrewarded_relayer_entries: 2,
|
||||||
messages_in_oldest_entry: 1,
|
messages_in_oldest_entry: 1,
|
||||||
total_messages: 2,
|
total_messages: 2,
|
||||||
|
last_delivered_nonce: 2,
|
||||||
};
|
};
|
||||||
let proof = T::prepare_message_delivery_proof(MessageDeliveryProofParams {
|
let proof = T::prepare_message_delivery_proof(MessageDeliveryProofParams {
|
||||||
lane: T::bench_lane_id(),
|
lane: T::bench_lane_id(),
|
||||||
|
|||||||
@@ -554,6 +554,12 @@ pub mod pallet {
|
|||||||
relayers_state.unrewarded_relayer_entries,
|
relayers_state.unrewarded_relayer_entries,
|
||||||
Error::<T, I>::InvalidUnrewardedRelayersState
|
Error::<T, I>::InvalidUnrewardedRelayersState
|
||||||
);
|
);
|
||||||
|
// the `last_delivered_nonce` field may also be used by the signed extension. Even
|
||||||
|
// though providing wrong value isn't critical, let's also check it here.
|
||||||
|
ensure!(
|
||||||
|
lane_data.last_delivered_nonce() == relayers_state.last_delivered_nonce,
|
||||||
|
Error::<T, I>::InvalidUnrewardedRelayersState
|
||||||
|
);
|
||||||
|
|
||||||
// mark messages as delivered
|
// mark messages as delivered
|
||||||
let mut lane = outbound_lane::<T, I>(lane_id);
|
let mut lane = outbound_lane::<T, I>(lane_id);
|
||||||
@@ -1159,7 +1165,9 @@ mod tests {
|
|||||||
fn inbound_unrewarded_relayers_state(
|
fn inbound_unrewarded_relayers_state(
|
||||||
lane: bp_messages::LaneId,
|
lane: bp_messages::LaneId,
|
||||||
) -> bp_messages::UnrewardedRelayersState {
|
) -> bp_messages::UnrewardedRelayersState {
|
||||||
let relayers = InboundLanes::<TestRuntime, ()>::get(&lane).relayers;
|
let inbound_lane_data = InboundLanes::<TestRuntime, ()>::get(&lane);
|
||||||
|
let last_delivered_nonce = inbound_lane_data.last_delivered_nonce();
|
||||||
|
let relayers = inbound_lane_data.relayers;
|
||||||
bp_messages::UnrewardedRelayersState {
|
bp_messages::UnrewardedRelayersState {
|
||||||
unrewarded_relayer_entries: relayers.len() as _,
|
unrewarded_relayer_entries: relayers.len() as _,
|
||||||
messages_in_oldest_entry: relayers
|
messages_in_oldest_entry: relayers
|
||||||
@@ -1167,6 +1175,7 @@ mod tests {
|
|||||||
.map(|entry| 1 + entry.messages.end - entry.messages.begin)
|
.map(|entry| 1 + entry.messages.end - entry.messages.begin)
|
||||||
.unwrap_or(0),
|
.unwrap_or(0),
|
||||||
total_messages: total_unrewarded_messages(&relayers).unwrap_or(MessageNonce::MAX),
|
total_messages: total_unrewarded_messages(&relayers).unwrap_or(MessageNonce::MAX),
|
||||||
|
last_delivered_nonce,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1225,6 +1234,7 @@ mod tests {
|
|||||||
UnrewardedRelayersState {
|
UnrewardedRelayersState {
|
||||||
unrewarded_relayer_entries: 1,
|
unrewarded_relayer_entries: 1,
|
||||||
total_messages: 1,
|
total_messages: 1,
|
||||||
|
last_delivered_nonce: 1,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
));
|
));
|
||||||
@@ -1467,6 +1477,7 @@ mod tests {
|
|||||||
unrewarded_relayer_entries: 1,
|
unrewarded_relayer_entries: 1,
|
||||||
messages_in_oldest_entry: 1,
|
messages_in_oldest_entry: 1,
|
||||||
total_messages: 1,
|
total_messages: 1,
|
||||||
|
last_delivered_nonce: 1,
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
Error::<TestRuntime, ()>::Halted,
|
Error::<TestRuntime, ()>::Halted,
|
||||||
@@ -1522,6 +1533,7 @@ mod tests {
|
|||||||
unrewarded_relayer_entries: 1,
|
unrewarded_relayer_entries: 1,
|
||||||
messages_in_oldest_entry: 1,
|
messages_in_oldest_entry: 1,
|
||||||
total_messages: 1,
|
total_messages: 1,
|
||||||
|
last_delivered_nonce: 1,
|
||||||
},
|
},
|
||||||
));
|
));
|
||||||
});
|
});
|
||||||
@@ -1619,6 +1631,7 @@ mod tests {
|
|||||||
unrewarded_relayer_entries: 2,
|
unrewarded_relayer_entries: 2,
|
||||||
messages_in_oldest_entry: 1,
|
messages_in_oldest_entry: 1,
|
||||||
total_messages: 2,
|
total_messages: 2,
|
||||||
|
last_delivered_nonce: 10,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -1654,6 +1667,7 @@ mod tests {
|
|||||||
unrewarded_relayer_entries: 2,
|
unrewarded_relayer_entries: 2,
|
||||||
messages_in_oldest_entry: 1,
|
messages_in_oldest_entry: 1,
|
||||||
total_messages: 2,
|
total_messages: 2,
|
||||||
|
last_delivered_nonce: 11,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
@@ -1749,6 +1763,7 @@ mod tests {
|
|||||||
UnrewardedRelayersState {
|
UnrewardedRelayersState {
|
||||||
unrewarded_relayer_entries: 1,
|
unrewarded_relayer_entries: 1,
|
||||||
total_messages: 1,
|
total_messages: 1,
|
||||||
|
last_delivered_nonce: 1,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
));
|
));
|
||||||
@@ -1774,6 +1789,7 @@ mod tests {
|
|||||||
UnrewardedRelayersState {
|
UnrewardedRelayersState {
|
||||||
unrewarded_relayer_entries: 2,
|
unrewarded_relayer_entries: 2,
|
||||||
total_messages: 2,
|
total_messages: 2,
|
||||||
|
last_delivered_nonce: 2,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
));
|
));
|
||||||
@@ -1818,6 +1834,7 @@ mod tests {
|
|||||||
UnrewardedRelayersState {
|
UnrewardedRelayersState {
|
||||||
unrewarded_relayer_entries: 1,
|
unrewarded_relayer_entries: 1,
|
||||||
total_messages: 2,
|
total_messages: 2,
|
||||||
|
last_delivered_nonce: 2,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
@@ -1843,6 +1860,33 @@ mod tests {
|
|||||||
UnrewardedRelayersState {
|
UnrewardedRelayersState {
|
||||||
unrewarded_relayer_entries: 2,
|
unrewarded_relayer_entries: 2,
|
||||||
total_messages: 1,
|
total_messages: 1,
|
||||||
|
last_delivered_nonce: 2,
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
),
|
||||||
|
Error::<TestRuntime, ()>::InvalidUnrewardedRelayersState,
|
||||||
|
);
|
||||||
|
|
||||||
|
// when last delivered nonce is invalid
|
||||||
|
assert_noop!(
|
||||||
|
Pallet::<TestRuntime>::receive_messages_delivery_proof(
|
||||||
|
Origin::signed(1),
|
||||||
|
TestMessagesDeliveryProof(Ok((
|
||||||
|
TEST_LANE_ID,
|
||||||
|
InboundLaneData {
|
||||||
|
relayers: vec![
|
||||||
|
unrewarded_relayer(1, 1, TEST_RELAYER_A),
|
||||||
|
unrewarded_relayer(2, 2, TEST_RELAYER_B)
|
||||||
|
]
|
||||||
|
.into_iter()
|
||||||
|
.collect(),
|
||||||
|
..Default::default()
|
||||||
|
}
|
||||||
|
))),
|
||||||
|
UnrewardedRelayersState {
|
||||||
|
unrewarded_relayer_entries: 2,
|
||||||
|
total_messages: 2,
|
||||||
|
last_delivered_nonce: 8,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
@@ -2079,6 +2123,7 @@ mod tests {
|
|||||||
UnrewardedRelayersState {
|
UnrewardedRelayersState {
|
||||||
unrewarded_relayer_entries: 1,
|
unrewarded_relayer_entries: 1,
|
||||||
total_messages: 2,
|
total_messages: 2,
|
||||||
|
last_delivered_nonce: 2,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
));
|
));
|
||||||
@@ -2089,6 +2134,7 @@ mod tests {
|
|||||||
UnrewardedRelayersState {
|
UnrewardedRelayersState {
|
||||||
unrewarded_relayer_entries: 1,
|
unrewarded_relayer_entries: 1,
|
||||||
total_messages: 1,
|
total_messages: 1,
|
||||||
|
last_delivered_nonce: 3,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
));
|
));
|
||||||
@@ -2116,6 +2162,7 @@ mod tests {
|
|||||||
let relayers_state = UnrewardedRelayersState {
|
let relayers_state = UnrewardedRelayersState {
|
||||||
unrewarded_relayer_entries: 1,
|
unrewarded_relayer_entries: 1,
|
||||||
total_messages: 3,
|
total_messages: 3,
|
||||||
|
last_delivered_nonce: 3,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
let pre_dispatch_weight =
|
let pre_dispatch_weight =
|
||||||
@@ -2190,7 +2237,7 @@ mod tests {
|
|||||||
TEST_LANE_ID,
|
TEST_LANE_ID,
|
||||||
InboundLaneData { last_confirmed_nonce: 1, relayers: Default::default() },
|
InboundLaneData { last_confirmed_nonce: 1, relayers: Default::default() },
|
||||||
))),
|
))),
|
||||||
UnrewardedRelayersState::default(),
|
UnrewardedRelayersState { last_delivered_nonce: 1, ..Default::default() },
|
||||||
),
|
),
|
||||||
Error::<TestRuntime, ()>::TryingToConfirmMoreMessagesThanExpected,
|
Error::<TestRuntime, ()>::TryingToConfirmMoreMessagesThanExpected,
|
||||||
);
|
);
|
||||||
@@ -2269,6 +2316,7 @@ mod tests {
|
|||||||
UnrewardedRelayersState {
|
UnrewardedRelayersState {
|
||||||
unrewarded_relayer_entries: 1,
|
unrewarded_relayer_entries: 1,
|
||||||
total_messages: max_messages_to_prune,
|
total_messages: max_messages_to_prune,
|
||||||
|
last_delivered_nonce: max_messages_to_prune,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
));
|
));
|
||||||
|
|||||||
@@ -289,6 +289,11 @@ pub struct UnrewardedRelayersState {
|
|||||||
pub messages_in_oldest_entry: MessageNonce,
|
pub messages_in_oldest_entry: MessageNonce,
|
||||||
/// Total number of messages in the relayers vector.
|
/// Total number of messages in the relayers vector.
|
||||||
pub total_messages: MessageNonce,
|
pub total_messages: MessageNonce,
|
||||||
|
/// Nonce of the latest message that has been delivered to the target chain.
|
||||||
|
///
|
||||||
|
/// This corresponds to the result of the `InboundLaneData::last_delivered_nonce` call
|
||||||
|
/// at the bridged chain.
|
||||||
|
pub last_delivered_nonce: MessageNonce,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Outbound lane data.
|
/// Outbound lane data.
|
||||||
|
|||||||
@@ -117,6 +117,7 @@ impl TransactionSignScheme for Millau {
|
|||||||
pallet_transaction_payment::ChargeTransactionPayment::<millau_runtime::Runtime>::from(param.unsigned.tip),
|
pallet_transaction_payment::ChargeTransactionPayment::<millau_runtime::Runtime>::from(param.unsigned.tip),
|
||||||
millau_runtime::BridgeRejectObsoleteGrandpaHeader,
|
millau_runtime::BridgeRejectObsoleteGrandpaHeader,
|
||||||
millau_runtime::BridgeRejectObsoleteParachainHeader,
|
millau_runtime::BridgeRejectObsoleteParachainHeader,
|
||||||
|
millau_runtime::BridgeRejectObsoleteMessages,
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
(),
|
(),
|
||||||
@@ -129,6 +130,7 @@ impl TransactionSignScheme for Millau {
|
|||||||
(),
|
(),
|
||||||
(),
|
(),
|
||||||
(),
|
(),
|
||||||
|
(),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
let signature = raw_payload.using_encoded(|payload| param.signer.sign(payload));
|
let signature = raw_payload.using_encoded(|payload| param.signer.sign(payload));
|
||||||
|
|||||||
@@ -474,6 +474,7 @@ fn prepare_dummy_messages_delivery_proof<SC: Chain, TC: Chain>(
|
|||||||
unrewarded_relayer_entries: 1,
|
unrewarded_relayer_entries: 1,
|
||||||
messages_in_oldest_entry: 1,
|
messages_in_oldest_entry: 1,
|
||||||
total_messages: 1,
|
total_messages: 1,
|
||||||
|
last_delivered_nonce: 1,
|
||||||
},
|
},
|
||||||
FromBridgedChainMessagesDeliveryProof {
|
FromBridgedChainMessagesDeliveryProof {
|
||||||
bridged_header_hash: Default::default(),
|
bridged_header_hash: Default::default(),
|
||||||
|
|||||||
@@ -191,11 +191,10 @@ where
|
|||||||
id: TargetHeaderIdOf<MessageLaneAdapter<P>>,
|
id: TargetHeaderIdOf<MessageLaneAdapter<P>>,
|
||||||
) -> Result<(TargetHeaderIdOf<MessageLaneAdapter<P>>, UnrewardedRelayersState), SubstrateError>
|
) -> Result<(TargetHeaderIdOf<MessageLaneAdapter<P>>, UnrewardedRelayersState), SubstrateError>
|
||||||
{
|
{
|
||||||
let relayers = self
|
let inbound_lane_data = self.inbound_lane_data(id).await?;
|
||||||
.inbound_lane_data(id)
|
let last_delivered_nonce =
|
||||||
.await?
|
inbound_lane_data.as_ref().map(|data| data.last_delivered_nonce()).unwrap_or(0);
|
||||||
.map(|data| data.relayers)
|
let relayers = inbound_lane_data.map(|data| data.relayers).unwrap_or_else(VecDeque::new);
|
||||||
.unwrap_or_else(VecDeque::new);
|
|
||||||
let unrewarded_relayers_state = bp_messages::UnrewardedRelayersState {
|
let unrewarded_relayers_state = bp_messages::UnrewardedRelayersState {
|
||||||
unrewarded_relayer_entries: relayers.len() as _,
|
unrewarded_relayer_entries: relayers.len() as _,
|
||||||
messages_in_oldest_entry: relayers
|
messages_in_oldest_entry: relayers
|
||||||
@@ -203,6 +202,7 @@ where
|
|||||||
.map(|entry| 1 + entry.messages.end - entry.messages.begin)
|
.map(|entry| 1 + entry.messages.end - entry.messages.begin)
|
||||||
.unwrap_or(0),
|
.unwrap_or(0),
|
||||||
total_messages: total_unrewarded_messages(&relayers).unwrap_or(MessageNonce::MAX),
|
total_messages: total_unrewarded_messages(&relayers).unwrap_or(MessageNonce::MAX),
|
||||||
|
last_delivered_nonce,
|
||||||
};
|
};
|
||||||
Ok((id, unrewarded_relayers_state))
|
Ok((id, unrewarded_relayers_state))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -729,6 +729,7 @@ pub(crate) mod tests {
|
|||||||
unrewarded_relayer_entries: 0,
|
unrewarded_relayer_entries: 0,
|
||||||
messages_in_oldest_entry: 0,
|
messages_in_oldest_entry: 0,
|
||||||
total_messages: 0,
|
total_messages: 0,
|
||||||
|
last_delivered_nonce: 0,
|
||||||
},
|
},
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -639,6 +639,7 @@ mod tests {
|
|||||||
unrewarded_relayer_entries: 0,
|
unrewarded_relayer_entries: 0,
|
||||||
messages_in_oldest_entry: 0,
|
messages_in_oldest_entry: 0,
|
||||||
total_messages: 0,
|
total_messages: 0,
|
||||||
|
last_delivered_nonce: 0,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
@@ -954,6 +955,7 @@ mod tests {
|
|||||||
unrewarded_relayer_entries: 2,
|
unrewarded_relayer_entries: 2,
|
||||||
messages_in_oldest_entry: 2,
|
messages_in_oldest_entry: 2,
|
||||||
total_messages: 2,
|
total_messages: 2,
|
||||||
|
last_delivered_nonce: 19,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
Reference in New Issue
Block a user