Skip to content

Commit

Permalink
Merge pull request #4112 from mkalinin/few-deposit-tests
Browse files Browse the repository at this point in the history
  • Loading branch information
jtraglia authored Feb 1, 2025
2 parents 07407f9 + da97a98 commit cdf1e5a
Show file tree
Hide file tree
Showing 5 changed files with 146 additions and 6 deletions.
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
from eth2spec.test.helpers.block import (
build_empty_block_for_next_slot,
)
from eth2spec.test.context import (
with_presets,
spec_state_test,
with_electra_and_later,
)
from eth2spec.test.helpers.execution_payload import (
compute_el_block_hash_for_block,
)
from eth2spec.test.helpers.state import (
state_transition_and_sign_block,
next_slot,
)
from eth2spec.test.helpers.deposits import (
prepare_deposit_request,
)
from eth2spec.test.helpers.fork_choice import (
get_genesis_forkchoice_store_and_block,
tick_and_add_block,
apply_next_slots_with_attestations,
)
from eth2spec.test.helpers.constants import (
MINIMAL,
)


@with_electra_and_later
@spec_state_test
@with_presets([MINIMAL], reason="too slow")
def test_new_validator_deposit_with_multiple_epoch_transitions(spec, state):
# signify the eth1 bridge deprecation
state.deposit_requests_start_index = state.eth1_deposit_index

# yield anchor state and block
store, anchor_block = get_genesis_forkchoice_store_and_block(spec, state)
yield 'anchor_state', state
yield 'anchor_block', anchor_block

test_steps = []

# (1) create deposit request for a new validator
deposit_request = prepare_deposit_request(
spec, len(state.validators), spec.MIN_ACTIVATION_BALANCE, signed=True)
deposit_block = build_empty_block_for_next_slot(spec, state)
deposit_block.body.execution_requests.deposits = [deposit_request]
deposit_block.body.execution_payload.block_hash = compute_el_block_hash_for_block(spec, deposit_block)
signed_deposit_block = state_transition_and_sign_block(spec, state, deposit_block)

pending_deposit = spec.PendingDeposit(
pubkey=deposit_request.pubkey,
withdrawal_credentials=deposit_request.withdrawal_credentials,
amount=deposit_request.amount,
signature=deposit_request.signature,
slot=deposit_block.slot
)

assert state.pending_deposits == [pending_deposit]

yield from tick_and_add_block(spec, store, signed_deposit_block, test_steps)

# (2) finalize and process pending deposit on one fork
slots = 4 * spec.SLOTS_PER_EPOCH - state.slot
post_state, _, latest_block = yield from apply_next_slots_with_attestations(
spec, state, store, slots, True, True, test_steps)

# check new validator has been created
assert post_state.pending_deposits == []
new_validator = post_state.validators[len(post_state.validators) - 1]
assert new_validator.pubkey == pending_deposit.pubkey
assert new_validator.withdrawal_credentials == pending_deposit.withdrawal_credentials

# (3) create a conflicting block that triggers deposit processing on another fork
prev_epoch_ancestor = store.blocks[latest_block.message.parent_root]
# important to skip last block of the epoch to make client do the epoch processing
# otherwise, client can read the post-epoch from cache
prev_epoch_ancestor = store.blocks[prev_epoch_ancestor.parent_root]
another_fork_state = store.block_states[prev_epoch_ancestor.hash_tree_root()].copy()

assert another_fork_state.pending_deposits == [pending_deposit]

# skip a slot to create and process a fork block
next_slot(spec, another_fork_state)
post_state, _, _ = yield from apply_next_slots_with_attestations(
spec, another_fork_state, store, 1, True, True, test_steps)

# check new validator has been created on another fork
assert post_state.pending_deposits == []
new_validator = post_state.validators[len(post_state.validators) - 1]
assert new_validator.pubkey == pending_deposit.pubkey
assert new_validator.withdrawal_credentials == pending_deposit.withdrawal_credentials

