Add basic tests

This commit is contained in:
Hsiao-Wei Wang 2023-05-10 01:06:51 +08:00
parent b8e77c5486
commit 34693f2db6
No known key found for this signature in database
GPG Key ID: AE3D6B174F971DE4
12 changed files with 178 additions and 8 deletions

View File

@ -9,12 +9,13 @@ from eth2spec.bellatrix import mainnet as spec_bellatrix_mainnet, minimal as spe
from eth2spec.capella import mainnet as spec_capella_mainnet, minimal as spec_capella_minimal
from eth2spec.deneb import mainnet as spec_deneb_mainnet, minimal as spec_deneb_minimal
from eth2spec.eip6110 import mainnet as spec_eip6110_mainnet, minimal as spec_eip6110_minimal
from eth2spec.eip7002 import mainnet as spec_eip7002_mainnet, minimal as spec_eip7002_minimal
from eth2spec.utils import bls
from .exceptions import SkippedTest
from .helpers.constants import (
PHASE0, ALTAIR, BELLATRIX, CAPELLA, DENEB,
EIP6110,
EIP6110, EIP7002,
MINIMAL, MAINNET,
ALL_PHASES,
ALL_FORK_UPGRADES,
@ -82,6 +83,7 @@ spec_targets: Dict[PresetBaseName, Dict[SpecForkName, Spec]] = {
CAPELLA: spec_capella_minimal,
DENEB: spec_deneb_minimal,
EIP6110: spec_eip6110_minimal,
EIP7002: spec_eip7002_minimal,
},
MAINNET: {
PHASE0: spec_phase0_mainnet,
@ -90,6 +92,7 @@ spec_targets: Dict[PresetBaseName, Dict[SpecForkName, Spec]] = {
CAPELLA: spec_capella_mainnet,
DENEB: spec_deneb_mainnet,
EIP6110: spec_eip6110_mainnet,
EIP7002: spec_eip7002_mainnet,
},
}
@ -433,6 +436,7 @@ with_bellatrix_and_later = with_all_phases_from(BELLATRIX)
with_capella_and_later = with_all_phases_from(CAPELLA)
with_deneb_and_later = with_all_phases_from(DENEB)
with_eip6110_and_later = with_all_phases_from(EIP6110)
with_eip7002_and_later = with_all_phases_from(EIP7002)
def _get_preset_targets(kw):

View File

@ -0,0 +1,40 @@
from eth2spec.test.context import spec_state_test, with_eip7002_and_later
from eth2spec.test.helpers.execution_layer_exits import run_execution_layer_exit_processing
from eth2spec.test.helpers.withdrawals import set_eth1_withdrawal_credential_with_balance
@with_eip7002_and_later
@spec_state_test
def test_basic_exit(spec, state):
# move state forward SHARD_COMMITTEE_PERIOD epochs to allow for exit
state.slot += spec.config.SHARD_COMMITTEE_PERIOD * spec.SLOTS_PER_EPOCH
current_epoch = spec.get_current_epoch(state)
validator_index = spec.get_active_validator_indices(state, current_epoch)[0]
address = b'\x22' * 20
set_eth1_withdrawal_credential_with_balance(spec, state, validator_index, address=address)
execution_layer_exit = spec.ExecutionLayerExit(
source_address=address,
validator_index=validator_index,
)
yield from run_execution_layer_exit_processing(spec, state, execution_layer_exit)
@with_eip7002_and_later
@spec_state_test
def test_incorrect_source_address(spec, state):
# move state forward SHARD_COMMITTEE_PERIOD epochs to allow for exit
state.slot += spec.config.SHARD_COMMITTEE_PERIOD * spec.SLOTS_PER_EPOCH
current_epoch = spec.get_current_epoch(state)
validator_index = spec.get_active_validator_indices(state, current_epoch)[0]
address = b'\x22' * 20
incorrect_address = b'\x33' * 20
set_eth1_withdrawal_credential_with_balance(spec, state, validator_index, address=address)
execution_layer_exit = spec.ExecutionLayerExit(
source_address=incorrect_address,
validator_index=validator_index,
)
yield from run_execution_layer_exit_processing(spec, state, execution_layer_exit, success=False)

View File

@ -0,0 +1,46 @@
from eth2spec.test.helpers.block import (
build_empty_block_for_next_slot
)
from eth2spec.test.context import (
spec_state_test,
with_eip7002_and_later,
)
from eth2spec.test.helpers.execution_payload import (
compute_el_block_hash,
)
from eth2spec.test.helpers.state import (
state_transition_and_sign_block
)
from eth2spec.test.helpers.withdrawals import (
set_eth1_withdrawal_credential_with_balance,
)
@with_eip7002_and_later
@spec_state_test
def test_basic_exit(spec, state):
# move state forward SHARD_COMMITTEE_PERIOD epochs to allow for exit
state.slot += spec.config.SHARD_COMMITTEE_PERIOD * spec.SLOTS_PER_EPOCH
current_epoch = spec.get_current_epoch(state)
validator_index = spec.get_active_validator_indices(state, current_epoch)[0]
address = b'\x22' * 20
set_eth1_withdrawal_credential_with_balance(spec, state, validator_index, address=address)
execution_layer_exit = spec.ExecutionLayerExit(
source_address=address,
validator_index=validator_index,
)
yield 'pre', state
assert state.validators[validator_index].exit_epoch == spec.FAR_FUTURE_EPOCH
block = build_empty_block_for_next_slot(spec, state)
block.body.execution_payload.exits = [execution_layer_exit]
block.body.execution_payload.block_hash = compute_el_block_hash(spec, block.body.execution_payload)
signed_block = state_transition_and_sign_block(spec, state, block)
yield 'blocks', [signed_block]
yield 'post', state
assert state.validators[validator_index].exit_epoch < spec.FAR_FUTURE_EPOCH

View File

@ -16,6 +16,7 @@ SHARDING = SpecForkName('sharding')
CUSTODY_GAME = SpecForkName('custody_game')
DAS = SpecForkName('das')
EIP6110 = SpecForkName('eip6110')
EIP7002 = SpecForkName('eip7002')
# The forks that pytest can run with.
ALL_PHASES = (
@ -23,6 +24,7 @@ ALL_PHASES = (
PHASE0, ALTAIR, BELLATRIX, CAPELLA, DENEB,
# Experimental patches
EIP6110,
EIP7002,
)
# The forks that output to the test vectors.
TESTGEN_FORKS = (PHASE0, ALTAIR, BELLATRIX, CAPELLA, DENEB, EIP6110)

View File

@ -0,0 +1,37 @@
from eth2spec.test.context import expect_assertion_error
#
# Run processing
#
def run_execution_layer_exit_processing(spec, state, execution_layer_exit, valid=True, success=True):
"""
Run ``process_execution_layer_exit``, yielding:
- pre-state ('pre')
- execution_layer_exit ('execution_layer_exit')
- post-state ('post').
If ``valid == False``, run expecting ``AssertionError``
"""
validator_index = execution_layer_exit.validator_index
yield 'pre', state
yield 'execution_layer_exit', execution_layer_exit
if not valid:
expect_assertion_error(lambda: spec.process_execution_layer_exit(state, execution_layer_exit))
yield 'post', None
return
pre_exit_epoch = state.validators[validator_index].exit_epoch
spec.process_execution_layer_exit(state, execution_layer_exit)
yield 'post', state
if success:
assert pre_exit_epoch == spec.FAR_FUTURE_EPOCH
assert state.validators[validator_index].exit_epoch < spec.FAR_FUTURE_EPOCH
else:
assert state.validators[validator_index].exit_epoch == pre_exit_epoch

View File

@ -8,6 +8,7 @@ from eth2spec.test.helpers.forks import (
is_post_capella,
is_post_deneb,
is_post_eip6110,
is_post_eip7002,
)
@ -34,6 +35,8 @@ def get_execution_payload_header(spec, execution_payload):
payload_header.excess_data_gas = execution_payload.excess_data_gas
if is_post_eip6110(spec):
payload_header.deposit_receipts_root = spec.hash_tree_root(execution_payload.deposit_receipts)
if is_post_eip7002(spec):
payload_header.exits_root = spec.hash_tree_root(execution_payload.exits)
return payload_header
@ -55,7 +58,8 @@ def compute_el_header_block_hash(spec,
payload_header,
transactions_trie_root,
withdrawals_trie_root=None,
deposit_receipts_trie_root=None):
deposit_receipts_trie_root=None,
exits_trie_root=None):
"""
Computes the RLP execution block hash described by an `ExecutionPayloadHeader`.
"""
@ -103,6 +107,9 @@ def compute_el_header_block_hash(spec,
# deposit_receipts_root
assert deposit_receipts_trie_root is not None
execution_payload_header_rlp.append((Binary(32, 32), deposit_receipts_trie_root))
if is_post_eip7002(spec):
# exits_trie_root
execution_payload_header_rlp.append((Binary(32, 32), exits_trie_root))
sedes = List([schema for schema, _ in execution_payload_header_rlp])
values = [value for _, value in execution_payload_header_rlp]
@ -112,7 +119,7 @@ def compute_el_header_block_hash(spec,
# https://eips.ethereum.org/EIPS/eip-4895
def get_withdrawal_rlp(spec, withdrawal):
def get_withdrawal_rlp(withdrawal):
withdrawal_rlp = [
# index
(big_endian_int, withdrawal.index),
@ -129,6 +136,20 @@ def get_withdrawal_rlp(spec, withdrawal):
return encode(values, sedes)
# https://eips.ethereum.org/EIPS/eip-7002
def get_exit_rlp(exit):
exit_rlp = [
# source_address
(Binary(20, 20), exit.source_address),
# validator_index
(big_endian_int, exit.validator_index),
]
sedes = List([schema for schema, _ in exit_rlp])
values = [value for _, value in exit_rlp]
return encode(values, sedes)
def get_deposit_receipt_rlp(spec, deposit_receipt):
deposit_receipt_rlp = [
# pubkey
@ -153,13 +174,17 @@ def compute_el_block_hash(spec, payload):
withdrawals_trie_root = None
deposit_receipts_trie_root = None
exits_trie_root = None
if is_post_capella(spec):
withdrawals_encoded = [get_withdrawal_rlp(spec, withdrawal) for withdrawal in payload.withdrawals]
withdrawals_encoded = [get_withdrawal_rlp(withdrawal) for withdrawal in payload.withdrawals]
withdrawals_trie_root = compute_trie_root_from_indexed_data(withdrawals_encoded)
if is_post_eip6110(spec):
deposit_receipts_encoded = [get_deposit_receipt_rlp(spec, receipt) for receipt in payload.deposit_receipts]
deposit_receipts_trie_root = compute_trie_root_from_indexed_data(deposit_receipts_encoded)
if is_post_eip7002(spec):
exits_encoded = [get_exit_rlp(exit) for exit in payload.exits]
exits_trie_root = compute_trie_root_from_indexed_data(exits_encoded)
payload_header = get_execution_payload_header(spec, payload)
@ -169,6 +194,7 @@ def compute_el_block_hash(spec, payload):
transactions_trie_root,
withdrawals_trie_root,
deposit_receipts_trie_root,
exits_trie_root,
)

View File

@ -1,10 +1,12 @@
from .constants import (
PHASE0, ALTAIR, BELLATRIX, CAPELLA, DENEB,
EIP6110,
EIP6110, EIP7002,
)
def is_post_fork(a, b):
if a == EIP7002:
return b in [PHASE0, ALTAIR, BELLATRIX, CAPELLA, DENEB, EIP7002]
if a == EIP6110:
return b in [PHASE0, ALTAIR, BELLATRIX, CAPELLA, DENEB, EIP6110]
if a == DENEB:
@ -38,3 +40,7 @@ def is_post_deneb(spec):
def is_post_eip6110(spec):
return is_post_fork(spec.fork, EIP6110)
def is_post_eip7002(spec):
return is_post_fork(spec.fork, EIP7002)

View File

@ -5,7 +5,7 @@ from eth2spec.test.helpers.execution_payload import (
compute_el_header_block_hash,
)
from eth2spec.test.helpers.forks import (
is_post_altair, is_post_bellatrix, is_post_capella, is_post_eip6110,
is_post_altair, is_post_bellatrix, is_post_capella, is_post_eip6110, is_post_eip7002,
)
from eth2spec.test.helpers.keys import pubkeys
@ -49,11 +49,14 @@ def get_sample_genesis_execution_payload_header(spec,
transactions_trie_root = bytes.fromhex("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421")
withdrawals_trie_root = None
deposit_receipts_trie_root = None
exits_trie_root = None
if is_post_capella(spec):
withdrawals_trie_root = bytes.fromhex("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421")
if is_post_eip6110(spec):
deposit_receipts_trie_root = bytes.fromhex("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421")
if is_post_eip7002(spec):
exits_trie_root = bytes.fromhex("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421")
payload_header.block_hash = compute_el_header_block_hash(
spec,
@ -61,6 +64,7 @@ def get_sample_genesis_execution_payload_header(spec,
transactions_trie_root,
withdrawals_trie_root,
deposit_receipts_trie_root,
exits_trie_root,
)
return payload_header

View File

@ -20,9 +20,14 @@ def set_validator_fully_withdrawable(spec, state, index, withdrawable_epoch=None
assert spec.is_fully_withdrawable_validator(validator, state.balances[index], withdrawable_epoch)
def set_eth1_withdrawal_credential_with_balance(spec, state, index, balance):
def set_eth1_withdrawal_credential_with_balance(spec, state, index, balance=None, address=None):
if balance is None:
balance = spec.MAX_EFFECTIVE_BALANCE
if address is None:
address = b'\x11' * 20
validator = state.validators[index]
validator.withdrawal_credentials = spec.ETH1_ADDRESS_WITHDRAWAL_PREFIX + validator.withdrawal_credentials[1:]
validator.withdrawal_credentials = spec.ETH1_ADDRESS_WITHDRAWAL_PREFIX + b'\x00' * 11 + address
validator.effective_balance = min(balance, spec.MAX_EFFECTIVE_BALANCE)
state.balances[index] = balance