Skip to content

feat: added randao utility module #691

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
Feb 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 2 additions & 10 deletions lib/lambda_ethereum_consensus/state_transition/accessors.ex
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ defmodule LambdaEthereumConsensus.StateTransition.Accessors do
alias LambdaEthereumConsensus.SszEx
alias LambdaEthereumConsensus.StateTransition.{Cache, Math, Misc, Predicates}
alias LambdaEthereumConsensus.Utils
alias LambdaEthereumConsensus.Utils.Randao
alias Types.{Attestation, BeaconState, IndexedAttestation, SyncCommittee, Validator}

@max_random_byte 2 ** 8 - 1
Expand Down Expand Up @@ -174,15 +175,6 @@ defmodule LambdaEthereumConsensus.StateTransition.Accessors do
end
end

@doc """
Return the randao mix at a recent ``epoch``.
"""
@spec get_randao_mix(BeaconState.t(), Types.epoch()) :: Types.bytes32()
def get_randao_mix(%BeaconState{randao_mixes: randao_mixes}, epoch) do
epochs_per_historical_vector = ChainSpec.get("EPOCHS_PER_HISTORICAL_VECTOR")
Enum.fetch!(randao_mixes, rem(epoch, epochs_per_historical_vector))
end

@doc """
Return the combined effective balance of the active validators.
Note: ``get_total_balance`` returns ``EFFECTIVE_BALANCE_INCREMENT`` Gwei minimum to avoid divisions by zero.
Expand Down Expand Up @@ -437,7 +429,7 @@ defmodule LambdaEthereumConsensus.StateTransition.Accessors do
epoch + ChainSpec.get("EPOCHS_PER_HISTORICAL_VECTOR") -
ChainSpec.get("MIN_SEED_LOOKAHEAD") - 1

mix = get_randao_mix(state, future_epoch)
mix = Randao.get_randao_mix(state.randao_mixes, future_epoch)

SszEx.hash(domain_type <> Misc.uint64_to_bytes(epoch) <> mix)
end
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ defmodule LambdaEthereumConsensus.StateTransition.EpochProcessing do

alias LambdaEthereumConsensus.StateTransition.{Accessors, Misc, Mutators, Predicates}
alias LambdaEthereumConsensus.Utils.BitVector
alias LambdaEthereumConsensus.Utils.Randao
alias Types.{BeaconState, HistoricalSummary, Validator}

@spec process_sync_committee_updates(BeaconState.t()) ::
Expand Down Expand Up @@ -91,10 +92,8 @@ defmodule LambdaEthereumConsensus.StateTransition.EpochProcessing do
def process_randao_mixes_reset(%BeaconState{randao_mixes: randao_mixes} = state) do
current_epoch = Accessors.get_current_epoch(state)
next_epoch = current_epoch + 1
epochs_per_historical_vector = ChainSpec.get("EPOCHS_PER_HISTORICAL_VECTOR")
randao_mix = Accessors.get_randao_mix(state, current_epoch)
index = rem(next_epoch, epochs_per_historical_vector)
new_randao_mixes = List.replace_at(randao_mixes, index, randao_mix)
randao_mix = Randao.get_randao_mix(randao_mixes, current_epoch)
new_randao_mixes = Randao.replace_randao_mix(randao_mixes, next_epoch, randao_mix)
new_state = %BeaconState{state | randao_mixes: new_randao_mixes}
{:ok, new_state}
end
Expand Down
13 changes: 5 additions & 8 deletions lib/lambda_ethereum_consensus/state_transition/operations.ex
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ defmodule LambdaEthereumConsensus.StateTransition.Operations do
alias LambdaEthereumConsensus.Utils
alias LambdaEthereumConsensus.Utils.BitList
alias LambdaEthereumConsensus.Utils.BitVector
alias LambdaEthereumConsensus.Utils.Randao

alias Types.{
Attestation,
Expand Down Expand Up @@ -228,7 +229,8 @@ defmodule LambdaEthereumConsensus.StateTransition.Operations do
{:error, "Inconsistency in parent hash"}

# Verify prev_randao
payload.prev_randao != Accessors.get_randao_mix(state, Accessors.get_current_epoch(state)) ->
payload.prev_randao !=
Randao.get_randao_mix(state.randao_mixes, Accessors.get_current_epoch(state)) ->
{:error, "Prev_randao verification failed"}

# Verify timestamp
Expand Down Expand Up @@ -766,18 +768,13 @@ defmodule LambdaEthereumConsensus.StateTransition.Operations do
signing_root = Misc.compute_signing_root(epoch, Types.Epoch, domain)

if Bls.valid?(proposer.pubkey, signing_root, randao_reveal) do
randao_mix = Accessors.get_randao_mix(state, epoch)
randao_mix = Randao.get_randao_mix(state.randao_mixes, epoch)
hash = SszEx.hash(randao_reveal)

# Mix in RANDAO reveal
mix = :crypto.exor(randao_mix, hash)

updated_randao_mixes =
List.replace_at(
state.randao_mixes,
rem(epoch, ChainSpec.get("EPOCHS_PER_HISTORICAL_VECTOR")),
mix
)
updated_randao_mixes = Randao.replace_randao_mix(state.randao_mixes, epoch, mix)

{:ok,
%BeaconState{
Expand Down
4 changes: 3 additions & 1 deletion lib/types/beacon_chain/beacon_state.ex
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ defmodule Types.BeaconState do
balances: Aja.Vector.t(Types.gwei()),
# Randomness
# size EPOCHS_PER_HISTORICAL_VECTOR 65_536
randao_mixes: list(Types.bytes32()),
randao_mixes: Aja.Vector.t(Types.bytes32()),
# Slashings
# Per-epoch sums of slashed effective balances
# size EPOCHS_PER_SLASHINGS_VECTOR 8192
Expand Down Expand Up @@ -110,6 +110,7 @@ defmodule Types.BeaconState do
map
|> Map.update!(:validators, &Aja.Vector.to_list/1)
|> Map.update!(:balances, &Aja.Vector.to_list/1)
|> Map.update!(:randao_mixes, &Aja.Vector.to_list/1)
|> Map.update!(:previous_epoch_participation, &Aja.Vector.to_list/1)
|> Map.update!(:current_epoch_participation, &Aja.Vector.to_list/1)
|> Map.update!(:latest_execution_payload_header, &Types.ExecutionPayloadHeader.encode/1)
Expand All @@ -119,6 +120,7 @@ defmodule Types.BeaconState do
map
|> Map.update!(:validators, &Aja.Vector.new/1)
|> Map.update!(:balances, &Aja.Vector.new/1)
|> Map.update!(:randao_mixes, &Aja.Vector.new/1)
|> Map.update!(:previous_epoch_participation, &Aja.Vector.new/1)
|> Map.update!(:current_epoch_participation, &Aja.Vector.new/1)
|> Map.update!(:latest_execution_payload_header, &Types.ExecutionPayloadHeader.decode/1)
Expand Down
25 changes: 25 additions & 0 deletions lib/utils/randao.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
defmodule LambdaEthereumConsensus.Utils.Randao do
@moduledoc """
This module provides utility functions for randao mixes
"""

@spec get_randao_mix_index(Types.epoch()) :: Types.epoch()
defp get_randao_mix_index(epoch), do: rem(epoch, ChainSpec.get("EPOCHS_PER_HISTORICAL_VECTOR"))

@doc """
Replaces the randao mix with a new one at the given epoch.
"""
@spec replace_randao_mix(Aja.Vector.t(Types.bytes32()), Types.epoch(), Types.bytes32()) ::
Aja.Vector.t(Types.bytes32())
def replace_randao_mix(randao_mixes, epoch, randao_mix),
do: Aja.Vector.replace_at!(randao_mixes, get_randao_mix_index(epoch), randao_mix)

@doc """
Return the randao mix at a recent ``epoch``.
"""
@spec get_randao_mix(Aja.Vector.t(Types.bytes32()), Types.epoch()) :: Types.bytes32()
def get_randao_mix(randao_mixes, epoch) do
index = get_randao_mix_index(epoch)
Aja.Vector.at!(randao_mixes, index)
end
end
1 change: 1 addition & 0 deletions test/spec/utils.ex
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ defmodule SpecTestUtils do
@vector_keys [
"validators",
"balances",
"randao_mixes",
"previous_epoch_participation",
"current_epoch_participation"
]
Expand Down