diff --git a/lib/lambda_ethereum_consensus/state_transition/accessors.ex b/lib/lambda_ethereum_consensus/state_transition/accessors.ex index a2b041aec..8ebe73010 100644 --- a/lib/lambda_ethereum_consensus/state_transition/accessors.ex +++ b/lib/lambda_ethereum_consensus/state_transition/accessors.ex @@ -17,7 +17,7 @@ defmodule LambdaEthereumConsensus.StateTransition.Accessors do alias Types.SyncCommittee alias Types.Validator - @max_random_byte 2 ** 8 - 1 + @max_random_byte 2 ** 16 - 1 @doc """ Compute the correct sync committee for a given `epoch`. @@ -118,13 +118,16 @@ defmodule LambdaEthereumConsensus.StateTransition.Accessors do |> Misc.compute_shuffled_index(active_validator_count, seed) do candidate_index = Aja.Vector.at!(active_validator_indices, shuffled_index) - <<_::binary-size(rem(index, 32)), random_byte, _::binary>> = - SszEx.hash(seed <> Misc.uint64_to_bytes(div(index, 32))) + random_bytes = SszEx.hash(seed <> Misc.uint_to_bytes(div(index, 16), 64)) + offset = rem(index, 16) * 2 - max_effective_balance = ChainSpec.get("MAX_EFFECTIVE_BALANCE") + bytes = binary_part(random_bytes, offset, 2) <> <<0::48>> + random_value = Misc.bytes_to_uint64(bytes) + + max_effective_balance = ChainSpec.get("MAX_EFFECTIVE_BALANCE_ELECTRA") effective_balance = Aja.Vector.at!(validators, candidate_index).effective_balance - if effective_balance * @max_random_byte >= max_effective_balance * random_byte do + if effective_balance * @max_random_byte >= max_effective_balance * random_value do {:ok, sync_committee_indices |> List.insert_at(0, candidate_index)} else {:ok, sync_committee_indices} diff --git a/lib/lambda_ethereum_consensus/state_transition/epoch_processing.ex b/lib/lambda_ethereum_consensus/state_transition/epoch_processing.ex index 1685e0b09..f3b63712b 100644 --- a/lib/lambda_ethereum_consensus/state_transition/epoch_processing.ex +++ b/lib/lambda_ethereum_consensus/state_transition/epoch_processing.ex @@ -117,17 +117,17 @@ defmodule LambdaEthereumConsensus.StateTransition.EpochProcessing do adjusted_total_slashing_balance = min(slashed_sum * proportional_slashing_multiplier, total_balance) + penalty_per_effective_balance_increment = + div(adjusted_total_slashing_balance, div(total_balance, increment)) + new_state = validators |> Stream.with_index() |> Enum.reduce(state, fn {validator, index}, acc -> if validator.slashed and epoch + div(epochs_per_slashings_vector, 2) == validator.withdrawable_epoch do - # increment factored out from penalty numerator to avoid uint64 overflow - penalty_numerator = - div(validator.effective_balance, increment) * adjusted_total_slashing_balance - - penalty = div(penalty_numerator, total_balance) * increment + effective_balance_increments = div(validator.effective_balance, increment) + penalty = penalty_per_effective_balance_increment * effective_balance_increments BeaconState.decrease_balance(acc, index, penalty) else diff --git a/lib/lambda_ethereum_consensus/state_transition/misc.ex b/lib/lambda_ethereum_consensus/state_transition/misc.ex index 375988237..3ec3e1dd3 100644 --- a/lib/lambda_ethereum_consensus/state_transition/misc.ex +++ b/lib/lambda_ethereum_consensus/state_transition/misc.ex @@ -12,7 +12,7 @@ defmodule LambdaEthereumConsensus.StateTransition.Misc do alias LambdaEthereumConsensus.Utils alias Types.BeaconState - @max_random_byte 2 ** 8 - 1 + @max_random_byte 2 ** 16 - 1 @doc """ Returns the Unix timestamp at the start of the given slot @@ -130,7 +130,7 @@ defmodule LambdaEthereumConsensus.StateTransition.Misc do ) :: {:ok, Types.validator_index()} def compute_proposer_index(state, indices, seed) do - max_effective_balance = ChainSpec.get("MAX_EFFECTIVE_BALANCE") + max_effective_balance = ChainSpec.get("MAX_EFFECTIVE_BALANCE_ELECTRA") total = Aja.Vector.size(indices) Stream.iterate(0, &(&1 + 1)) @@ -138,15 +138,18 @@ defmodule LambdaEthereumConsensus.StateTransition.Misc do {:ok, index} = compute_shuffled_index(rem(i, total), total, seed) candidate_index = Aja.Vector.at!(indices, index) - <<_::binary-size(rem(i, 32)), random_byte, _::binary>> = - SszEx.hash(seed <> uint_to_bytes(div(i, 32), 64)) + random_bytes = SszEx.hash(seed <> uint_to_bytes(div(i, 16), 64)) + offset = rem(i, 16) * 2 + + bytes = binary_part(random_bytes, offset, 2) <> <<0::48>> + random_value = bytes_to_uint64(bytes) effective_balance = Aja.Vector.at(state.validators, candidate_index).effective_balance - {effective_balance, random_byte, candidate_index} + {effective_balance, random_value, candidate_index} end) - |> Stream.filter(fn {effective_balance, random_byte, _} -> - effective_balance * @max_random_byte >= max_effective_balance * random_byte + |> Stream.filter(fn {effective_balance, random_value, _} -> + effective_balance * @max_random_byte >= max_effective_balance * random_value end) |> Enum.take(1) |> then(fn [{_, _, candidate_index}] -> {:ok, candidate_index} end) diff --git a/test/spec/runners/sync.ex b/test/spec/runners/sync.ex index 5dec75059..6dac8f600 100644 --- a/test/spec/runners/sync.ex +++ b/test/spec/runners/sync.ex @@ -32,6 +32,14 @@ defmodule SyncTestRunner do def run_test_case(%SpecTestCase{} = testcase) do original_engine_api_config = Application.fetch_env!(:lambda_ethereum_consensus, EngineApi) + on_exit(fn -> + Application.put_env( + :lambda_ethereum_consensus, + EngineApi, + original_engine_api_config + ) + end) + Application.put_env( :lambda_ethereum_consensus, EngineApi, @@ -41,13 +49,6 @@ defmodule SyncTestRunner do {:ok, _pid} = SyncTestRunner.EngineApiMock.start_link([]) ForkChoiceTestRunner.run_test_case(testcase) - - # TODO: we should do this cleanup even if the test crashes/fails - Application.put_env( - :lambda_ethereum_consensus, - EngineApi, - original_engine_api_config - ) end end