Skip to content
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
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