Skip to content

Commit

Permalink
Implement "Use 16-bit random value in validator filter"
Browse files Browse the repository at this point in the history
  • Loading branch information
michaelsproul committed Dec 20, 2024
1 parent c31f1cc commit 282eefb
Showing 1 changed file with 40 additions and 6 deletions.
46 changes: 40 additions & 6 deletions consensus/types/src/beacon_state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ mod tests;

pub const CACHED_EPOCHS: usize = 3;
const MAX_RANDOM_BYTE: u64 = (1 << 8) - 1;
const MAX_RANDOM_VALUE: u64 = (1 << 16) - 1;

pub type Validators<E> = List<Validator, <E as EthSpec>::ValidatorRegistryLimit>;
pub type Balances<E> = List<u64, <E as EthSpec>::ValidatorRegistryLimit>;
Expand Down Expand Up @@ -895,6 +896,11 @@ impl<E: EthSpec> BeaconState<E> {
}

let max_effective_balance = spec.max_effective_balance_for_fork(self.fork_name_unchecked());
let max_random_value = if self.fork_name_unchecked().electra_enabled() {
MAX_RANDOM_VALUE
} else {
MAX_RANDOM_BYTE
};

let mut i = 0;
loop {
Expand All @@ -908,17 +914,25 @@ impl<E: EthSpec> BeaconState<E> {
let candidate_index = *indices
.get(shuffled_index)
.ok_or(Error::ShuffleIndexOutOfBounds(shuffled_index))?;
let random_byte = Self::shuffling_random_byte(i, seed)?;
let random_value = self.shuffling_random_value(i, seed)?;
let effective_balance = self.get_effective_balance(candidate_index)?;
if effective_balance.safe_mul(MAX_RANDOM_BYTE)?
>= max_effective_balance.safe_mul(u64::from(random_byte))?
if effective_balance.safe_mul(max_random_value)?
>= max_effective_balance.safe_mul(random_value)?
{
return Ok(candidate_index);
}
i.safe_add_assign(1)?;
}
}

fn shuffling_random_value(&self, i: usize, seed: &[u8]) -> Result<u64, Error> {
if self.fork_name_unchecked().electra_enabled() {
Self::shuffling_random_u16_electra(i, seed).map(u64::from)
} else {
Self::shuffling_random_byte(i, seed).map(u64::from)
}
}

/// Get a random byte from the given `seed`.
///
/// Used by the proposer & sync committee selection functions.
Expand All @@ -932,6 +946,21 @@ impl<E: EthSpec> BeaconState<E> {
.ok_or(Error::ShuffleIndexOutOfBounds(index))
}

/// Get two random bytes from the given `seed`.
///
/// This is used in place of the
fn shuffling_random_u16_electra(i: usize, seed: &[u8]) -> Result<u16, Error> {
let mut preimage = seed.to_vec();
preimage.append(&mut int_to_bytes8(i.safe_div(16)? as u64));
let offset = i.safe_rem(16)?.safe_mul(2)?;
hash(&preimage)
.get(offset..offset.safe_add(2)?)
.ok_or(Error::ShuffleIndexOutOfBounds(offset))?
.try_into()
.map(u16::from_le_bytes)
.map_err(|_| Error::ShuffleIndexOutOfBounds(offset))
}

/// Convenience accessor for the `execution_payload_header` as an `ExecutionPayloadHeaderRef`.
pub fn latest_execution_payload_header(&self) -> Result<ExecutionPayloadHeaderRef<E>, Error> {
match self {
Expand Down Expand Up @@ -1093,6 +1122,11 @@ impl<E: EthSpec> BeaconState<E> {

let seed = self.get_seed(epoch, Domain::SyncCommittee, spec)?;
let max_effective_balance = spec.max_effective_balance_for_fork(self.fork_name_unchecked());
let max_random_value = if self.fork_name_unchecked().electra_enabled() {
MAX_RANDOM_VALUE
} else {
MAX_RANDOM_BYTE
};

let mut i = 0;
let mut sync_committee_indices = Vec::with_capacity(E::SyncCommitteeSize::to_usize());
Expand All @@ -1107,10 +1141,10 @@ impl<E: EthSpec> BeaconState<E> {
let candidate_index = *active_validator_indices
.get(shuffled_index)
.ok_or(Error::ShuffleIndexOutOfBounds(shuffled_index))?;
let random_byte = Self::shuffling_random_byte(i, seed.as_slice())?;
let random_value = self.shuffling_random_value(i, seed.as_slice())?;
let effective_balance = self.get_validator(candidate_index)?.effective_balance;
if effective_balance.safe_mul(MAX_RANDOM_BYTE)?
>= max_effective_balance.safe_mul(u64::from(random_byte))?
if effective_balance.safe_mul(max_random_value)?
>= max_effective_balance.safe_mul(random_value)?
{
sync_committee_indices.push(candidate_index);
}
Expand Down

0 comments on commit 282eefb

Please sign in to comment.