yield 'steps', test_steps
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from eth2spec.test.helpers.block import (
build_empty_block_for_next_slot
build_empty_block_for_next_slot,
)
from eth2spec.test.context import (
spec_state_test,
Expand All @@ -21,6 +21,9 @@
set_eth1_withdrawal_credential_with_balance,
set_compounding_withdrawal_credential_with_balance,
)
from eth2spec.test.helpers.deposits import (
prepare_deposit_request,
)


@with_electra_and_later
Expand Down Expand Up @@ -327,3 +330,43 @@ def test_withdrawal_and_switch_to_compounding_request_same_validator(spec, state
assert spec.is_compounding_withdrawal_credential(state.validators[validator_index].withdrawal_credentials)
# Ensure there was no excess balance pending deposit
assert len(state.pending_deposits) == 0


@with_electra_and_later
@spec_state_test
def test_deposit_request_with_same_pubkey_different_withdrawal_credentials(spec, state):
# signify the eth1 bridge deprecation
state.deposit_requests_start_index = state.eth1_deposit_index

# prepare three deposit requests, where
# 1st and 3rd have the same pubkey but different withdrawal credentials
deposit_request_0 = prepare_deposit_request(
spec, len(state.validators), spec.MIN_ACTIVATION_BALANCE, state.eth1_deposit_index, signed=True)
deposit_request_1 = prepare_deposit_request(
spec, len(state.validators) + 1, spec.MIN_ACTIVATION_BALANCE, state.eth1_deposit_index + 1, signed=True)
deposit_request_2 = prepare_deposit_request(
spec, len(state.validators), spec.MIN_ACTIVATION_BALANCE, state.eth1_deposit_index + 2, signed=True,
withdrawal_credentials=(spec.ETH1_ADDRESS_WITHDRAWAL_PREFIX + b'\x00' * 11 + b'\x11' * 20)
)

# build a block with deposit requests
block = build_empty_block_for_next_slot(spec, state)
block.body.execution_requests.deposits = [deposit_request_0, deposit_request_1, deposit_request_2]
block.body.execution_payload.block_hash = compute_el_block_hash_for_block(spec, block)

yield 'pre', state

signed_block = state_transition_and_sign_block(spec, state, block)

yield 'blocks', [signed_block]
yield 'post', state

# check deposit requests are processed correctly
for i, deposit_request in enumerate(block.body.execution_requests.deposits):
assert state.pending_deposits[i] == spec.PendingDeposit(
pubkey=deposit_request.pubkey,
withdrawal_credentials=deposit_request.withdrawal_credentials,
amount=deposit_request.amount,
signature=deposit_request.signature,
slot=signed_block.message.slot,
)
Original file line number Diff line number Diff line change
Expand Up @@ -93,8 +93,8 @@ def prepare_state_and_block(spec,
deposit_data = build_deposit_data(spec,
pubkeys[keypair_index],
privkeys[keypair_index],
# use max effective balance
spec.MAX_EFFECTIVE_BALANCE,
# use min activation balance
spec.MIN_ACTIVATION_BALANCE,
# insecurely use pubkey as withdrawal key
spec.BLS_WITHDRAWAL_PREFIX + spec.hash(pubkeys[keypair_index])[1:],
signed=True)
Expand All @@ -118,8 +118,8 @@ def prepare_state_and_block(spec,
for offset in range(deposit_request_cnt):
deposit_request = prepare_deposit_request(spec,
keypair_index,
# use max effective balance
spec.MAX_EFFECTIVE_BALANCE,
# use min activation balance
spec.MIN_ACTIVATION_BALANCE,
first_deposit_request_index + offset,
signed=True)
deposit_requests.append(deposit_request)
Expand Down
5 changes: 4 additions & 1 deletion tests/generators/fork_choice/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,10 @@
]}
deneb_mods = combine_mods(_new_deneb_mods, capella_mods)

electra_mods = deneb_mods # No additional Electra specific fork choice tests
_new_electra_mods = {key: 'eth2spec.test.electra.fork_choice.test_' + key for key in [
'deposit_with_reorg',
]}
electra_mods = combine_mods(_new_electra_mods, deneb_mods)

# Fulu adds new `is_data_available` tests
_new_fulu_mods = {key: 'eth2spec.test.fulu.fork_choice.test_' + key for key in [
Expand Down

0 comments on commit cdf1e5a

Please sign in to comment.