Skip to content

Commit

Permalink
Introduce ActiveLaneRelayersSet and NextLaneRelayersSet (#2627)
Browse files Browse the repository at this point in the history
* intreoduce ActiveLaneRelayersSet and NextLaneRelayersSet

* more tests

* fix runtimes

* CI

* CI 2

* CI 3

* apply review suggestions

* return Option<> from try_remove

* RelayerAndReward -> LaneRegistration

* separate BTreeSet -> boolean flag
  • Loading branch information
svyatonik authored Oct 27, 2023
1 parent a485a9a commit 5137448
Show file tree
Hide file tree
Showing 8 changed files with 721 additions and 28 deletions.
3 changes: 2 additions & 1 deletion bin/millau/runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -432,7 +432,8 @@ impl pallet_bridge_relayers::Config for Runtime {
ConstU64<1_000>,
ConstU64<8>,
>;
type MaxRelayersPerLane = ConstU32<16>;
type MaxActiveRelayersPerLane = ConstU32<16>;
type MaxNextRelayersPerLane = ConstU32<1_024>;
type SlotLength = ConstU64<16>;
type PriorityBoostPerMessage = PriorityBoostPerMessage;
type PriorityBoostForActiveLaneRelayer = ConstU64<0>;
Expand Down
3 changes: 2 additions & 1 deletion bin/rialto-parachain/runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -541,7 +541,8 @@ impl pallet_bridge_relayers::Config for Runtime {
type PaymentProcedure =
bp_relayers::PayRewardFromAccount<pallet_balances::Pallet<Runtime>, AccountId>;
type StakeAndSlash = ();
type MaxRelayersPerLane = ConstU32<16>;
type MaxActiveRelayersPerLane = ConstU32<16>;
type MaxNextRelayersPerLane = ConstU32<1_024>;
type SlotLength = ConstU32<16>;
type PriorityBoostPerMessage = ConstU64<0>;
type PriorityBoostForActiveLaneRelayer = ConstU64<0>;
Expand Down
3 changes: 2 additions & 1 deletion bin/rialto/runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -422,7 +422,8 @@ impl pallet_bridge_relayers::Config for Runtime {
type PaymentProcedure =
bp_relayers::PayRewardFromAccount<pallet_balances::Pallet<Runtime>, AccountId>;
type StakeAndSlash = ();
type MaxRelayersPerLane = ConstU32<16>;
type MaxActiveRelayersPerLane = ConstU32<16>;
type MaxNextRelayersPerLane = ConstU32<1_024>;
type SlotLength = ConstU32<16>;
type PriorityBoostPerMessage = ConstU64<0>;
type PriorityBoostForActiveLaneRelayer = ConstU64<0>;
Expand Down
42 changes: 25 additions & 17 deletions modules/relayers/src/extension/priority.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ use frame_system::{pallet_prelude::BlockNumberFor, Pallet as SystemPallet};
use sp_runtime::{
traits::{One, Zero},
transaction_validity::TransactionPriority,
Saturating,
};

// reexport everything from `integrity_tests` module
Expand Down Expand Up @@ -68,8 +69,9 @@ where
{
// if there are no relayers, explicitly registered at this lane, noone gets additional
// priority boost
let lane_relayers = RelayersPallet::<R>::lane_relayers(lane_id);
let lane_relayers_len: BlockNumberFor<R> = (lane_relayers.len() as u32).into();
let lane_relayers = RelayersPallet::<R>::active_lane_relayers(lane_id);
let active_lane_relayers = lane_relayers.relayers();
let lane_relayers_len: BlockNumberFor<R> = (active_lane_relayers.len() as u32).into();
if lane_relayers_len.is_zero() {
return 0
}
Expand All @@ -82,17 +84,17 @@ where

// let's compute current slot number
let current_block_number = SystemPallet::<R>::block_number();
let slot = current_block_number / slot_length;
let slot = current_block_number.saturating_sub(*lane_relayers.enacted_at()) / slot_length;

// and then get the relayer for that slot
let slot_relayer = match usize::try_from(slot % lane_relayers_len) {
Ok(slot_relayer_index) => &lane_relayers[slot_relayer_index],
Ok(slot_relayer_index) => &active_lane_relayers[slot_relayer_index],
Err(_) => return 0,
};

// if message delivery transaction is submitted by the relayer, assigned to the current
// slot, let's boost the transaction priority
if relayer != slot_relayer {
if relayer != slot_relayer.relayer() {
return 0
}

Expand Down Expand Up @@ -263,24 +265,30 @@ mod integrity_tests {
#[cfg(test)]
mod tests {
use super::*;
use crate::{mock::*, LaneRelayers};
use crate::{mock::*, ActiveLaneRelayers};
use bp_relayers::{ActiveLaneRelayersSet, NextLaneRelayersSet};
use sp_runtime::traits::ConstU32;

#[test]
fn compute_per_lane_priority_boost_works() {
run_test(|| {
// insert 3 relayers to the queue
let lane_id = LaneId::new(1, 2);
let relayer1 = 1_000;
let relayer2 = 2_000;
let relayer3 = 3_000;
LaneRelayers::<TestRuntime>::insert(
lane_id,
sp_runtime::BoundedVec::try_from(vec![relayer1, relayer2, relayer3]).unwrap(),
);

// at blocks 1..=SlotLength relayer1 gets the boost
System::set_block_number(0);
for _ in 1..SlotLength::get() {
let relayer1 = 100;
let relayer2 = 200;
let relayer3 = 300;
let mut next_set: NextLaneRelayersSet<_, _, ConstU32<3>> =
NextLaneRelayersSet::empty(5);
assert!(next_set.try_insert(relayer1, 0));
assert!(next_set.try_insert(relayer2, 0));
assert!(next_set.try_insert(relayer3, 0));
let mut active_set = ActiveLaneRelayersSet::default();
active_set.activate_next_set(7, next_set, |_| true);
ActiveLaneRelayers::<TestRuntime>::insert(lane_id, active_set);

// at blocks 7..=7+SlotLength relayer1 gets the boost
System::set_block_number(6);
for _ in 7..SlotLength::get() + 7 {
System::set_block_number(System::block_number() + 1);
assert_eq!(
compute_per_lane_priority_boost::<TestRuntime>(lane_id, &relayer1),
Expand Down
47 changes: 40 additions & 7 deletions modules/relayers/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@

use bp_messages::LaneId;
use bp_relayers::{
PaymentProcedure, Registration, RelayerRewardsKeyProvider, RewardsAccountParams, StakeAndSlash,
ActiveLaneRelayersSet, NextLaneRelayersSet, PaymentProcedure, Registration,
RelayerRewardsKeyProvider, RewardsAccountParams, StakeAndSlash,
};
use bp_runtime::StorageDoubleMapKeyProvider;
use frame_support::fail;
Expand Down Expand Up @@ -70,9 +71,28 @@ pub mod pallet {
/// Stake and slash scheme.
type StakeAndSlash: StakeAndSlash<Self::AccountId, BlockNumberFor<Self>, Self::Reward>;

/// Maximal number of relayers that can register themselves on a single lane.
/// Maximal number of relayers that can reside in the active lane relayers set on a single
/// lane.
///
/// Lowering this value leads to additional concurrency between relayers, potentially
/// making messages cheaper. So it shall not be too large.
#[pallet::constant]
type MaxActiveRelayersPerLane: Get<u32>;
/// Maximal number of relayers that can reside in the next lane relayers set on a single
/// lane.
///
/// Relayers set is a bounded priority queue, where relayers with lower expected reward are
/// prioritized over greedier relayers. At the end of epoch, we select top
/// `MaxActiveRelayersPerLane` relayers from the next set and move them to the next set. To
/// alleviate possible spam attacks, where relayers are registering at lane with zero reward
/// (pushing out actual relayers with larger expected reward) and then `deregistering`
/// themselves right before epoch end, we make the next relayers set larger than the active
/// set. It would make it more expensive for attackers to fill the whole next set.
///
/// This value must be larger than or equal to the [`Self::MaxActiveRelayersPerLane`].
#[pallet::constant]
type MaxRelayersPerLane: Get<u32>;
type MaxNextRelayersPerLane: Get<u32>;

/// Length of slots in chain blocks.
///
/// Registered relayer may explicitly register himself at some lane to get priority boost
Expand Down Expand Up @@ -483,20 +503,33 @@ pub mod pallet {
OptionQuery,
>;

/// A set of relayers that have explicitly registered themselves at a given lane.
/// An active set of relayers that have explicitly registered themselves at a given lane.
///
/// Every relayer inside this set receives additional priority boost when it submits
/// message delivers messages at given lane. The boost only happens inside the slot,
/// assigned to relayer.
#[pallet::storage]
#[pallet::getter(fn lane_relayers)]
pub type LaneRelayers<T: Config> = StorageMap<
#[pallet::getter(fn active_lane_relayers)]
pub type ActiveLaneRelayers<T: Config> = StorageMap<
_,
Identity,
LaneId,
BoundedVec<T::AccountId, T::MaxRelayersPerLane>,
ActiveLaneRelayersSet<T::AccountId, BlockNumberFor<T>, T::MaxActiveRelayersPerLane>,
ValueQuery,
>;

/// A next set of relayers that have explicitly registered themselves at a given lane.
///
/// This set may replace the [`ActiveLaneRelayers`] after current epoch ends.
#[pallet::storage]
#[pallet::getter(fn next_lane_relayers)]
pub type NextLaneRelayers<T: Config> = StorageMap<
_,
Identity,
LaneId,
NextLaneRelayersSet<T::AccountId, BlockNumberFor<T>, T::MaxNextRelayersPerLane>,
OptionQuery,
>;
}

#[cfg(test)]
Expand Down
5 changes: 4 additions & 1 deletion modules/relayers/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,8 @@ parameter_types! {
pub AdjustmentVariable: Multiplier = Multiplier::saturating_from_rational(3, 100_000);
pub MinimumMultiplier: Multiplier = Multiplier::saturating_from_rational(1, 1_000_000u128);
pub MaximumMultiplier: Multiplier = sp_runtime::traits::Bounded::max_value();
pub MaxActiveRelayersPerLane: u32 = 4;
pub MaxNextRelayersPerLane: u32 = 16;
pub SlotLength: u32 = 16;
pub PriorityBoostForActiveLaneRelayer: TransactionPriority = 1;
}
Expand Down Expand Up @@ -313,7 +315,8 @@ impl pallet_bridge_relayers::Config for TestRuntime {
type Reward = ThisChainBalance;
type PaymentProcedure = TestPaymentProcedure;
type StakeAndSlash = TestStakeAndSlash;
type MaxRelayersPerLane = ConstU32<16>;
type MaxActiveRelayersPerLane = MaxActiveRelayersPerLane;
type MaxNextRelayersPerLane = MaxNextRelayersPerLane;
type SlotLength = SlotLength;
type PriorityBoostPerMessage = ConstU64<1>;
type PriorityBoostForActiveLaneRelayer = PriorityBoostForActiveLaneRelayer;
Expand Down
Loading

0 comments on commit 5137448

Please sign in to comment.