Skip to content

Commit e611684

Browse files
LeanSerrarodrigo-o
andauthored
feat: electra slashing, proposer_index & compute_sync_committees changes (#1417)
Co-authored-by: Rodrigo Oliveri <[email protected]>
1 parent f84cade commit e611684

File tree

4 files changed

+31
-24
lines changed

4 files changed

+31
-24
lines changed

lib/lambda_ethereum_consensus/state_transition/accessors.ex

+8-5
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ defmodule LambdaEthereumConsensus.StateTransition.Accessors do
1717
alias Types.SyncCommittee
1818
alias Types.Validator
1919

20-
@max_random_byte 2 ** 8 - 1
20+
@max_random_byte 2 ** 16 - 1
2121

2222
@doc """
2323
Compute the correct sync committee for a given `epoch`.
@@ -118,13 +118,16 @@ defmodule LambdaEthereumConsensus.StateTransition.Accessors do
118118
|> Misc.compute_shuffled_index(active_validator_count, seed) do
119119
candidate_index = Aja.Vector.at!(active_validator_indices, shuffled_index)
120120

121-
<<_::binary-size(rem(index, 32)), random_byte, _::binary>> =
122-
SszEx.hash(seed <> Misc.uint64_to_bytes(div(index, 32)))
121+
random_bytes = SszEx.hash(seed <> Misc.uint_to_bytes(div(index, 16), 64))
122+
offset = rem(index, 16) * 2
123123

124-
max_effective_balance = ChainSpec.get("MAX_EFFECTIVE_BALANCE")
124+
bytes = binary_part(random_bytes, offset, 2) <> <<0::48>>
125+
random_value = Misc.bytes_to_uint64(bytes)
126+
127+
max_effective_balance = ChainSpec.get("MAX_EFFECTIVE_BALANCE_ELECTRA")
125128
effective_balance = Aja.Vector.at!(validators, candidate_index).effective_balance
126129

127-
if effective_balance * @max_random_byte >= max_effective_balance * random_byte do
130+
if effective_balance * @max_random_byte >= max_effective_balance * random_value do
128131
{:ok, sync_committee_indices |> List.insert_at(0, candidate_index)}
129132
else
130133
{:ok, sync_committee_indices}

lib/lambda_ethereum_consensus/state_transition/epoch_processing.ex

+5-5
Original file line numberDiff line numberDiff line change
@@ -117,17 +117,17 @@ defmodule LambdaEthereumConsensus.StateTransition.EpochProcessing do
117117
adjusted_total_slashing_balance =
118118
min(slashed_sum * proportional_slashing_multiplier, total_balance)
119119

120+
penalty_per_effective_balance_increment =
121+
div(adjusted_total_slashing_balance, div(total_balance, increment))
122+
120123
new_state =
121124
validators
122125
|> Stream.with_index()
123126
|> Enum.reduce(state, fn {validator, index}, acc ->
124127
if validator.slashed and
125128
epoch + div(epochs_per_slashings_vector, 2) == validator.withdrawable_epoch do
126-
# increment factored out from penalty numerator to avoid uint64 overflow
127-
penalty_numerator =
128-
div(validator.effective_balance, increment) * adjusted_total_slashing_balance
129-
130-
penalty = div(penalty_numerator, total_balance) * increment
129+
effective_balance_increments = div(validator.effective_balance, increment)
130+
penalty = penalty_per_effective_balance_increment * effective_balance_increments
131131

132132
BeaconState.decrease_balance(acc, index, penalty)
133133
else

lib/lambda_ethereum_consensus/state_transition/misc.ex

+10-7
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ defmodule LambdaEthereumConsensus.StateTransition.Misc do
1212
alias LambdaEthereumConsensus.Utils
1313
alias Types.BeaconState
1414

15-
@max_random_byte 2 ** 8 - 1
15+
@max_random_byte 2 ** 16 - 1
1616

1717
@doc """
1818
Returns the Unix timestamp at the start of the given slot
@@ -130,23 +130,26 @@ defmodule LambdaEthereumConsensus.StateTransition.Misc do
130130
) ::
131131
{:ok, Types.validator_index()}
132132
def compute_proposer_index(state, indices, seed) do
133-
max_effective_balance = ChainSpec.get("MAX_EFFECTIVE_BALANCE")
133+
max_effective_balance = ChainSpec.get("MAX_EFFECTIVE_BALANCE_ELECTRA")
134134
total = Aja.Vector.size(indices)
135135

136136
Stream.iterate(0, &(&1 + 1))
137137
|> Stream.map(fn i ->
138138
{:ok, index} = compute_shuffled_index(rem(i, total), total, seed)
139139
candidate_index = Aja.Vector.at!(indices, index)
140140

141-
<<_::binary-size(rem(i, 32)), random_byte, _::binary>> =
142-
SszEx.hash(seed <> uint_to_bytes(div(i, 32), 64))
141+
random_bytes = SszEx.hash(seed <> uint_to_bytes(div(i, 16), 64))
142+
offset = rem(i, 16) * 2
143+
144+
bytes = binary_part(random_bytes, offset, 2) <> <<0::48>>
145+
random_value = bytes_to_uint64(bytes)
143146

144147
effective_balance = Aja.Vector.at(state.validators, candidate_index).effective_balance
145148

146-
{effective_balance, random_byte, candidate_index}
149+
{effective_balance, random_value, candidate_index}
147150
end)
148-
|> Stream.filter(fn {effective_balance, random_byte, _} ->
149-
effective_balance * @max_random_byte >= max_effective_balance * random_byte
151+
|> Stream.filter(fn {effective_balance, random_value, _} ->
152+
effective_balance * @max_random_byte >= max_effective_balance * random_value
150153
end)
151154
|> Enum.take(1)
152155
|> then(fn [{_, _, candidate_index}] -> {:ok, candidate_index} end)

test/spec/runners/sync.ex

+8-7
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,14 @@ defmodule SyncTestRunner do
3232
def run_test_case(%SpecTestCase{} = testcase) do
3333
original_engine_api_config = Application.fetch_env!(:lambda_ethereum_consensus, EngineApi)
3434

35+
on_exit(fn ->
36+
Application.put_env(
37+
:lambda_ethereum_consensus,
38+
EngineApi,
39+
original_engine_api_config
40+
)
41+
end)
42+
3543
Application.put_env(
3644
:lambda_ethereum_consensus,
3745
EngineApi,
@@ -41,13 +49,6 @@ defmodule SyncTestRunner do
4149
{:ok, _pid} = SyncTestRunner.EngineApiMock.start_link([])
4250

4351
ForkChoiceTestRunner.run_test_case(testcase)
44-
45-
# TODO: we should do this cleanup even if the test crashes/fails
46-
Application.put_env(
47-
:lambda_ethereum_consensus,
48-
EngineApi,
49-
original_engine_api_config
50-
)
5152
end
5253
end
5354

0 commit comments

Comments
 (0)