Merge branch 'develop' into next

This is an initial resolution of conflicts which does not work.
This commit is contained in:
Luke Parker
2025-01-30 00:56:29 -05:00
128 changed files with 1835 additions and 44261 deletions

View File

@@ -334,11 +334,13 @@ pub mod pallet {
/// The generated key pair for a given validator set instance.
#[pallet::storage]
#[pallet::getter(fn keys)]
pub type Keys<T: Config> = StorageMap<_, Twox64Concat, ValidatorSet, KeyPair, OptionQuery>;
pub type Keys<T: Config> =
StorageMap<_, Twox64Concat, ExternalValidatorSet, KeyPair, OptionQuery>;
/// The key for validator sets which can (and still need to) publish their slash reports.
#[pallet::storage]
pub type PendingSlashReport<T: Config> = StorageMap<_, Identity, NetworkId, Public, OptionQuery>;
pub type PendingSlashReport<T: Config> =
StorageMap<_, Identity, ExternalNetworkId, Public, OptionQuery>;
/// Disabled validators.
#[pallet::storage]
@@ -361,7 +363,7 @@ pub mod pallet {
removed: T::AccountId,
},
KeyGen {
set: ValidatorSet,
set: ExternalValidatorSet,
key_pair: KeyPair,
},
AcceptedHandover {
@@ -636,14 +638,16 @@ pub mod pallet {
amount: Amount,
) -> Result<bool, DispatchError> {
// Check it's safe to decrease this set's stake by this amount
let new_total_staked = Self::total_allocated_stake(network)
.unwrap()
.0
.checked_sub(amount.0)
.ok_or(Error::<T>::NotEnoughAllocated)?;
let required_stake = Self::required_stake_for_network(network);
if new_total_staked < required_stake {
Err(Error::<T>::DeallocationWouldRemoveEconomicSecurity)?;
if let NetworkId::External(n) = network {
let new_total_staked = Self::total_allocated_stake(NetworkId::from(n))
.unwrap()
.0
.checked_sub(amount.0)
.ok_or(Error::<T>::NotEnoughAllocated)?;
let required_stake = Self::required_stake_for_network(n);
if new_total_staked < required_stake {
Err(Error::<T>::DeallocationWouldRemoveEconomicSecurity)?;
}
}
let old_allocation =
@@ -726,20 +730,23 @@ pub mod pallet {
return false;
}
// Handover is automatically complete for Serai as it doesn't have a handover protocol
if network == NetworkId::Serai {
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(ValidatorSet { network, session }) {
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(ValidatorSet { network, session: Session(session.0 - 1) }))
(!Keys::<T>::contains_key(ExternalValidatorSet {
network: n,
session: Session(session.0 - 1),
}))
}
fn new_session() {
@@ -769,19 +776,23 @@ pub mod pallet {
// TODO: This is called retire_set, yet just starts retiring the set
// Update the nomenclature within this function
pub fn retire_set(set: ValidatorSet) {
// If the prior prior set didn't report, emit they're retired now
if PendingSlashReport::<T>::get(set.network).is_some() {
Self::deposit_event(Event::SetRetired {
set: ValidatorSet { network: set.network, session: Session(set.session.0 - 1) },
});
}
// Serai doesn't set keys and network slashes are handled by BABE/GRANDPA
if set.network != NetworkId::Serai {
if let NetworkId::External(n) = set.network {
// If the prior prior set didn't report, emit they're retired now
if PendingSlashReport::<T>::get(n).is_some() {
Self::deposit_event(Event::SetRetired {
set: ValidatorSet { network: set.network, session: Session(set.session.0 - 1) },
});
}
// This overwrites the prior value as the prior to-report set's stake presumably just
// unlocked, making their report unenforceable
let keys = Keys::<T>::take(set).unwrap();
PendingSlashReport::<T>::set(set.network, Some(keys.0));
let keys =
Keys::<T>::take(ExternalValidatorSet { network: n, session: set.session }).unwrap();
PendingSlashReport::<T>::set(n, Some(keys.0));
} else {
// emit the event for serai network
Self::deposit_event(Event::SetRetired { set });
}
// We're retiring this set because the set after it accepted the handover
@@ -853,7 +864,7 @@ pub mod pallet {
}
/// Returns the required stake in terms SRI for a given `Balance`.
pub fn required_stake(balance: &Balance) -> SubstrateAmount {
pub fn required_stake(balance: &ExternalBalance) -> SubstrateAmount {
use dex_pallet::HigherPrecisionBalance;
// This is inclusive to an increase in accuracy
@@ -876,11 +887,11 @@ pub mod pallet {
}
/// Returns the current total required stake for a given `network`.
pub fn required_stake_for_network(network: NetworkId) -> SubstrateAmount {
pub fn required_stake_for_network(network: ExternalNetworkId) -> SubstrateAmount {
let mut total_required = 0;
for coin in network.coins() {
let supply = Coins::<T>::supply(coin);
total_required += Self::required_stake(&Balance { coin: *coin, amount: Amount(supply) });
let supply = Coins::<T>::supply(Coin::from(coin));
total_required += Self::required_stake(&ExternalBalance { coin, amount: Amount(supply) });
}
total_required
}
@@ -976,7 +987,7 @@ pub mod pallet {
#[pallet::weight(0)] // TODO
pub fn set_keys(
origin: OriginFor<T>,
network: NetworkId,
network: ExternalNetworkId,
key_pair: KeyPair,
signature_participants: bitvec::vec::BitVec<u8, bitvec::order::Lsb0>,
signature: Signature,
@@ -988,8 +999,8 @@ pub mod pallet {
let _ = signature_participants;
let _ = signature;
let session = Self::session(network).unwrap();
let set = ValidatorSet { network, session };
let session = Self::session(NetworkId::from(network)).unwrap();
let set = ExternalValidatorSet { network, session };
Keys::<T>::set(set, Some(key_pair.clone()));
@@ -997,7 +1008,7 @@ pub mod pallet {
// We generally set TotalAllocatedStake when the prior set retires, and the new set is fully
// active and liable. Since this is the first set, there is no prior set to wait to retire
if session == Session(0) {
Self::set_total_allocated_stake(network);
Self::set_total_allocated_stake(NetworkId::from(network));
}
Self::deposit_event(Event::KeyGen { set, key_pair });
@@ -1009,7 +1020,7 @@ pub mod pallet {
#[pallet::weight(0)] // TODO
pub fn report_slashes(
origin: OriginFor<T>,
network: NetworkId,
network: ExternalNetworkId,
slashes: SlashReport,
signature: Signature,
) -> DispatchResult {
@@ -1024,7 +1035,10 @@ pub mod pallet {
// Emit set retireed
Pallet::<T>::deposit_event(Event::SetRetired {
set: ValidatorSet { network, session: Session(Self::session(network).unwrap().0 - 1) },
set: ValidatorSet {
network: network.into(),
session: Session(Self::session(NetworkId::from(network)).unwrap().0 - 1),
},
});
Ok(())
@@ -1124,17 +1138,12 @@ pub mod pallet {
Call::set_keys { network, ref key_pair, ref signature_participants, ref signature } => {
let network = *network;
// Don't allow the Serai set to set_keys, as they have no reason to do so
if network == NetworkId::Serai {
Err(InvalidTransaction::Custom(0))?;
}
// Confirm this set has a session
let Some(current_session) = Self::session(network) else {
let Some(current_session) = Self::session(NetworkId::from(network)) else {
Err(InvalidTransaction::Custom(1))?
};
let set = ValidatorSet { network, session: current_session };
let set = ExternalValidatorSet { network, session: current_session };
// Confirm it has yet to set keys
if Keys::<T>::get(set).is_some() {
@@ -1143,7 +1152,7 @@ pub mod pallet {
// This is a needed precondition as this uses storage variables for the latest decided
// session on this assumption
assert_eq!(Pallet::<T>::latest_decided_session(network), Some(current_session));
assert_eq!(Pallet::<T>::latest_decided_session(network.into()), Some(current_session));
let participants =
Participants::<T>::get(network).expect("session existed without participants");
@@ -1158,7 +1167,7 @@ pub mod pallet {
let mut signing_key_shares = 0;
for (participant, in_use) in participants.into_iter().zip(signature_participants) {
let participant = participant.0;
let shares = InSet::<T>::get(network, participant)
let shares = InSet::<T>::get(NetworkId::from(network), participant)
.expect("participant from Participants wasn't InSet");
all_key_shares += shares;
@@ -1192,17 +1201,14 @@ pub mod pallet {
}
Call::report_slashes { network, ref slashes, ref signature } => {
let network = *network;
// Don't allow Serai to publish a slash report as BABE/GRANDPA handles slashes directly
if network == NetworkId::Serai {
Err(InvalidTransaction::Custom(0))?;
}
let Some(key) = PendingSlashReport::<T>::take(network) else {
// Assumed already published
Err(InvalidTransaction::Stale)?
};
// There must have been a previous session is PendingSlashReport is populated
let set =
ValidatorSet { network, session: Session(Self::session(network).unwrap().0 - 1) };
ExternalValidatorSet { network, session: Session(Self::session(network).unwrap().0 - 1) };
if !key.verify(&slashes.report_slashes_message(), signature) {
Err(InvalidTransaction::BadProof)?;
}
@@ -1228,13 +1234,14 @@ pub mod pallet {
}
impl<T: Config> AllowMint for Pallet<T> {
fn is_allowed(balance: &Balance) -> bool {
fn is_allowed(balance: &ExternalBalance) -> bool {
// get the required stake
let current_required = Self::required_stake_for_network(balance.coin.network());
let new_required = current_required + Self::required_stake(balance);
// get the total stake for the network & compare.
let staked = Self::total_allocated_stake(balance.coin.network()).unwrap_or(Amount(0));
let staked =
Self::total_allocated_stake(NetworkId::from(balance.coin.network())).unwrap_or(Amount(0));
staked.0 >= new_required
}
}