Limit max number of unconfirmed messages at inbound lane (#545)

* limit maximal number of unconfirmed messages at inbound lane

* unrewarded_relayer_entries API

* change relay to support max unrewarded relayer entries

* Update modules/message-lane/src/inbound_lane.rs

Co-authored-by: Tomasz Drwięga <tomusdrw@users.noreply.github.com>

* Update relays/messages-relay/src/message_lane_loop.rs

Co-authored-by: Hernando Castano <HCastano@users.noreply.github.com>

* removed pub

Co-authored-by: Tomasz Drwięga <tomusdrw@users.noreply.github.com>
Co-authored-by: Hernando Castano <HCastano@users.noreply.github.com>
This commit is contained in:
Svyatoslav Nikolsky
2020-12-08 13:58:07 +03:00
committed by Bastian Köcher
parent 93b3d49047
commit 2944f997d1
17 changed files with 321 additions and 52 deletions
@@ -31,6 +31,8 @@ pub trait InboundLaneStorage {
/// Lane id.
fn id(&self) -> LaneId;
/// Return maximal number of unrewarded relayer entries in inbound lane.
fn max_unrewarded_relayer_entries(&self) -> MessageNonce;
/// Return maximal number of unconfirmed messages in inbound lane.
fn max_unconfirmed_messages(&self) -> MessageNonce;
/// Get lane data from the storage.
@@ -97,8 +99,14 @@ impl<S: InboundLaneStorage> InboundLane<S> {
return false;
}
// if there are more unrewarded relayer entries than we may accept, reject this message
if data.relayers.len() as MessageNonce >= self.storage.max_unrewarded_relayer_entries() {
return false;
}
// if there are more unconfirmed messages than we may accept, reject this message
if self.storage.max_unconfirmed_messages() <= data.relayers.len() as MessageNonce {
let unconfirmed_messages_count = nonce.saturating_sub(data.latest_confirmed_nonce);
if unconfirmed_messages_count > self.storage.max_unconfirmed_messages() {
return false;
}
@@ -271,10 +279,10 @@ mod tests {
}
#[test]
fn fails_to_receive_messages_above_max_limit_per_lane() {
fn fails_to_receive_messages_above_unrewarded_relayer_entries_limit_per_lane() {
run_test(|| {
let mut lane = inbound_lane::<TestRuntime, _>(TEST_LANE_ID);
let max_nonce = <TestRuntime as crate::Trait>::MaxUnconfirmedMessagesAtInboundLane::get();
let max_nonce = <TestRuntime as crate::Trait>::MaxUnrewardedRelayerEntriesAtInboundLane::get();
for current_nonce in 1..max_nonce + 1 {
assert!(lane.receive_message::<TestMessageDispatch>(
TEST_RELAYER_A + current_nonce,
@@ -303,6 +311,39 @@ mod tests {
});
}
#[test]
fn fails_to_receive_messages_above_unconfirmed_messages_limit_per_lane() {
run_test(|| {
let mut lane = inbound_lane::<TestRuntime, _>(TEST_LANE_ID);
let max_nonce = <TestRuntime as crate::Trait>::MaxUnconfirmedMessagesAtInboundLane::get();
for current_nonce in 1..=max_nonce {
assert!(lane.receive_message::<TestMessageDispatch>(
TEST_RELAYER_A,
current_nonce,
message_data(REGULAR_PAYLOAD).into()
));
}
// Fails to dispatch new message from different than latest relayer.
assert_eq!(
false,
lane.receive_message::<TestMessageDispatch>(
TEST_RELAYER_B,
max_nonce + 1,
message_data(REGULAR_PAYLOAD).into()
)
);
// Fails to dispatch new messages from latest relayer.
assert_eq!(
false,
lane.receive_message::<TestMessageDispatch>(
TEST_RELAYER_A,
max_nonce + 1,
message_data(REGULAR_PAYLOAD).into()
)
);
});
}
#[test]
fn correctly_receives_following_messages_from_two_relayers_alternately() {
run_test(|| {
+43 -9
View File
@@ -75,16 +75,20 @@ pub trait Trait<I = DefaultInstance>: frame_system::Trait {
/// confirmed. The reason is that if you want to use lane, you should be ready to pay
/// for it.
type MaxMessagesToPruneAtOnce: Get<MessageNonce>;
/// Maximal number of "messages" (see note below) in the 'unconfirmed' state at inbound lane.
/// Unconfirmed message at inbound lane is the message that has been: sent, delivered and
/// dispatched. Its delivery confirmation is still pending. This limit is introduced to bound
/// maximal number of relayers-ids in the inbound lane state.
/// Maximal number of unrewarded relayer entries at inbound lane. Unrewarded means that the
/// relayer has delivered messages, but either confirmations haven't been delivered back to the
/// source chain, or we haven't received reward confirmations yet.
///
/// "Message" in this context does not necessarily mean an individual message, but instead
/// continuous range of individual messages, that are delivered by single relayer. So if relayer#1
/// has submitted delivery transaction#1 with individual messages [1; 2] and then delivery
/// transaction#2 with individual messages [3; 4], this would be treated as single "Message" and
/// would occupy single unit of `MaxUnconfirmedMessagesAtInboundLane` limit.
/// This constant limits maximal number of entries in the `InboundLaneData::relayers`. Keep
/// in mind that the same relayer account may take several (non-consecutive) entries in this
/// set.
type MaxUnrewardedRelayerEntriesAtInboundLane: Get<MessageNonce>;
/// Maximal number of unconfirmed messages at inbound lane. Unconfirmed means that the
/// message has been delivered, but either confirmations haven't been delivered back to the
/// source chain, or we haven't received reward confirmations for these messages yet.
///
/// This constant limits difference between last message from last entry of the
/// `InboundLaneData::relayers` and first message at the first entry.
type MaxUnconfirmedMessagesAtInboundLane: Get<MessageNonce>;
/// Maximal number of messages in single delivery transaction. This directly affects the base
/// weight of the delivery transaction.
@@ -481,6 +485,17 @@ impl<T: Trait<I>, I: Instance> Module<T, I> {
pub fn inbound_latest_confirmed_nonce(lane: LaneId) -> MessageNonce {
InboundLanes::<T, I>::get(&lane).latest_confirmed_nonce
}
/// Get state of unrewarded relayers set.
pub fn inbound_unrewarded_relayers_state(
lane: bp_message_lane::LaneId,
) -> bp_message_lane::UnrewardedRelayersState {
let relayers = InboundLanes::<T, I>::get(&lane).relayers;
bp_message_lane::UnrewardedRelayersState {
unrewarded_relayer_entries: relayers.len() as _,
messages_in_oldest_entry: relayers.front().map(|(begin, end, _)| 1 + end - begin).unwrap_or(0),
}
}
}
/// Getting storage keys for messages and lanes states. These keys are normally used when building
@@ -569,6 +584,10 @@ impl<T: Trait<I>, I: Instance> InboundLaneStorage for RuntimeInboundLaneStorage<
self.lane_id
}
fn max_unrewarded_relayer_entries(&self) -> MessageNonce {
T::MaxUnrewardedRelayerEntriesAtInboundLane::get()
}
fn max_unconfirmed_messages(&self) -> MessageNonce {
T::MaxUnconfirmedMessagesAtInboundLane::get()
}
@@ -681,6 +700,7 @@ mod tests {
message, run_test, Origin, TestEvent, TestMessageDeliveryAndDispatchPayment, TestMessagesProof, TestRuntime,
PAYLOAD_REJECTED_BY_TARGET_CHAIN, REGULAR_PAYLOAD, TEST_LANE_ID, TEST_RELAYER_A, TEST_RELAYER_B,
};
use bp_message_lane::UnrewardedRelayersState;
use frame_support::{assert_noop, assert_ok};
use frame_system::{EventRecord, Module as System, Phase};
use hex_literal::hex;
@@ -916,6 +936,13 @@ mod tests {
.collect(),
},
);
assert_eq!(
Module::<TestRuntime>::inbound_unrewarded_relayers_state(TEST_LANE_ID),
UnrewardedRelayersState {
unrewarded_relayer_entries: 2,
messages_in_oldest_entry: 1,
},
);
// message proof includes outbound lane state with latest confirmed message updated to 9
let mut message_proof: TestMessagesProof = Ok(vec![message(11, REGULAR_PAYLOAD)]).into();
@@ -941,6 +968,13 @@ mod tests {
latest_confirmed_nonce: 9,
},
);
assert_eq!(
Module::<TestRuntime>::inbound_unrewarded_relayers_state(TEST_LANE_ID),
UnrewardedRelayersState {
unrewarded_relayer_entries: 2,
messages_in_oldest_entry: 1,
},
);
});
}
+3 -1
View File
@@ -99,13 +99,15 @@ impl frame_system::Trait for TestRuntime {
parameter_types! {
pub const MaxMessagesToPruneAtOnce: u64 = 10;
pub const MaxUnconfirmedMessagesAtInboundLane: u64 = 16;
pub const MaxUnrewardedRelayerEntriesAtInboundLane: u64 = 16;
pub const MaxUnconfirmedMessagesAtInboundLane: u64 = 32;
pub const MaxMessagesInDeliveryTransaction: u64 = 128;
}
impl Trait for TestRuntime {
type Event = TestEvent;
type MaxMessagesToPruneAtOnce = MaxMessagesToPruneAtOnce;
type MaxUnrewardedRelayerEntriesAtInboundLane = MaxUnrewardedRelayerEntriesAtInboundLane;
type MaxUnconfirmedMessagesAtInboundLane = MaxUnconfirmedMessagesAtInboundLane;
type MaxMessagesInDeliveryTransaction = MaxMessagesInDeliveryTransaction;