mirror of
https://github.com/serai-dex/serai.git
synced 2025-12-08 20:29:23 +00:00
Restore integration with pallet-babe to serai-validator-sets-pallet
This commit is contained in:
@@ -27,6 +27,9 @@ sp-api = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "16336
|
|||||||
frame-system = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "16336c737dbe833e9d138a256af99698aba637c7", default-features = false }
|
frame-system = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "16336c737dbe833e9d138a256af99698aba637c7", default-features = false }
|
||||||
frame-support = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "16336c737dbe833e9d138a256af99698aba637c7", default-features = false }
|
frame-support = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "16336c737dbe833e9d138a256af99698aba637c7", default-features = false }
|
||||||
|
|
||||||
|
pallet-session = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "16336c737dbe833e9d138a256af99698aba637c7", default-features = false }
|
||||||
|
pallet-babe = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "16336c737dbe833e9d138a256af99698aba637c7", default-features = false }
|
||||||
|
|
||||||
serai-abi = { path = "../abi", default-features = false, features = ["substrate"] }
|
serai-abi = { path = "../abi", default-features = false, features = ["substrate"] }
|
||||||
|
|
||||||
serai-coins-pallet = { path = "../coins", default-features = false }
|
serai-coins-pallet = { path = "../coins", default-features = false }
|
||||||
@@ -50,6 +53,9 @@ std = [
|
|||||||
"frame-system/std",
|
"frame-system/std",
|
||||||
"frame-support/std",
|
"frame-support/std",
|
||||||
|
|
||||||
|
"pallet-session/std",
|
||||||
|
"pallet-babe/std",
|
||||||
|
|
||||||
"serai-abi/std",
|
"serai-abi/std",
|
||||||
|
|
||||||
"serai-coins-pallet/std",
|
"serai-coins-pallet/std",
|
||||||
@@ -60,11 +66,16 @@ try-runtime = [
|
|||||||
|
|
||||||
"frame-system/try-runtime",
|
"frame-system/try-runtime",
|
||||||
"frame-support/try-runtime",
|
"frame-support/try-runtime",
|
||||||
|
|
||||||
|
"pallet-session/try-runtime",
|
||||||
|
"pallet-babe/try-runtime",
|
||||||
]
|
]
|
||||||
|
|
||||||
runtime-benchmarks = [
|
runtime-benchmarks = [
|
||||||
"frame-system/runtime-benchmarks",
|
"frame-system/runtime-benchmarks",
|
||||||
"frame-support/runtime-benchmarks",
|
"frame-support/runtime-benchmarks",
|
||||||
|
|
||||||
|
"pallet-babe/runtime-benchmarks",
|
||||||
]
|
]
|
||||||
|
|
||||||
default = ["std"]
|
default = ["std"]
|
||||||
|
|||||||
@@ -15,40 +15,6 @@ mod sessions;
|
|||||||
use sessions::{*, GenesisValidators as GenesisValidatorsContainer};
|
use sessions::{*, GenesisValidators as GenesisValidatorsContainer};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
use core::marker::PhantomData;
|
|
||||||
|
|
||||||
use scale::{Encode, Decode};
|
|
||||||
|
|
||||||
use sp_std::{vec, vec::Vec};
|
|
||||||
use sp_core::sr25519::{Public, Signature};
|
|
||||||
use sp_application_crypto::RuntimePublic;
|
|
||||||
use sp_session::{ShouldEndSession, GetSessionNumber, GetValidatorCount};
|
|
||||||
use sp_runtime::{KeyTypeId, ConsensusEngineId, traits::IsMember};
|
|
||||||
use sp_staking::offence::{ReportOffence, Offence, OffenceError};
|
|
||||||
|
|
||||||
use frame_system::{pallet_prelude::*, RawOrigin};
|
|
||||||
use frame_support::{
|
|
||||||
pallet_prelude::*,
|
|
||||||
sp_runtime::SaturatedConversion,
|
|
||||||
traits::{DisabledValidators, KeyOwnerProofSystem, FindAuthor},
|
|
||||||
BoundedVec, WeakBoundedVec, StoragePrefixedMap,
|
|
||||||
};
|
|
||||||
|
|
||||||
use serai_abi::primitives::*;
|
|
||||||
pub use validator_sets_primitives as primitives;
|
|
||||||
use primitives::*;
|
|
||||||
|
|
||||||
use serai_coins_pallet::{Pallet as Coins, AllowMint};
|
|
||||||
use dex_pallet::Pallet as Dex;
|
|
||||||
|
|
||||||
use pallet_babe::{
|
|
||||||
Pallet as Babe, AuthorityId as BabeAuthorityId, EquivocationOffence as BabeEquivocationOffence,
|
|
||||||
};
|
|
||||||
use pallet_grandpa::{
|
|
||||||
Pallet as Grandpa, AuthorityId as GrandpaAuthorityId,
|
|
||||||
EquivocationOffence as GrandpaEquivocationOffence,
|
|
||||||
};
|
|
||||||
|
|
||||||
#[derive(Debug, Encode, Decode, PartialEq, Eq, Clone)]
|
#[derive(Debug, Encode, Decode, PartialEq, Eq, Clone)]
|
||||||
pub struct MembershipProof<T: pallet::Config>(pub Public, pub PhantomData<T>);
|
pub struct MembershipProof<T: pallet::Config>(pub Public, pub PhantomData<T>);
|
||||||
impl<T: pallet::Config> GetSessionNumber for MembershipProof<T> {
|
impl<T: pallet::Config> GetSessionNumber for MembershipProof<T> {
|
||||||
@@ -79,7 +45,10 @@ mod pallet {
|
|||||||
use sp_core::sr25519::Public;
|
use sp_core::sr25519::Public;
|
||||||
|
|
||||||
use frame_system::pallet_prelude::*;
|
use frame_system::pallet_prelude::*;
|
||||||
use frame_support::pallet_prelude::*;
|
use frame_support::{pallet_prelude::*, traits::OneSessionHandler};
|
||||||
|
|
||||||
|
use pallet_session::ShouldEndSession;
|
||||||
|
use pallet_babe::Pallet as Babe;
|
||||||
|
|
||||||
use serai_abi::primitives::{
|
use serai_abi::primitives::{
|
||||||
crypto::SignedEmbeddedEllipticCurveKeys,
|
crypto::SignedEmbeddedEllipticCurveKeys,
|
||||||
@@ -96,9 +65,12 @@ mod pallet {
|
|||||||
|
|
||||||
#[pallet::config]
|
#[pallet::config]
|
||||||
pub trait Config:
|
pub trait Config:
|
||||||
frame_system::Config + serai_coins_pallet::Config<serai_coins_pallet::CoinsInstance>
|
frame_system::Config
|
||||||
|
+ pallet_session::Config
|
||||||
|
+ pallet_babe::Config
|
||||||
|
+ serai_coins_pallet::Config<serai_coins_pallet::CoinsInstance>
|
||||||
{
|
{
|
||||||
// type ShouldEndSession: ShouldEndSession<BlockNumberFor<Self>>;
|
type ShouldEndSession: ShouldEndSession<BlockNumberFor<Self>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[pallet::genesis_config]
|
#[pallet::genesis_config]
|
||||||
@@ -108,58 +80,9 @@ mod pallet {
|
|||||||
pub participants: Vec<(T::AccountId, Vec<SignedEmbeddedEllipticCurveKeys>)>,
|
pub participants: Vec<(T::AccountId, Vec<SignedEmbeddedEllipticCurveKeys>)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[pallet::genesis_build]
|
|
||||||
impl<T: Config> BuildGenesisConfig for GenesisConfig<T> {
|
|
||||||
fn build(&self) {
|
|
||||||
for (participant, keys) in &self.participants {
|
|
||||||
for (network, keys) in ExternalNetworkId::all().zip(keys.iter().cloned()) {
|
|
||||||
assert_eq!(network, keys.network());
|
|
||||||
<Abstractions<T> as crate::EmbeddedEllipticCurveKeys>::set_embedded_elliptic_curve_keys(
|
|
||||||
*participant,
|
|
||||||
keys,
|
|
||||||
)
|
|
||||||
.expect("genesis embedded elliptic curve keys weren't valid");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for network in NetworkId::all() {
|
|
||||||
Abstractions::<T>::attempt_new_session(network, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[pallet::pallet]
|
#[pallet::pallet]
|
||||||
pub struct Pallet<T>(PhantomData<T>);
|
pub struct Pallet<T>(PhantomData<T>);
|
||||||
|
|
||||||
/*
|
|
||||||
/// The allocation required per key share.
|
|
||||||
// Uses Identity for the lookup to avoid a hash of a severely limited fixed key-space.
|
|
||||||
#[pallet::storage]
|
|
||||||
#[pallet::getter(fn allocation_per_key_share)]
|
|
||||||
pub type AllocationPerKeyShare<T: Config> =
|
|
||||||
StorageMap<_, Identity, NetworkId, Amount, OptionQuery>;
|
|
||||||
/// The validators selected to be in-set (and their key shares), regardless of if removed.
|
|
||||||
///
|
|
||||||
/// This method allows iterating over all validators and their stake.
|
|
||||||
#[pallet::storage]
|
|
||||||
#[pallet::getter(fn participants_for_latest_decided_set)]
|
|
||||||
pub(crate) type Participants<T: Config> = StorageMap<
|
|
||||||
_,
|
|
||||||
Identity,
|
|
||||||
NetworkId,
|
|
||||||
BoundedVec<(Public, u64), ConstU32<{ MAX_KEY_SHARES_PER_SET_U32 }>>,
|
|
||||||
OptionQuery,
|
|
||||||
>;
|
|
||||||
/// The validators selected to be in-set, regardless of if removed.
|
|
||||||
///
|
|
||||||
/// This method allows quickly checking for presence in-set and looking up a validator's key
|
|
||||||
/// shares.
|
|
||||||
// Uses Identity for NetworkId to avoid a hash of a severely limited fixed key-space.
|
|
||||||
#[pallet::storage]
|
|
||||||
pub(crate) type InSet<T: Config> =
|
|
||||||
StorageDoubleMap<_, Identity, NetworkId, Blake2_128Concat, Public, u64, OptionQuery>;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
struct Abstractions<T: Config>(PhantomData<T>);
|
struct Abstractions<T: Config>(PhantomData<T>);
|
||||||
|
|
||||||
// Satisfy the `EmbeddedEllipticCurveKeys` abstraction
|
// Satisfy the `EmbeddedEllipticCurveKeys` abstraction
|
||||||
@@ -281,20 +204,6 @@ mod pallet {
|
|||||||
session: Session,
|
session: Session,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Config> Pallet<T> {
|
|
||||||
fn new_set(network: NetworkId) {
|
|
||||||
// TODO
|
|
||||||
let include_genesis_validators = true;
|
|
||||||
// TODO: prevent new set if it doesn't have enough stake for economic security.
|
|
||||||
Abstractions::<T>::attempt_new_session(network, include_genesis_validators)
|
|
||||||
|
|
||||||
/* TODO
|
|
||||||
let set = ValidatorSet { network, session };
|
|
||||||
Pallet::<T>::deposit_event(Event::NewSet { set });
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#[pallet::error]
|
#[pallet::error]
|
||||||
@@ -307,20 +216,43 @@ mod pallet {
|
|||||||
DeallocationError(DeallocationError),
|
DeallocationError(DeallocationError),
|
||||||
}
|
}
|
||||||
|
|
||||||
/* TODO
|
#[pallet::genesis_build]
|
||||||
#[pallet::hooks]
|
impl<T: Config> BuildGenesisConfig for GenesisConfig<T> {
|
||||||
impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> {
|
fn build(&self) {
|
||||||
fn on_initialize(n: BlockNumberFor<T>) -> Weight {
|
for (participant, keys) in &self.participants {
|
||||||
if T::ShouldEndSession::should_end_session(n) {
|
for (network, keys) in ExternalNetworkId::all().zip(keys.iter().cloned()) {
|
||||||
Self::rotate_session();
|
assert_eq!(network, keys.network());
|
||||||
// TODO: set the proper weights
|
<Abstractions<T> as crate::EmbeddedEllipticCurveKeys>::set_embedded_elliptic_curve_keys(
|
||||||
T::BlockWeights::get().max_block
|
*participant,
|
||||||
} else {
|
keys,
|
||||||
Weight::zero()
|
)
|
||||||
|
.expect("genesis embedded elliptic curve keys weren't valid");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
for network in NetworkId::all() {
|
||||||
|
assert!(
|
||||||
|
Abstractions::<T>::attempt_new_session(network, true),
|
||||||
|
"failed to attempt a new session on genesis"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Immediately accept the handover for the genesis validators, for the Serai network
|
||||||
|
Abstractions::<T>::accept_handover(NetworkId::Serai);
|
||||||
|
// And decide the next session for the Serai network, as BABE requires selecting the next one
|
||||||
|
// already
|
||||||
|
assert!(
|
||||||
|
Abstractions::<T>::attempt_new_session(NetworkId::Serai, true),
|
||||||
|
"failed to attempt the next session for the Serai network on genesis"
|
||||||
|
);
|
||||||
|
|
||||||
|
// Spawn BABE's genesis session
|
||||||
|
Babe::<T>::on_genesis_session(
|
||||||
|
Abstractions::<T>::serai_validators(Session(0))
|
||||||
|
.iter()
|
||||||
|
.map(|(validator, key)| (validator, pallet_babe::AuthorityId::from(*key))),
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
|
|
||||||
impl<T: Config> Pallet<T> {
|
impl<T: Config> Pallet<T> {
|
||||||
fn account() -> T::AccountId {
|
fn account() -> T::AccountId {
|
||||||
@@ -366,37 +298,19 @@ mod pallet {
|
|||||||
Abstractions::<T>::stake_for_current_validator_set(network)
|
Abstractions::<T>::stake_for_current_validator_set(network)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn attempt_external_network_session_rotation() {
|
||||||
|
for network in ExternalNetworkId::all() {
|
||||||
|
let include_genesis_validators = true; // TODO
|
||||||
|
Abstractions::<T>::attempt_new_session(network.into(), include_genesis_validators);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* TODO
|
||||||
|
Dex::<T>::on_new_session(network);
|
||||||
|
Grandpa::new_session
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
// is_bft returns if the network is able to survive any single node becoming byzantine.
|
|
||||||
fn is_bft(network: NetworkId) -> bool {
|
|
||||||
let allocation_per_key_share = AllocationPerKeyShare::<T>::get(network).unwrap().0;
|
|
||||||
|
|
||||||
let mut validators_len = 0;
|
|
||||||
let mut top = None;
|
|
||||||
let mut key_shares = 0;
|
|
||||||
for (_, amount) in Abstractions::<T>::iter_allocations(network, allocation_per_key_share) {
|
|
||||||
validators_len += 1;
|
|
||||||
|
|
||||||
key_shares += amount.0 / allocation_per_key_share;
|
|
||||||
if top.is_none() {
|
|
||||||
top = Some(key_shares);
|
|
||||||
}
|
|
||||||
|
|
||||||
if key_shares > u64::from(MAX_KEY_SHARES_PER_SET_U32) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let Some(top) = top else { return false };
|
|
||||||
|
|
||||||
// key_shares may be over MAX_KEY_SHARES_PER_SET, which will cause a round robin reduction of
|
|
||||||
// each validator's key shares until their sum is MAX_KEY_SHARES_PER_SET
|
|
||||||
// post_amortization_key_shares_for_top_validator yields what the top validator's key shares
|
|
||||||
// would be after such a reduction, letting us evaluate this correctly
|
|
||||||
let top = post_amortization_key_shares_for_top_validator(validators_len, top, key_shares);
|
|
||||||
(top * 3) < key_shares.min(MAX_KEY_SHARES_PER_SET_U32.into())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn increase_allocation(
|
fn increase_allocation(
|
||||||
network: NetworkId,
|
network: NetworkId,
|
||||||
account: T::AccountId,
|
account: T::AccountId,
|
||||||
@@ -410,7 +324,6 @@ mod pallet {
|
|||||||
Err(Error::<T>::AllocationWouldPreventFaultTolerance)?;
|
Err(Error::<T>::AllocationWouldPreventFaultTolerance)?;
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
Abstractions::<T>::increase_allocation(network, account, amount, block_reward)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn session_to_unlock_on_for_current_set(network: NetworkId) -> Option<Session> {
|
fn session_to_unlock_on_for_current_set(network: NetworkId) -> Option<Session> {
|
||||||
@@ -477,54 +390,6 @@ mod pallet {
|
|||||||
Sessions::<T>::decrease_allocation(network, account, amount)
|
Sessions::<T>::decrease_allocation(network, account, amount)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Checks if this session has completed the handover from the prior session.
|
|
||||||
fn handover_completed(network: NetworkId, session: Session) -> bool {
|
|
||||||
let Some(current_session) = Self::session(network) else { return false };
|
|
||||||
|
|
||||||
// If the session we've been queried about is old, it must have completed its handover
|
|
||||||
if current_session.0 > session.0 {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
// If the session we've been queried about has yet to start, it can't have completed its
|
|
||||||
// handover
|
|
||||||
if current_session.0 < session.0 {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
let NetworkId::External(n) = network else {
|
|
||||||
// Handover is automatically complete for Serai as it doesn't have a handover protocol
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
|
|
||||||
// The current session must have set keys for its handover to be completed
|
|
||||||
if !Keys::<T>::contains_key(ExternalValidatorSet { network: n, session }) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// This must be the first session (which has set keys) OR the prior session must have been
|
|
||||||
// retired (signified by its keys no longer being present)
|
|
||||||
(session.0 == 0) ||
|
|
||||||
(!Keys::<T>::contains_key(ExternalValidatorSet {
|
|
||||||
network: n,
|
|
||||||
session: Session(session.0 - 1),
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn new_session() {
|
|
||||||
for network in serai_abi::primitives::NETWORKS {
|
|
||||||
// If this network hasn't started sessions yet, don't start one now
|
|
||||||
let Some(current_session) = Self::session(network) else { continue };
|
|
||||||
// Only spawn a new set if:
|
|
||||||
// - This is Serai, as we need to rotate Serai upon a new session (per Babe)
|
|
||||||
// - The current set was actually established with a completed handover protocol
|
|
||||||
if (network == NetworkId::Serai) || Self::handover_completed(network, current_session) {
|
|
||||||
Pallet::<T>::new_set(network);
|
|
||||||
// let the Dex know session is rotated.
|
|
||||||
Dex::<T>::on_new_session(network);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: This is called retire_set, yet just starts retiring the set
|
// TODO: This is called retire_set, yet just starts retiring the set
|
||||||
// Update the nomenclature within this function
|
// Update the nomenclature within this function
|
||||||
pub fn retire_set(set: ValidatorSet) {
|
pub fn retire_set(set: ValidatorSet) {
|
||||||
@@ -553,48 +418,12 @@ mod pallet {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Take the amount deallocatable.
|
|
||||||
///
|
|
||||||
/// `session` refers to the Session the stake becomes deallocatable on.
|
|
||||||
fn take_deallocatable_amount(
|
|
||||||
network: NetworkId,
|
|
||||||
session: Session,
|
|
||||||
key: Public,
|
|
||||||
) -> Option<Amount> {
|
|
||||||
// Check this Session has properly started, completing the handover from the prior session.
|
|
||||||
if !Self::handover_completed(network, session) {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
PendingDeallocations::<T>::take((network, key), session)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn rotate_session() {
|
pub(crate) fn rotate_session() {
|
||||||
// next serai validators that is in the queue.
|
|
||||||
let now_validators = Participants::<T>::get(NetworkId::Serai)
|
|
||||||
.expect("no Serai participants upon rotate_session");
|
|
||||||
let prior_serai_session = Self::session(NetworkId::Serai).unwrap();
|
|
||||||
|
|
||||||
// TODO: T::SessionHandler::on_before_session_ending() was here.
|
|
||||||
// end the current serai session.
|
|
||||||
Self::retire_set(ValidatorSet { network: NetworkId::Serai, session: prior_serai_session });
|
Self::retire_set(ValidatorSet { network: NetworkId::Serai, session: prior_serai_session });
|
||||||
|
|
||||||
// make a new session and get the next validator set.
|
// make a new session and get the next validator set.
|
||||||
Self::new_session();
|
Self::new_session();
|
||||||
|
|
||||||
// Update Babe and Grandpa
|
|
||||||
let session = prior_serai_session.0 + 1;
|
|
||||||
let next_validators = Participants::<T>::get(NetworkId::Serai).unwrap();
|
|
||||||
Babe::<T>::enact_epoch_change(
|
|
||||||
WeakBoundedVec::force_from(
|
|
||||||
now_validators.iter().copied().map(|(id, w)| (BabeAuthorityId::from(id), w)).collect(),
|
|
||||||
None,
|
|
||||||
),
|
|
||||||
WeakBoundedVec::force_from(
|
|
||||||
next_validators.iter().copied().map(|(id, w)| (BabeAuthorityId::from(id), w)).collect(),
|
|
||||||
None,
|
|
||||||
),
|
|
||||||
Some(session),
|
|
||||||
);
|
|
||||||
Grandpa::<T>::new_session(
|
Grandpa::<T>::new_session(
|
||||||
true,
|
true,
|
||||||
session,
|
session,
|
||||||
@@ -729,17 +558,69 @@ mod pallet {
|
|||||||
false
|
false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the external network key for a given external network
|
|
||||||
pub fn external_network_key(network: ExternalNetworkId) -> Option<Vec<u8>> {
|
|
||||||
let current_session = Self::session(NetworkId::from(network))?;
|
|
||||||
let keys = Keys::<T>::get(ExternalValidatorSet { network, session: current_session })?;
|
|
||||||
|
|
||||||
Some(keys.1.into_inner())
|
|
||||||
}
|
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[pallet::hooks]
|
||||||
|
impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> {
|
||||||
|
fn on_initialize(n: BlockNumberFor<T>) -> Weight {
|
||||||
|
if <T as Config>::ShouldEndSession::should_end_session(n) {
|
||||||
|
Babe::<T>::on_before_session_ending();
|
||||||
|
|
||||||
|
{
|
||||||
|
// Accept the hand-over to the next session for the Serai network
|
||||||
|
Abstractions::<T>::accept_handover(NetworkId::Serai);
|
||||||
|
// Decide the next session for the Serai network
|
||||||
|
let include_genesis_validators = true; // TODO
|
||||||
|
assert!(
|
||||||
|
Abstractions::<T>::attempt_new_session(NetworkId::Serai, include_genesis_validators),
|
||||||
|
"failed to attempt the next session for the Serai network"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update BABE
|
||||||
|
{
|
||||||
|
let current_serai_session = Abstractions::<T>::current_session(NetworkId::Serai)
|
||||||
|
.expect("never selected a session for Serai");
|
||||||
|
let latest_decided_serai_session =
|
||||||
|
Abstractions::<T>::latest_decided_session(NetworkId::Serai)
|
||||||
|
.expect("current session yet no latest decided session for Serai");
|
||||||
|
assert_eq!(
|
||||||
|
Session(current_serai_session.0 + 1),
|
||||||
|
latest_decided_serai_session,
|
||||||
|
"latest decided Serai session wasn't the session after the current session"
|
||||||
|
);
|
||||||
|
|
||||||
|
let prior_serai_validators = Abstractions::<T>::serai_validators(Session(
|
||||||
|
current_serai_session.0.checked_sub(1).expect("ShouldEndSession triggered on genesis"),
|
||||||
|
));
|
||||||
|
assert!(
|
||||||
|
!prior_serai_validators.is_empty(),
|
||||||
|
"prior Serai validators weren't able to be fetched from storage",
|
||||||
|
);
|
||||||
|
let serai_validators = Abstractions::<T>::serai_validators(current_serai_session);
|
||||||
|
let queued_serai_validators =
|
||||||
|
Abstractions::<T>::serai_validators(latest_decided_serai_session);
|
||||||
|
|
||||||
|
fn map((validator, key): &(Public, Public)) -> (&Public, pallet_babe::AuthorityId) {
|
||||||
|
(validator, (*key).into())
|
||||||
|
}
|
||||||
|
Babe::<T>::on_new_session(
|
||||||
|
prior_serai_validators != serai_validators,
|
||||||
|
serai_validators.iter().map(map),
|
||||||
|
queued_serai_validators.iter().map(map),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Self::attempt_external_network_session_rotation();
|
||||||
|
|
||||||
|
Weight::zero() // TODO
|
||||||
|
} else {
|
||||||
|
Weight::zero()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[pallet::call]
|
#[pallet::call]
|
||||||
impl<T: Config> Pallet<T> {
|
impl<T: Config> Pallet<T> {
|
||||||
/*
|
/*
|
||||||
|
|||||||
@@ -148,7 +148,9 @@ pub(crate) trait Sessions {
|
|||||||
///
|
///
|
||||||
/// Doesn't spawn the next session if the latest decided session has yet to start. This bounds
|
/// Doesn't spawn the next session if the latest decided session has yet to start. This bounds
|
||||||
/// the current session to be the latest decided session or the one prior.
|
/// the current session to be the latest decided session or the one prior.
|
||||||
fn attempt_new_session(network: NetworkId, include_genesis_validators: bool);
|
///
|
||||||
|
/// Returns `true` if the next session was decided. Returns `false` otherwise.
|
||||||
|
fn attempt_new_session(network: NetworkId, include_genesis_validators: bool) -> bool;
|
||||||
|
|
||||||
/// Have the latest-decided session accept the handover from the current set, if one exists.
|
/// Have the latest-decided session accept the handover from the current set, if one exists.
|
||||||
///
|
///
|
||||||
@@ -215,10 +217,23 @@ pub(crate) trait Sessions {
|
|||||||
|
|
||||||
/// The stake for the current validator set.
|
/// The stake for the current validator set.
|
||||||
fn stake_for_current_validator_set(network: NetworkId) -> Option<Amount>;
|
fn stake_for_current_validator_set(network: NetworkId) -> Option<Amount>;
|
||||||
|
|
||||||
|
/// The selected validators for a set.
|
||||||
|
///
|
||||||
|
/// This will return an empty iterator if the validators have yet to be decided, or if the
|
||||||
|
/// selected validators were cleared due to being historic.
|
||||||
|
fn selected_validators(set: ValidatorSet) -> impl Iterator<Item = (Public, KeySharesStruct)>;
|
||||||
|
|
||||||
|
/// The validators for the Serai network, in the form expected by BABE, GRANDPA.
|
||||||
|
fn serai_validators(session: Session) -> Vec<(Public, Public)> {
|
||||||
|
Self::selected_validators(ValidatorSet { network: NetworkId::Serai, session })
|
||||||
|
.map(|(validator, _key_shares)| (validator, validator))
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Storage: SessionsStorage> Sessions for Storage {
|
impl<Storage: SessionsStorage> Sessions for Storage {
|
||||||
fn attempt_new_session(network: NetworkId, include_genesis_validators: bool) {
|
fn attempt_new_session(network: NetworkId, include_genesis_validators: bool) -> bool {
|
||||||
// If we haven't rotated to the latest decided session, return
|
// If we haven't rotated to the latest decided session, return
|
||||||
// This prevents us from deciding session #n+2 when we haven't even started #n+1
|
// This prevents us from deciding session #n+2 when we haven't even started #n+1
|
||||||
let current_session = Storage::CurrentSession::get(network);
|
let current_session = Storage::CurrentSession::get(network);
|
||||||
@@ -228,12 +243,12 @@ impl<Storage: SessionsStorage> Sessions for Storage {
|
|||||||
// If the latest decided session is current, we can decide the next session
|
// If the latest decided session is current, we can decide the next session
|
||||||
} else {
|
} else {
|
||||||
// If we already have a pending session, don't spawn a new one
|
// If we already have a pending session, don't spawn a new one
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
(Some(_current), None) => unreachable!("current session but never decided a session"),
|
(Some(_current), None) => unreachable!("current session but never decided a session"),
|
||||||
// If we decided our first session, but didn't start it, don't decide another session
|
// If we decided our first session, but didn't start it, don't decide another session
|
||||||
(None, Some(_latest)) => return,
|
(None, Some(_latest)) => return false,
|
||||||
(None, None) => {
|
(None, None) => {
|
||||||
// If we've never started a session, we can decide the first session
|
// If we've never started a session, we can decide the first session
|
||||||
}
|
}
|
||||||
@@ -290,6 +305,8 @@ impl<Storage: SessionsStorage> Sessions for Storage {
|
|||||||
key_shares,
|
key_shares,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
fn accept_handover(network: NetworkId) {
|
fn accept_handover(network: NetworkId) {
|
||||||
@@ -524,4 +541,8 @@ impl<Storage: SessionsStorage> Sessions for Storage {
|
|||||||
fn stake_for_current_validator_set(network: NetworkId) -> Option<Amount> {
|
fn stake_for_current_validator_set(network: NetworkId) -> Option<Amount> {
|
||||||
Storage::TotalAllocatedStake::get(network)
|
Storage::TotalAllocatedStake::get(network)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn selected_validators(set: ValidatorSet) -> impl Iterator<Item = (Public, KeySharesStruct)> {
|
||||||
|
selected_validators::<Storage::SelectedValidators>(set)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user