mirror of
https://github.com/serai-dex/serai.git
synced 2025-12-08 12:19:24 +00:00
Perform key share amortization on-chain to avoid discrepancies
This commit is contained in:
@@ -11,10 +11,7 @@ use ciphersuite::{group::GroupEncoding, Ciphersuite, Ristretto};
|
|||||||
use serai_client::{
|
use serai_client::{
|
||||||
SeraiError, Block, Serai, TemporalSerai,
|
SeraiError, Block, Serai, TemporalSerai,
|
||||||
primitives::{BlockHash, NetworkId},
|
primitives::{BlockHash, NetworkId},
|
||||||
validator_sets::{
|
validator_sets::{primitives::ValidatorSet, ValidatorSetsEvent},
|
||||||
primitives::{ValidatorSet, amortize_excess_key_shares},
|
|
||||||
ValidatorSetsEvent,
|
|
||||||
},
|
|
||||||
in_instructions::InInstructionsEvent,
|
in_instructions::InInstructionsEvent,
|
||||||
coins::CoinsEvent,
|
coins::CoinsEvent,
|
||||||
};
|
};
|
||||||
@@ -69,12 +66,7 @@ async fn handle_new_set<D: Db>(
|
|||||||
let set_participants =
|
let set_participants =
|
||||||
serai.participants(set.network).await?.expect("NewSet for set which doesn't exist");
|
serai.participants(set.network).await?.expect("NewSet for set which doesn't exist");
|
||||||
|
|
||||||
let mut set_data = set_participants
|
set_participants.into_iter().map(|(k, w)| (k, u16::try_from(w).unwrap())).collect::<Vec<_>>()
|
||||||
.into_iter()
|
|
||||||
.map(|(k, w)| (k, u16::try_from(w).unwrap()))
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
amortize_excess_key_shares(&mut set_data);
|
|
||||||
set_data
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let time = if let Ok(time) = block.time() {
|
let time = if let Ok(time) = block.time() {
|
||||||
|
|||||||
@@ -363,22 +363,27 @@ pub mod pallet {
|
|||||||
|
|
||||||
let allocation_per_key_share = Self::allocation_per_key_share(network).unwrap().0;
|
let allocation_per_key_share = Self::allocation_per_key_share(network).unwrap().0;
|
||||||
|
|
||||||
let mut iter = SortedAllocationsIter::<T>::new(network);
|
|
||||||
let mut participants = vec![];
|
let mut participants = vec![];
|
||||||
let mut key_shares = 0;
|
|
||||||
let mut total_stake = 0;
|
let mut total_stake = 0;
|
||||||
|
{
|
||||||
|
let mut iter = SortedAllocationsIter::<T>::new(network);
|
||||||
|
let mut key_shares = 0;
|
||||||
while key_shares < u64::from(MAX_KEY_SHARES_PER_SET) {
|
while key_shares < u64::from(MAX_KEY_SHARES_PER_SET) {
|
||||||
let Some((key, amount)) = iter.next() else { break };
|
let Some((key, amount)) = iter.next() else { break };
|
||||||
|
|
||||||
let these_key_shares = amount.0 / allocation_per_key_share;
|
let these_key_shares =
|
||||||
InSet::<T>::set(network, key, Some(these_key_shares));
|
(amount.0 / allocation_per_key_share).min(u64::from(MAX_KEY_SHARES_PER_SET));
|
||||||
participants.push((key, these_key_shares));
|
participants.push((key, these_key_shares));
|
||||||
|
|
||||||
// This can technically set key_shares to a value exceeding MAX_KEY_SHARES_PER_SET
|
|
||||||
// Off-chain, the key shares per validator will be accordingly adjusted
|
|
||||||
key_shares += these_key_shares;
|
key_shares += these_key_shares;
|
||||||
total_stake += amount.0;
|
total_stake += amount.0;
|
||||||
}
|
}
|
||||||
|
amortize_excess_key_shares(&mut participants);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (key, shares) in &participants {
|
||||||
|
InSet::<T>::set(network, key, Some(*shares));
|
||||||
|
}
|
||||||
TotalAllocatedStake::<T>::set(network, Some(Amount(total_stake)));
|
TotalAllocatedStake::<T>::set(network, Some(Amount(total_stake)));
|
||||||
|
|
||||||
let set = ValidatorSet { network, session };
|
let set = ValidatorSet { network, session };
|
||||||
|
|||||||
@@ -115,11 +115,11 @@ pub fn report_slashes_message(set: &ValidatorSet, slashes: &[(Public, u32)]) ->
|
|||||||
/// maximum.
|
/// maximum.
|
||||||
///
|
///
|
||||||
/// Reduction occurs by reducing each validator in a reverse round-robin.
|
/// Reduction occurs by reducing each validator in a reverse round-robin.
|
||||||
pub fn amortize_excess_key_shares(validators: &mut [(Public, u16)]) {
|
pub fn amortize_excess_key_shares(validators: &mut [(Public, u64)]) {
|
||||||
let total_key_shares = validators.iter().map(|(_, shares)| shares).sum::<u16>();
|
let total_key_shares = validators.iter().map(|(_, shares)| shares).sum::<u64>();
|
||||||
for i in 0 .. usize::from(
|
for i in 0 .. usize::try_from(total_key_shares.saturating_sub(u64::from(MAX_KEY_SHARES_PER_SET)))
|
||||||
total_key_shares.saturating_sub(u16::try_from(MAX_KEY_SHARES_PER_SET).unwrap()),
|
.unwrap()
|
||||||
) {
|
{
|
||||||
validators[validators.len() - ((i % validators.len()) + 1)].1 -= 1;
|
validators[validators.len() - ((i % validators.len()) + 1)].1 -= 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user