Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 19 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ members = [
'math',
'node',
'pallets/parameters',
'pallets/collator-rotation',
'runtime/basilisk',
'pallets/marketplace',
'pallets/asset-registry',
Expand Down Expand Up @@ -58,6 +59,7 @@ pallet-asset-registry = { path = "pallets/asset-registry", default-features = fa
pallet-ema-oracle = { path = "pallets/ema-oracle", default-features = false}
pallet-lbp = { path = "pallets/lbp", default-features = false }
pallet-parameters = { path = "pallets/parameters", default-features = false }
pallet-collator-rotation = { path = "pallets/collator-rotation", default-features = false }
pallet-route-executor = { path = "pallets/route-executor", default-features = false }
pallet-transaction-multi-payment = { path = "pallets/transaction-multi-payment", default-features = false }
pallet-xyk = { path = "pallets/xyk", default-features = false }
Expand Down
2 changes: 1 addition & 1 deletion integration-tests/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "runtime-integration-tests"
version = "1.2.1"
version = "1.2.2"
description = "Integration tests"
authors = ["GalacticCouncil"]
edition = "2021"
Expand Down
116 changes: 41 additions & 75 deletions integration-tests/src/sessions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,88 +4,54 @@ use basilisk_runtime::CollatorRewards;
use pallet_session::SessionManager;
use pretty_assertions::assert_eq;
use xcm_emulator::TestExt;

#[test]
fn new_session_should_rotate_collators_list() {
fn new_session_should_alternate_full_set_and_benched_set() {
TestNet::reset();

Basilisk::execute_with(|| {
let collator1 = basilisk::invulnerables()[0].0.clone(); //d435...
let collator2 = basilisk::invulnerables()[1].0.clone(); //8eaf...
let collator3 = basilisk::invulnerables()[2].0.clone(); //90b5...
let collator4 = basilisk::invulnerables()[3].0.clone(); //6ebe...
let collator5 = basilisk::invulnerables()[4].0.clone(); //ec5e...
let collator6 = basilisk::invulnerables()[5].0.clone(); //9c78...
let collator7 = basilisk::invulnerables()[6].0.clone(); //a678...
let collator8 = basilisk::invulnerables()[7].0.clone(); //2433...
let collator9 = basilisk::invulnerables()[8].0.clone(); //ee28...
let collator10 = basilisk::invulnerables()[9].0.clone(); //da53...
// Invulnerables are stored sorted by `pallet_collator_selection`, so the
// inner `CollatorSelection::new_session` returns them in sorted order.
// `pallet_collator_rotation` then benches `(N / 2) % len` on odd sessions
// only; even sessions pass the full set through unchanged.
let collator1 = basilisk::invulnerables()[0].0.clone(); // d435...
let collator2 = basilisk::invulnerables()[1].0.clone(); // 8eaf...
let collator3 = basilisk::invulnerables()[2].0.clone(); // 90b5...
let collator4 = basilisk::invulnerables()[3].0.clone(); // 6ebe...
let collator5 = basilisk::invulnerables()[4].0.clone(); // ec5e...
let collator6 = basilisk::invulnerables()[5].0.clone(); // 9c78...
let collator7 = basilisk::invulnerables()[6].0.clone(); // a678...
let collator8 = basilisk::invulnerables()[7].0.clone(); // 2433...
let collator9 = basilisk::invulnerables()[8].0.clone(); // ee28...
let collator10 = basilisk::invulnerables()[9].0.clone(); // da53...

let full_sorted = vec![
collator8.clone(),
collator4.clone(),
collator2.clone(),
collator3.clone(),
collator6.clone(),
collator7.clone(),
collator1.clone(),
collator10.clone(),
collator5.clone(),
collator9.clone(),
];

let collators = CollatorRewards::new_session(0).unwrap();
assert_eq!(
collators,
vec![
collator8.clone(),
collator4.clone(),
collator2.clone(),
collator3.clone(),
collator6.clone(),
collator7.clone(),
collator1.clone(),
collator10.clone(),
collator5.clone(),
collator9.clone()
]
);
// Session 0 (even): full set, no bench.
assert_eq!(CollatorRewards::new_session(0).unwrap(), full_sorted);

let collators = CollatorRewards::new_session(1).unwrap();
assert_eq!(
collators,
vec![
collator4.clone(),
collator2.clone(),
collator3.clone(),
collator6.clone(),
collator7.clone(),
collator1.clone(),
collator10.clone(),
collator5.clone(),
collator9.clone(),
collator8.clone(),
]
);
// Session 1 (odd, bench index 1/2 = 0): collator at sorted position 0.
let mut session1 = full_sorted.clone();
session1.remove(0);
assert_eq!(CollatorRewards::new_session(1).unwrap(), session1);

let collators = CollatorRewards::new_session(2).unwrap();
assert_eq!(
collators,
vec![
collator2.clone(),
collator3.clone(),
collator6.clone(),
collator7.clone(),
collator1.clone(),
collator10.clone(),
collator5.clone(),
collator9.clone(),
collator8.clone(),
collator4.clone(),
]
);
// Session 2 (even): full set returns.
assert_eq!(CollatorRewards::new_session(2).unwrap(), full_sorted);

let collators = CollatorRewards::new_session(3).unwrap();
assert_eq!(
collators,
vec![
collator3.clone(),
collator6.clone(),
collator7.clone(),
collator1.clone(),
collator10.clone(),
collator5.clone(),
collator9.clone(),
collator8.clone(),
collator4.clone(),
collator2.clone(),
]
);
// Session 3 (odd, bench index 3/2 = 1): collator at sorted position 1.
let mut session3 = full_sorted.clone();
session3.remove(1);
assert_eq!(CollatorRewards::new_session(3).unwrap(), session3);
});
}
43 changes: 43 additions & 0 deletions pallets/collator-rotation/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
[package]
name = "pallet-collator-rotation"
version = "1.0.0"
authors = ["GalacticCouncil"]
edition = "2021"
license = "Apache-2.0"
homepage = "https://github.com/galacticcouncil/Basilisk-node"
repository = "https://github.com/galacticcouncil/Basilisk-node"
description = "Wraps a SessionManager and benches one collator per session, rotating by session index"

[dependencies]
codec = { workspace = true, features = ["derive", "max-encoded-len"] }
scale-info = { workspace = true }
frame-support = { workspace = true }
frame-system = { workspace = true }
pallet-session = { workspace = true }
sp-staking = { workspace = true }
sp-std = { workspace = true }

[dev-dependencies]
sp-core = { workspace = true }
sp-io = { workspace = true }
sp-runtime = { workspace = true }

[features]
default = ["std"]
std = [
"codec/std",
"scale-info/std",
"frame-support/std",
"frame-system/std",
"pallet-session/std",
"sp-staking/std",
"sp-std/std",
"sp-core/std",
"sp-io/std",
"sp-runtime/std",
]
try-runtime = [
"frame-support/try-runtime",
"frame-system/try-runtime",
"pallet-session/try-runtime",
]
63 changes: 63 additions & 0 deletions pallets/collator-rotation/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
// This file is part of Basilisk-node.
//
// Copyright (C) 2020-2026 Intergalactic, Limited (GIB).
// SPDX-License-Identifier: Apache-2.0

#![cfg_attr(not(feature = "std"), no_std)]

#[cfg(test)]
mod mock;
#[cfg(test)]
mod tests;

pub use pallet::*;

use pallet_session::SessionManager;
use sp_staking::SessionIndex;
use sp_std::vec::Vec;

#[frame_support::pallet]
pub mod pallet {
use super::*;

#[pallet::config]
pub trait Config: frame_system::Config<RuntimeEvent: From<Event<Self>>> {
type Inner: SessionManager<Self::AccountId>;
}

#[pallet::pallet]
pub struct Pallet<T>(_);

#[pallet::event]
#[pallet::generate_deposit(pub(crate) fn deposit_event)]
pub enum Event<T: Config> {
CollatorBenched {
who: T::AccountId,
session_index: SessionIndex,
},
}
}

impl<T: Config> SessionManager<T::AccountId> for Pallet<T> {
fn new_session(new_index: SessionIndex) -> Option<Vec<T::AccountId>> {
let mut collators = T::Inner::new_session(new_index)?;
// bench 1 collator every odd session rotation
if new_index % 2 == 1 && collators.len() > 1 {
let bench_idx = ((new_index / 2) as usize) % collators.len();
let benched = collators.remove(bench_idx);
Self::deposit_event(Event::CollatorBenched {
who: benched,
session_index: new_index,
});
}
Some(collators)
}

fn end_session(end_index: SessionIndex) {
T::Inner::end_session(end_index)
}

fn start_session(start_index: SessionIndex) {
T::Inner::start_session(start_index)
}
}
Loading
Loading