Skip to content

Commit

Permalink
Add state to message lanes (#2214)
Browse files Browse the repository at this point in the history
* add LaneState enum and a field to lanes data

* use OptionQuery in InboundLanes and OutboundLanes

* ensure that lanes are opened when accessing them

* an option to specify opened lanes in genesis config + fixed tests

* added PR reference to TODO

* fix failing benchmarks

* spelling

* get_or_init_data -> data

bump Substrate, Polkadot and Cumulus (#2223)
  • Loading branch information
svyatonik authored and bkontur committed Jul 23, 2024
1 parent 6531755 commit 169a487
Show file tree
Hide file tree
Showing 17 changed files with 476 additions and 202 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -943,7 +943,7 @@ pub(crate) mod tests {
use bp_header_chain::StoredHeaderDataBuilder;
use bp_messages::{
source_chain::FromBridgedChainMessagesDeliveryProof,
target_chain::FromBridgedChainMessagesProof, DeliveredMessages, InboundLaneData,
target_chain::FromBridgedChainMessagesProof, DeliveredMessages, InboundLaneData, LaneState,
MessageNonce, MessagesOperatingMode, OutboundLaneData, UnrewardedRelayer,
UnrewardedRelayersState,
};
Expand Down Expand Up @@ -1149,6 +1149,7 @@ pub(crate) mod tests {
nonces_start: pallet_bridge_messages::InboundLanes::<TestRuntime>::get(
TEST_LANE_ID,
)
.unwrap()
.last_delivered_nonce() +
1,
nonces_end: best_message,
Expand Down Expand Up @@ -2884,6 +2885,7 @@ pub(crate) mod tests {
// allow empty message delivery transactions
let lane_id = TestLaneId::get();
let in_lane_data = InboundLaneData {
state: LaneState::Opened,
last_confirmed_nonce: 0,
relayers: vec![UnrewardedRelayer {
relayer: relayer_account_at_bridged_chain(),
Expand Down
6 changes: 0 additions & 6 deletions bridges/bin/runtime-common/src/integrity.rs
Original file line number Diff line number Diff line change
Expand Up @@ -165,12 +165,6 @@ where
R: pallet_bridge_messages::Config<MI>,
MI: 'static,
{
assert!(
!R::ActiveOutboundLanes::get().is_empty(),
"ActiveOutboundLanes ({:?}) must not be empty",
R::ActiveOutboundLanes::get(),
);

assert!(
pallet_bridge_messages::BridgedChainOf::<R, MI>::MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX
<= pallet_bridge_messages::BridgedChainOf::<R, MI>::MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX,
Expand Down
102 changes: 65 additions & 37 deletions bridges/bin/runtime-common/src/messages_call_ext.rs
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,10 @@ impl<T: Config<I>, I: 'static> CallHelper<T, I> {
match info {
CallInfo::ReceiveMessagesProof(info) => {
let inbound_lane_data =
pallet_bridge_messages::InboundLanes::<T, I>::get(info.base.lane_id);
match pallet_bridge_messages::InboundLanes::<T, I>::get(info.base.lane_id) {
Some(inbound_lane_data) => inbound_lane_data,
None => return false,
};
if info.base.bundled_range.is_empty() {
let post_occupation =
unrewarded_relayers_occupation::<T, I>(&inbound_lane_data);
Expand All @@ -162,7 +165,10 @@ impl<T: Config<I>, I: 'static> CallHelper<T, I> {
},
CallInfo::ReceiveMessagesDeliveryProof(info) => {
let outbound_lane_data =
pallet_bridge_messages::OutboundLanes::<T, I>::get(info.0.lane_id);
match pallet_bridge_messages::OutboundLanes::<T, I>::get(info.0.lane_id) {
Some(outbound_lane_data) => outbound_lane_data,
None => return false,
};
outbound_lane_data.latest_received_nonce == *info.0.bundled_range.end()
},
}
Expand Down Expand Up @@ -219,7 +225,7 @@ impl<
..
}) = self.is_sub_type()
{
let inbound_lane_data = pallet_bridge_messages::InboundLanes::<T, I>::get(proof.lane);
let inbound_lane_data = pallet_bridge_messages::InboundLanes::<T, I>::get(proof.lane)?;

return Some(ReceiveMessagesProofInfo {
base: BaseMessagesProofInfo {
Expand All @@ -243,7 +249,8 @@ impl<
..
}) = self.is_sub_type()
{
let outbound_lane_data = pallet_bridge_messages::OutboundLanes::<T, I>::get(proof.lane);
let outbound_lane_data =
pallet_bridge_messages::OutboundLanes::<T, I>::get(proof.lane)?;

return Some(ReceiveMessagesDeliveryProofInfo(BaseMessagesProofInfo {
lane_id: proof.lane,
Expand Down Expand Up @@ -349,29 +356,31 @@ mod tests {
};
use bp_messages::{
source_chain::FromBridgedChainMessagesDeliveryProof,
target_chain::FromBridgedChainMessagesProof, DeliveredMessages, UnrewardedRelayer,
UnrewardedRelayersState,
target_chain::FromBridgedChainMessagesProof, DeliveredMessages, InboundLaneData, LaneState,
OutboundLaneData, UnrewardedRelayer, UnrewardedRelayersState,
};
use sp_std::ops::RangeInclusive;

const TEST_LANE_ID: LaneId = LaneId([0, 0, 0, 0]);

fn fill_unrewarded_relayers() {
let mut inbound_lane_state =
pallet_bridge_messages::InboundLanes::<TestRuntime>::get(LaneId([0, 0, 0, 0]));
pallet_bridge_messages::InboundLanes::<TestRuntime>::get(TEST_LANE_ID).unwrap();
for n in 0..BridgedUnderlyingChain::MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX {
inbound_lane_state.relayers.push_back(UnrewardedRelayer {
relayer: Default::default(),
messages: DeliveredMessages { begin: n + 1, end: n + 1 },
});
}
pallet_bridge_messages::InboundLanes::<TestRuntime>::insert(
LaneId([0, 0, 0, 0]),
TEST_LANE_ID,
inbound_lane_state,
);
}

fn fill_unrewarded_messages() {
let mut inbound_lane_state =
pallet_bridge_messages::InboundLanes::<TestRuntime>::get(LaneId([0, 0, 0, 0]));
pallet_bridge_messages::InboundLanes::<TestRuntime>::get(TEST_LANE_ID).unwrap();
inbound_lane_state.relayers.push_back(UnrewardedRelayer {
relayer: Default::default(),
messages: DeliveredMessages {
Expand All @@ -380,15 +389,19 @@ mod tests {
},
});
pallet_bridge_messages::InboundLanes::<TestRuntime>::insert(
LaneId([0, 0, 0, 0]),
TEST_LANE_ID,
inbound_lane_state,
);
}

fn deliver_message_10() {
pallet_bridge_messages::InboundLanes::<TestRuntime>::insert(
LaneId([0, 0, 0, 0]),
bp_messages::InboundLaneData { relayers: Default::default(), last_confirmed_nonce: 10 },
TEST_LANE_ID,
bp_messages::InboundLaneData {
state: LaneState::Opened,
relayers: Default::default(),
last_confirmed_nonce: 10,
},
);
}

Expand All @@ -405,7 +418,7 @@ mod tests {
proof: Box::new(FromBridgedChainMessagesProof {
bridged_header_hash: Default::default(),
storage_proof: Default::default(),
lane: LaneId([0, 0, 0, 0]),
lane: TEST_LANE_ID,
nonces_start,
nonces_end,
}),
Expand All @@ -415,9 +428,23 @@ mod tests {
.is_ok()
}

fn run_test<T>(test: impl Fn() -> T) -> T {
sp_io::TestExternalities::new(Default::default()).execute_with(|| {
pallet_bridge_messages::InboundLanes::<TestRuntime>::insert(
TEST_LANE_ID,
InboundLaneData::opened(),
);
pallet_bridge_messages::OutboundLanes::<TestRuntime>::insert(
TEST_LANE_ID,
OutboundLaneData::opened(),
);
test()
})
}

#[test]
fn extension_rejects_obsolete_messages() {
sp_io::TestExternalities::new(Default::default()).execute_with(|| {
run_test(|| {
// when current best delivered is message#10 and we're trying to deliver messages 8..=9
// => tx is rejected
deliver_message_10();
Expand All @@ -427,7 +454,7 @@ mod tests {

#[test]
fn extension_rejects_same_message() {
sp_io::TestExternalities::new(Default::default()).execute_with(|| {
run_test(|| {
// when current best delivered is message#10 and we're trying to import messages 10..=10
// => tx is rejected
deliver_message_10();
Expand All @@ -437,7 +464,7 @@ mod tests {

#[test]
fn extension_rejects_call_with_some_obsolete_messages() {
sp_io::TestExternalities::new(Default::default()).execute_with(|| {
run_test(|| {
// when current best delivered is message#10 and we're trying to deliver messages
// 10..=15 => tx is rejected
deliver_message_10();
Expand All @@ -447,7 +474,7 @@ mod tests {

#[test]
fn extension_rejects_call_with_future_messages() {
sp_io::TestExternalities::new(Default::default()).execute_with(|| {
run_test(|| {
// when current best delivered is message#10 and we're trying to deliver messages
// 13..=15 => tx is rejected
deliver_message_10();
Expand All @@ -470,7 +497,7 @@ mod tests {
#[test]
fn extension_rejects_empty_delivery_with_rewards_confirmations_if_there_are_free_relayer_and_message_slots(
) {
sp_io::TestExternalities::new(Default::default()).execute_with(|| {
run_test(|| {
deliver_message_10();
assert!(!validate_message_delivery(10, 9));
});
Expand All @@ -479,7 +506,7 @@ mod tests {
#[test]
fn extension_accepts_empty_delivery_with_rewards_confirmations_if_there_are_no_free_relayer_slots(
) {
sp_io::TestExternalities::new(Default::default()).execute_with(|| {
run_test(|| {
deliver_message_10();
fill_unrewarded_relayers();
assert!(validate_message_delivery(10, 9));
Expand All @@ -489,7 +516,7 @@ mod tests {
#[test]
fn extension_accepts_empty_delivery_with_rewards_confirmations_if_there_are_no_free_message_slots(
) {
sp_io::TestExternalities::new(Default::default()).execute_with(|| {
run_test(|| {
fill_unrewarded_messages();
assert!(validate_message_delivery(
BridgedUnderlyingChain::MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX,
Expand All @@ -500,7 +527,7 @@ mod tests {

#[test]
fn extension_accepts_new_messages() {
sp_io::TestExternalities::new(Default::default()).execute_with(|| {
run_test(|| {
// when current best delivered is message#10 and we're trying to deliver message 11..=15
// => tx is accepted
deliver_message_10();
Expand All @@ -510,8 +537,9 @@ mod tests {

fn confirm_message_10() {
pallet_bridge_messages::OutboundLanes::<TestRuntime>::insert(
LaneId([0, 0, 0, 0]),
TEST_LANE_ID,
bp_messages::OutboundLaneData {
state: LaneState::Opened,
oldest_unpruned_nonce: 0,
latest_received_nonce: 10,
latest_generated_nonce: 10,
Expand All @@ -525,7 +553,7 @@ mod tests {
proof: FromBridgedChainMessagesDeliveryProof {
bridged_header_hash: Default::default(),
storage_proof: Default::default(),
lane: LaneId([0, 0, 0, 0]),
lane: TEST_LANE_ID,
},
relayers_state: UnrewardedRelayersState {
last_delivered_nonce,
Expand All @@ -539,7 +567,7 @@ mod tests {

#[test]
fn extension_rejects_obsolete_confirmations() {
sp_io::TestExternalities::new(Default::default()).execute_with(|| {
run_test(|| {
// when current best confirmed is message#10 and we're trying to confirm message#5 => tx
// is rejected
confirm_message_10();
Expand All @@ -549,7 +577,7 @@ mod tests {

#[test]
fn extension_rejects_same_confirmation() {
sp_io::TestExternalities::new(Default::default()).execute_with(|| {
run_test(|| {
// when current best confirmed is message#10 and we're trying to confirm message#10 =>
// tx is rejected
confirm_message_10();
Expand All @@ -559,7 +587,7 @@ mod tests {

#[test]
fn extension_rejects_empty_confirmation_even_if_there_are_no_free_unrewarded_entries() {
sp_io::TestExternalities::new(Default::default()).execute_with(|| {
run_test(|| {
confirm_message_10();
fill_unrewarded_relayers();
assert!(!validate_message_confirmation(10));
Expand All @@ -568,7 +596,7 @@ mod tests {

#[test]
fn extension_accepts_new_confirmation() {
sp_io::TestExternalities::new(Default::default()).execute_with(|| {
run_test(|| {
// when current best confirmed is message#10 and we're trying to confirm message#15 =>
// tx is accepted
confirm_message_10();
Expand All @@ -583,7 +611,7 @@ mod tests {
CallHelper::<TestRuntime, ()>::was_successful(&CallInfo::ReceiveMessagesProof(
ReceiveMessagesProofInfo {
base: BaseMessagesProofInfo {
lane_id: LaneId([0, 0, 0, 0]),
lane_id: TEST_LANE_ID,
bundled_range,
best_stored_nonce: 0, // doesn't matter for `was_successful`
},
Expand All @@ -602,7 +630,7 @@ mod tests {
#[test]
#[allow(clippy::reversed_empty_ranges)]
fn was_successful_returns_false_for_failed_reward_confirmation_transaction() {
sp_io::TestExternalities::new(Default::default()).execute_with(|| {
run_test(|| {
fill_unrewarded_messages();
assert!(!was_message_delivery_successful(10..=9, true));
});
Expand All @@ -611,30 +639,30 @@ mod tests {
#[test]
#[allow(clippy::reversed_empty_ranges)]
fn was_successful_returns_true_for_successful_reward_confirmation_transaction() {
sp_io::TestExternalities::new(Default::default()).execute_with(|| {
run_test(|| {
assert!(was_message_delivery_successful(10..=9, true));
});
}

#[test]
fn was_successful_returns_false_for_failed_delivery() {
sp_io::TestExternalities::new(Default::default()).execute_with(|| {
run_test(|| {
deliver_message_10();
assert!(!was_message_delivery_successful(10..=12, false));
});
}

#[test]
fn was_successful_returns_false_for_partially_successful_delivery() {
sp_io::TestExternalities::new(Default::default()).execute_with(|| {
run_test(|| {
deliver_message_10();
assert!(!was_message_delivery_successful(9..=12, false));
});
}

#[test]
fn was_successful_returns_true_for_successful_delivery() {
sp_io::TestExternalities::new(Default::default()).execute_with(|| {
run_test(|| {
deliver_message_10();
assert!(was_message_delivery_successful(9..=10, false));
});
Expand All @@ -643,7 +671,7 @@ mod tests {
fn was_message_confirmation_successful(bundled_range: RangeInclusive<MessageNonce>) -> bool {
CallHelper::<TestRuntime, ()>::was_successful(&CallInfo::ReceiveMessagesDeliveryProof(
ReceiveMessagesDeliveryProofInfo(BaseMessagesProofInfo {
lane_id: LaneId([0, 0, 0, 0]),
lane_id: TEST_LANE_ID,
bundled_range,
best_stored_nonce: 0, // doesn't matter for `was_successful`
}),
Expand All @@ -652,23 +680,23 @@ mod tests {

#[test]
fn was_successful_returns_false_for_failed_confirmation() {
sp_io::TestExternalities::new(Default::default()).execute_with(|| {
run_test(|| {
confirm_message_10();
assert!(!was_message_confirmation_successful(10..=12));
});
}

#[test]
fn was_successful_returns_false_for_partially_successful_confirmation() {
sp_io::TestExternalities::new(Default::default()).execute_with(|| {
run_test(|| {
confirm_message_10();
assert!(!was_message_confirmation_successful(9..=12));
});
}

#[test]
fn was_successful_returns_true_for_successful_confirmation() {
sp_io::TestExternalities::new(Default::default()).execute_with(|| {
run_test(|| {
confirm_message_10();
assert!(was_message_confirmation_successful(9..=10));
});
Expand Down
3 changes: 2 additions & 1 deletion bridges/bin/runtime-common/src/messages_xcm_extension.rs
Original file line number Diff line number Diff line change
Expand Up @@ -339,7 +339,7 @@ mod tests {
use super::*;
use crate::mock::*;

use bp_messages::OutboundLaneData;
use bp_messages::{LaneState, OutboundLaneData};
use frame_support::parameter_types;
use pallet_bridge_messages::OutboundLanes;

Expand Down Expand Up @@ -397,6 +397,7 @@ mod tests {
OutboundLanes::<TestRuntime, ()>::insert(
TEST_LANE_ID,
OutboundLaneData {
state: LaneState::Opened,
oldest_unpruned_nonce: 0,
latest_received_nonce: 0,
latest_generated_nonce,
Expand Down
Loading

0 comments on commit 169a487

Please sign in to comment.