Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Introduce ActiveLaneRelayersSet and NextLaneRelayersSet #2627

Merged
merged 11 commits into from
Oct 27, 2023
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
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please note that it isn't the whole solution - there's yet two additional steps mentioned in #2605 (comment) and extracted to the #2618

/// 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