Skip to content

Commit b665698

Browse files
committed
Fix off-by-one in process_pending_balance_deposits
1 parent fcca2b5 commit b665698

File tree

2 files changed

+58
-5
lines changed

2 files changed

+58
-5
lines changed

specs/electra/beacon-chain.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -854,6 +854,7 @@ def process_registry_updates(state: BeaconState) -> None:
854854

855855
```python
856856
def process_pending_balance_deposits(state: BeaconState) -> None:
857+
next_epoch = Epoch(get_current_epoch(state) + 1)
857858
available_for_processing = state.deposit_balance_to_consume + get_activation_exit_churn_limit(state)
858859
processed_amount = 0
859860
next_deposit_index = 0
@@ -863,7 +864,7 @@ def process_pending_balance_deposits(state: BeaconState) -> None:
863864
validator = state.validators[deposit.index]
864865
# Validator is exiting, postpone the deposit until after withdrawable epoch
865866
if validator.exit_epoch < FAR_FUTURE_EPOCH:
866-
if get_current_epoch(state) <= validator.withdrawable_epoch:
867+
if next_epoch <= validator.withdrawable_epoch:
867868
deposits_to_postpone.append(deposit)
868869
# Deposited balance will never become active. Increase balance but do not consume churn
869870
else:

tests/core/pyspec/eth2spec/test/electra/epoch_processing/test_process_pending_consolidations.py

Lines changed: 56 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -256,14 +256,12 @@ def test_pending_consolidation_compounding_creds(spec, state):
256256
spec.PendingConsolidation(source_index=source_index, target_index=target_index)
257257
)
258258
# Set the source and the target withdrawal credential to compounding
259-
compounding_withdrawal_credential_1 = (
259+
state.validators[source_index].withdrawal_credentials = (
260260
spec.COMPOUNDING_WITHDRAWAL_PREFIX + b"\x00" * 11 + b"\x11" * 20
261261
)
262-
compounding_withdrawal_credential_2 = (
262+
state.validators[target_index].withdrawal_credentials = (
263263
spec.COMPOUNDING_WITHDRAWAL_PREFIX + b"\x00" * 11 + b"\x12" * 20
264264
)
265-
state.validators[source_index].withdrawal_credentials = compounding_withdrawal_credential_1
266-
state.validators[target_index].withdrawal_credentials = compounding_withdrawal_credential_2
267265

268266
# Advance to withdrawable_epoch - 1 with full participation
269267
target_epoch = state.validators[source_index].withdrawable_epoch - spec.Epoch(1)
@@ -289,3 +287,57 @@ def test_pending_consolidation_compounding_creds(spec, state):
289287

290288
# Pending balance deposit to the target is not created
291289
assert len(state.pending_balance_deposits) == 0
290+
291+
292+
@with_electra_and_later
293+
@spec_state_test
294+
def test_pending_consolidation_with_pending_deposit(spec, state):
295+
current_epoch = spec.get_current_epoch(state)
296+
source_index = spec.get_active_validator_indices(state, current_epoch)[0]
297+
target_index = spec.get_active_validator_indices(state, current_epoch)[1]
298+
# initiate source exit
299+
spec.initiate_validator_exit(state, source_index)
300+
# set withdrawable_epoch to exit_epoch + 1
301+
state.validators[source_index].withdrawable_epoch = state.validators[source_index].exit_epoch + spec.Epoch(1)
302+
# append pending consolidation
303+
state.pending_consolidations.append(
304+
spec.PendingConsolidation(source_index=source_index, target_index=target_index)
305+
)
306+
# append pending deposit
307+
state.pending_balance_deposits.append(
308+
spec.PendingBalanceDeposit(index=source_index, amount=spec.MIN_ACTIVATION_BALANCE)
309+
)
310+
# Set the source and the target withdrawal credential to compounding
311+
state.validators[source_index].withdrawal_credentials = (
312+
spec.COMPOUNDING_WITHDRAWAL_PREFIX + b"\x00" * 11 + b"\x11" * 20
313+
)
314+
state.validators[target_index].withdrawal_credentials = (
315+
spec.COMPOUNDING_WITHDRAWAL_PREFIX + b"\x00" * 11 + b"\x12" * 20
316+
)
317+
318+
# Advance to withdrawable_epoch - 1 with full participation
319+
target_epoch = state.validators[source_index].withdrawable_epoch - spec.Epoch(1)
320+
while spec.get_current_epoch(state) < target_epoch:
321+
next_epoch_with_full_participation(spec, state)
322+
323+
# Obtain state before the call to process_pending_balance_deposits
324+
state_before_consolidation = compute_state_by_epoch_processing_to(spec, state, "process_pending_balance_deposits")
325+
326+
yield from run_epoch_processing_with(spec, state, "process_pending_consolidations")
327+
328+
# Pending consolidation was successfully processed
329+
expected_target_balance = (
330+
state_before_consolidation.balances[source_index] + state_before_consolidation.balances[target_index]
331+
)
332+
assert (
333+
state.validators[target_index].withdrawal_credentials[:1]
334+
== spec.COMPOUNDING_WITHDRAWAL_PREFIX
335+
)
336+
assert state.balances[target_index] == expected_target_balance
337+
assert state.balances[source_index] == 0
338+
assert state.pending_consolidations == []
339+
340+
# Pending balance deposit to the source was not processed
341+
assert len(state.pending_balance_deposits) == 1
342+
assert state.pending_balance_deposits[0] == spec.PendingBalanceDeposit(
343+
index=source_index, amount=spec.MIN_ACTIVATION_BALANCE)

0 commit comments

Comments
 (0)