Skip to content

Commit

Permalink
extract ShiftSessionManager into separate pallet (paritytech#342)
Browse files Browse the repository at this point in the history
  • Loading branch information
svyatonik authored and bkchr committed Apr 10, 2024
1 parent 8589400 commit 6df0341
Show file tree
Hide file tree
Showing 4 changed files with 289 additions and 92 deletions.
6 changes: 6 additions & 0 deletions bridges/bin/node/runtime/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,11 @@ tag = 'v2.0.0-rc6'
default-features = false
git = "https://github.com/paritytech/substrate/"

[dependencies.pallet-shift-session-manager]
version = "0.1.0"
default-features = false
path = "../../../modules/shift-session-manager"

[dependencies.pallet-sudo]
version = "2.0.0-rc6"
tag = 'v2.0.0-rc6'
Expand Down Expand Up @@ -264,6 +269,7 @@ std = [
"pallet-bridge-eth-poa/std",
"pallet-grandpa/std",
"pallet-randomness-collective-flip/std",
"pallet-shift-session-manager/std",
"pallet-sudo/std",
"pallet-timestamp/std",
"pallet-transaction-payment/std",
Expand Down
95 changes: 3 additions & 92 deletions bridges/bin/node/runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ pub mod benches;
pub mod kovan;
pub mod rialto;

use codec::{Decode, Encode};
use pallet_grandpa::{fg_primitives, AuthorityId as GrandpaId, AuthorityList as GrandpaAuthorityList};
use sp_api::impl_runtime_apis;
use sp_consensus_aura::sr25519::AuthorityId as AuraId;
Expand Down Expand Up @@ -401,63 +400,14 @@ impl pallet_session::Trait for Runtime {
type ValidatorIdOf = ();
type ShouldEndSession = pallet_session::PeriodicSessions<Period, Offset>;
type NextSessionRotation = pallet_session::PeriodicSessions<Period, Offset>;
type SessionManager = ShiftSessionManager;
type SessionManager = pallet_shift_session_manager::Module<Runtime>;
type SessionHandler = <SessionKeys as OpaqueKeys>::KeyTypeIdProviders;
type Keys = SessionKeys;
type DisabledValidatorsThreshold = ();
type WeightInfo = ();
}

pub struct ShiftSessionManager;

impl ShiftSessionManager {
/// Select validators for session.
fn select_validators(
session_index: sp_staking::SessionIndex,
available_validators: &[AccountId],
) -> Vec<AccountId> {
let available_validators_count = available_validators.len();
let count = sp_std::cmp::max(1, 2 * available_validators_count / 3);
let offset = session_index as usize % available_validators_count;
let end = offset + count;
let session_validators = match end.overflowing_sub(available_validators_count) {
(wrapped_end, false) if wrapped_end != 0 => available_validators[offset..]
.iter()
.chain(available_validators[..wrapped_end].iter())
.cloned()
.collect(),
_ => available_validators[offset..end].to_vec(),
};

session_validators
}
}

impl pallet_session::SessionManager<AccountId> for ShiftSessionManager {
fn end_session(_: sp_staking::SessionIndex) {}
fn start_session(_: sp_staking::SessionIndex) {}
fn new_session(session_index: sp_staking::SessionIndex) -> Option<Vec<AccountId>> {
// can't access genesis config here :/
if session_index == 0 || session_index == 1 {
return None;
}

// the idea that on first call (i.e. when session 1 ends) we're reading current
// set of validators from session module (they are initial validators) and save
// in our 'local storage'.
// then for every session we select (deterministically) 2/3 of these initial
// validators to serve validators of new session
let available_validators = sp_io::storage::get(b":available_validators")
.and_then(|validators| Decode::decode(&mut &validators[..]).ok())
.unwrap_or_else(|| {
let validators = <pallet_session::Module<Runtime>>::validators();
sp_io::storage::set(b":available_validators", &validators.encode());
validators
});

Some(Self::select_validators(session_index, &available_validators))
}
}
impl pallet_shift_session_manager::Trait for Runtime {}

construct_runtime!(
pub enum Runtime where
Expand All @@ -479,6 +429,7 @@ construct_runtime!(
TransactionPayment: pallet_transaction_payment::{Module, Storage},
Sudo: pallet_sudo::{Module, Call, Config<T>, Storage, Event<T>},
Session: pallet_session::{Module, Call, Storage, Event, Config<T>},
ShiftSessionManager: pallet_shift_session_manager::{Module},
}
);

Expand Down Expand Up @@ -771,46 +722,6 @@ mod tests {
use super::*;
use bp_currency_exchange::DepositInto;

#[test]
fn shift_session_manager_works() {
let acc1 = AccountId::from([1u8; 32]);
let acc2 = AccountId::from([2u8; 32]);
let acc3 = AccountId::from([3u8; 32]);
let acc4 = AccountId::from([4u8; 32]);
let acc5 = AccountId::from([5u8; 32]);
let all_accs = vec![acc1.clone(), acc2.clone(), acc3.clone(), acc4.clone(), acc5.clone()];

// at least 1 validator is selected
assert_eq!(
ShiftSessionManager::select_validators(0, &[acc1.clone()]),
vec![acc1.clone()],
);

// at session#0, shift is also 0
assert_eq!(
ShiftSessionManager::select_validators(0, &all_accs),
vec![acc1.clone(), acc2.clone(), acc3.clone()],
);

// at session#1, shift is also 1
assert_eq!(
ShiftSessionManager::select_validators(1, &all_accs),
vec![acc2.clone(), acc3.clone(), acc4.clone()],
);

// at session#3, we're wrapping
assert_eq!(
ShiftSessionManager::select_validators(3, &all_accs),
vec![acc4, acc5, acc1.clone()],
);

// at session#5, we're starting from the beginning again
assert_eq!(
ShiftSessionManager::select_validators(5, &all_accs),
vec![acc1, acc2, acc3],
);
}

fn run_deposit_into_test(test: impl Fn(AccountId) -> Balance) {
let mut ext: sp_io::TestExternalities = SystemConfig::default().build_storage::<Runtime>().unwrap().into();
ext.execute_with(|| {
Expand Down
67 changes: 67 additions & 0 deletions bridges/modules/shift-session-manager/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
[package]
name = "pallet-shift-session-manager"
description = "A Substrate Runtime module that selects 2/3 of initial validators for every session"
version = "0.1.0"
authors = ["Parity Technologies <admin@parity.io>"]
edition = "2018"
license = "GPL-3.0-or-later WITH Classpath-exception-2.0"

[dependencies]
codec = { package = "parity-scale-codec", version = "1.3.1", default-features = false }

# Substrate Based Dependencies

[dependencies.frame-support]
version = "2.0.0-rc6"
tag = 'v2.0.0-rc6'
default-features = false
git = "https://github.com/paritytech/substrate/"

[dependencies.frame-system]
version = "2.0.0-rc6"
tag = 'v2.0.0-rc6'
default-features = false
git = "https://github.com/paritytech/substrate/"

[dependencies.pallet-session]
version = "2.0.0-rc6"
tag = 'v2.0.0-rc6'
default-features = false
git = "https://github.com/paritytech/substrate/"

[dependencies.sp-core]
version = "2.0.0-rc6"
tag = 'v2.0.0-rc6'
default-features = false
git = "https://github.com/paritytech/substrate/"

[dependencies.sp-runtime]
version = "2.0.0-rc6"
tag = 'v2.0.0-rc6'
default-features = false
git = "https://github.com/paritytech/substrate/"

[dependencies.sp-staking]
version = "2.0.0-rc6"
tag = 'v2.0.0-rc6'
default-features = false
git = "https://github.com/paritytech/substrate/"

[dependencies.sp-std]
version = "2.0.0-rc6"
tag = 'v2.0.0-rc6'
default-features = false
git = "https://github.com/paritytech/substrate/"

[features]
default = ["std"]
std = [
"codec/std",
"frame-support/std",
"frame-system/std",
"pallet-session/std",
"sp-core/std",
"sp-runtime/std",
"sp-staking/std",
"sp-std/std",
]
Loading

0 comments on commit 6df0341

Please sign in to comment.