Add deposits transition tests
This commit is contained in:
parent
502745e012
commit
80e6b0d665
|
@ -0,0 +1,238 @@
|
|||
from eth2spec.test.helpers.block import (
|
||||
build_empty_block_for_next_slot,
|
||||
)
|
||||
from eth2spec.test.context import (
|
||||
spec_state_test,
|
||||
with_phases,
|
||||
EIP6110,
|
||||
expect_assertion_error,
|
||||
)
|
||||
from eth2spec.test.helpers.deposits import (
|
||||
build_deposit_data,
|
||||
deposit_from_context,
|
||||
prepare_deposit_receipt,
|
||||
)
|
||||
from eth2spec.test.helpers.execution_payload import (
|
||||
compute_el_block_hash,
|
||||
)
|
||||
from eth2spec.test.helpers.keys import privkeys, pubkeys
|
||||
|
||||
|
||||
def run_deposit_transition_block(spec, state, block, top_up_keys=[], valid=True):
|
||||
"""
|
||||
Run ``process_block``, yielding:
|
||||
- pre-state ('pre')
|
||||
- block ('block')
|
||||
- post-state ('post').
|
||||
If ``valid == False``, run expecting ``AssertionError``
|
||||
"""
|
||||
yield 'pre', state
|
||||
yield 'block', block
|
||||
|
||||
if not valid:
|
||||
expect_assertion_error(lambda: spec.process_block(state, block))
|
||||
yield 'post', None
|
||||
return
|
||||
|
||||
spec.process_block(state, block)
|
||||
yield 'post', state
|
||||
|
||||
# Check that deposits are applied
|
||||
expected_pubkeys = [d.data.pubkey for d in block.body.deposits]
|
||||
deposit_receipts = block.body.execution_payload.deposit_receipts
|
||||
expected_pubkeys = expected_pubkeys + [d.pubkey for d in deposit_receipts if (d.pubkey not in top_up_keys)]
|
||||
actual_pubkeys = [v.pubkey for v in state.validators[len(state.validators) - len(expected_pubkeys):]]
|
||||
|
||||
assert actual_pubkeys == expected_pubkeys
|
||||
|
||||
|
||||
def prepare_state_and_block(spec,
|
||||
state,
|
||||
deposit_cnt,
|
||||
deposit_receipt_cnt,
|
||||
first_deposit_receipt_index=0,
|
||||
deposit_receipts_start_index=None):
|
||||
deposits = []
|
||||
deposit_receipts = []
|
||||
keypair_index = len(state.validators)
|
||||
|
||||
# Prepare deposits
|
||||
deposit_data_list = []
|
||||
for index in range(deposit_cnt):
|
||||
deposit_data = build_deposit_data(spec,
|
||||
pubkeys[keypair_index],
|
||||
privkeys[keypair_index],
|
||||
# use max effective balance
|
||||
spec.MAX_EFFECTIVE_BALANCE,
|
||||
# insecurely use pubkey as withdrawal key
|
||||
spec.BLS_WITHDRAWAL_PREFIX + spec.hash(pubkeys[keypair_index])[1:],
|
||||
signed=True)
|
||||
deposit_data_list.append(deposit_data)
|
||||
keypair_index += 1
|
||||
|
||||
deposit_root = None
|
||||
for index in range(deposit_cnt):
|
||||
deposit, deposit_root, _ = deposit_from_context(spec, deposit_data_list, index)
|
||||
deposits.append(deposit)
|
||||
|
||||
if deposit_root:
|
||||
state.eth1_deposit_index = 0
|
||||
state.eth1_data = spec.Eth1Data(deposit_root=deposit_root,
|
||||
deposit_count=deposit_cnt,
|
||||
block_hash=state.eth1_data.block_hash)
|
||||
|
||||
# Prepare deposit receipts
|
||||
for offset in range(deposit_receipt_cnt):
|
||||
deposit_receipt = prepare_deposit_receipt(spec,
|
||||
keypair_index,
|
||||
# use max effective balance
|
||||
spec.MAX_EFFECTIVE_BALANCE,
|
||||
first_deposit_receipt_index + offset,
|
||||
signed=True)
|
||||
deposit_receipts.append(deposit_receipt)
|
||||
keypair_index += 1
|
||||
|
||||
# Set start index if defined
|
||||
if deposit_receipts_start_index:
|
||||
state.deposit_receipts_start_index = deposit_receipts_start_index
|
||||
|
||||
block = build_empty_block_for_next_slot(spec, state)
|
||||
|
||||
# Assign deposits and deposit receipts
|
||||
block.body.deposits = deposits
|
||||
block.body.execution_payload.deposit_receipts = deposit_receipts
|
||||
block.body.execution_payload.block_hash = compute_el_block_hash(spec, block.body.execution_payload)
|
||||
|
||||
# Advance a slot
|
||||
spec.process_slots(state, block.slot)
|
||||
|
||||
return state, block
|
||||
|
||||
|
||||
@with_phases([EIP6110])
|
||||
@spec_state_test
|
||||
def test_deposit_transition__start_index_is_set(spec, state):
|
||||
# 0 deposits, 2 deposit receipts, unset deposit_receipts_start_index
|
||||
state, block = prepare_state_and_block(spec, state,
|
||||
deposit_cnt=0,
|
||||
deposit_receipt_cnt=2,
|
||||
first_deposit_receipt_index=state.eth1_data.deposit_count + 11)
|
||||
|
||||
yield from run_deposit_transition_block(spec, state, block)
|
||||
|
||||
# deposit_receipts_start_index must be set to the index of the first receipt
|
||||
assert state.deposit_receipts_start_index == block.body.execution_payload.deposit_receipts[0].index
|
||||
|
||||
|
||||
@with_phases([EIP6110])
|
||||
@spec_state_test
|
||||
def test_deposit_transition__process_eth1_deposits(spec, state):
|
||||
# 3 deposits, 1 deposit receipt, state.eth1_data.deposit_count < state.deposit_receipts_start_index
|
||||
state, block = prepare_state_and_block(spec, state,
|
||||
deposit_cnt=3,
|
||||
deposit_receipt_cnt=1,
|
||||
first_deposit_receipt_index=11,
|
||||
deposit_receipts_start_index=7)
|
||||
|
||||
yield from run_deposit_transition_block(spec, state, block)
|
||||
|
||||
|
||||
@with_phases([EIP6110])
|
||||
@spec_state_test
|
||||
def test_deposit_transition__process_max_eth1_deposits(spec, state):
|
||||
# spec.MAX_DEPOSITS deposits, 1 deposit receipt, state.eth1_data.deposit_count > state.deposit_receipts_start_index
|
||||
# state.deposit_receipts_start_index == spec.MAX_DEPOSITS
|
||||
state, block = prepare_state_and_block(spec, state,
|
||||
deposit_cnt=spec.MAX_DEPOSITS,
|
||||
deposit_receipt_cnt=1,
|
||||
first_deposit_receipt_index=spec.MAX_DEPOSITS + 1,
|
||||
deposit_receipts_start_index=spec.MAX_DEPOSITS)
|
||||
state.eth1_data = spec.Eth1Data(deposit_root=state.eth1_data.deposit_root,
|
||||
deposit_count=23,
|
||||
block_hash=state.eth1_data.block_hash)
|
||||
|
||||
yield from run_deposit_transition_block(spec, state, block)
|
||||
|
||||
|
||||
@with_phases([EIP6110])
|
||||
@spec_state_test
|
||||
def test_deposit_transition__process_eth1_deposits_up_to_start_index(spec, state):
|
||||
# 3 deposits, 1 deposit receipt, state.eth1_data.deposit_count == state.deposit_receipts_start_index
|
||||
state, block = prepare_state_and_block(spec, state,
|
||||
deposit_cnt=3,
|
||||
deposit_receipt_cnt=1,
|
||||
first_deposit_receipt_index=7,
|
||||
deposit_receipts_start_index=3)
|
||||
|
||||
yield from run_deposit_transition_block(spec, state, block)
|
||||
|
||||
|
||||
@with_phases([EIP6110])
|
||||
@spec_state_test
|
||||
def test_deposit_transition__invalid_not_enough_eth1_deposits(spec, state):
|
||||
# 3 deposits, 1 deposit receipt, state.eth1_data.deposit_count < state.deposit_receipts_start_index
|
||||
state, block = prepare_state_and_block(spec, state,
|
||||
deposit_cnt=3,
|
||||
deposit_receipt_cnt=1,
|
||||
first_deposit_receipt_index=29,
|
||||
deposit_receipts_start_index=23)
|
||||
state.eth1_data = spec.Eth1Data(deposit_root=state.eth1_data.deposit_root,
|
||||
deposit_count=17,
|
||||
block_hash=state.eth1_data.block_hash)
|
||||
|
||||
yield from run_deposit_transition_block(spec, state, block, valid=False)
|
||||
|
||||
|
||||
@with_phases([EIP6110])
|
||||
@spec_state_test
|
||||
def test_deposit_transition__invalid_too_many_eth1_deposits(spec, state):
|
||||
# 3 deposits, 1 deposit receipt, state.eth1_data.deposit_count < state.eth1_data_index
|
||||
state, block = prepare_state_and_block(spec, state,
|
||||
deposit_cnt=3,
|
||||
deposit_receipt_cnt=1,
|
||||
first_deposit_receipt_index=11,
|
||||
deposit_receipts_start_index=7)
|
||||
state.eth1_data = spec.Eth1Data(deposit_root=state.eth1_data.deposit_root,
|
||||
deposit_count=2,
|
||||
block_hash=state.eth1_data.block_hash)
|
||||
|
||||
yield from run_deposit_transition_block(spec, state, block, valid=False)
|
||||
|
||||
|
||||
@with_phases([EIP6110])
|
||||
@spec_state_test
|
||||
def test_deposit_transition__invalid_eth1_deposits_overlap_in_protocol_deposits(spec, state):
|
||||
# spec.MAX_DEPOSITS deposits, 1 deposit receipt, state.eth1_data.deposit_count > state.deposit_receipts_start_index
|
||||
# state.deposit_receipts_start_index == spec.MAX_DEPOSITS - 1
|
||||
state, block = prepare_state_and_block(spec, state,
|
||||
deposit_cnt=spec.MAX_DEPOSITS,
|
||||
deposit_receipt_cnt=1,
|
||||
first_deposit_receipt_index=spec.MAX_DEPOSITS,
|
||||
deposit_receipts_start_index=spec.MAX_DEPOSITS - 1)
|
||||
state.eth1_data = spec.Eth1Data(deposit_root=state.eth1_data.deposit_root,
|
||||
deposit_count=23,
|
||||
block_hash=state.eth1_data.block_hash)
|
||||
|
||||
yield from run_deposit_transition_block(spec, state, block, valid=False)
|
||||
|
||||
|
||||
@with_phases([EIP6110])
|
||||
@spec_state_test
|
||||
def test_deposit_transition__deposit_and_top_up_same_block(spec, state):
|
||||
# 1 deposit, 1 deposit receipt that top ups deposited validator
|
||||
state, block = prepare_state_and_block(spec, state,
|
||||
deposit_cnt=1,
|
||||
deposit_receipt_cnt=1,
|
||||
first_deposit_receipt_index=11,
|
||||
deposit_receipts_start_index=7)
|
||||
|
||||
# Artificially assign deposit's pubkey to a deposit receipt of the same block
|
||||
top_up_keys = [block.body.deposits[0].data.pubkey]
|
||||
block.body.execution_payload.deposit_receipts[0].pubkey = top_up_keys[0]
|
||||
block.body.execution_payload.block_hash = compute_el_block_hash(spec, block.body.execution_payload)
|
||||
|
||||
yield from run_deposit_transition_block(spec, state, block, top_up_keys=top_up_keys)
|
||||
|
||||
# Check the top up
|
||||
expected_balance = block.body.deposits[0].data.amount + block.body.execution_payload.deposit_receipts[0].amount
|
||||
assert state.balances[len(state.balances) - 1] == expected_balance
|
|
@ -100,9 +100,9 @@ def compute_el_header_block_hash(spec,
|
|||
# excess_data_gas
|
||||
execution_payload_header_rlp.append((big_endian_int, payload_header.excess_data_gas))
|
||||
if is_post_eip6110(spec):
|
||||
# TODO: RLP or SSZ for `deposit_receipts_root`
|
||||
# FIXME: if using RLP, we need to implement `get_deposit_receipt_rlp` helper
|
||||
...
|
||||
# deposit_receipts_root
|
||||
assert deposit_receipts_trie_root is not None
|
||||
execution_payload_header_rlp.append((Binary(32, 32), deposit_receipts_trie_root))
|
||||
|
||||
sedes = List([schema for schema, _ in execution_payload_header_rlp])
|
||||
values = [value for _, value in execution_payload_header_rlp]
|
||||
|
@ -129,14 +129,37 @@ def get_withdrawal_rlp(spec, withdrawal):
|
|||
return encode(values, sedes)
|
||||
|
||||
|
||||
def get_deposit_receipt_rlp(spec, deposit_receipt):
|
||||
deposit_receipt_rlp = [
|
||||
# pubkey
|
||||
(Binary(48, 48), deposit_receipt.pubkey),
|
||||
# withdrawal_credentials
|
||||
(Binary(32, 32), deposit_receipt.withdrawal_credentials),
|
||||
# amount
|
||||
(big_endian_int, deposit_receipt.amount),
|
||||
# pubkey
|
||||
(Binary(96, 96), deposit_receipt.signature),
|
||||
# index
|
||||
(big_endian_int, deposit_receipt.index),
|
||||
]
|
||||
|
||||
sedes = List([schema for schema, _ in deposit_receipt_rlp])
|
||||
values = [value for _, value in deposit_receipt_rlp]
|
||||
return encode(values, sedes)
|
||||
|
||||
|
||||
def compute_el_block_hash(spec, payload):
|
||||
transactions_trie_root = compute_trie_root_from_indexed_data(payload.transactions)
|
||||
|
||||
withdrawals_trie_root = None
|
||||
deposit_receipts_trie_root = None
|
||||
|
||||
if is_post_capella(spec):
|
||||
withdrawals_encoded = [get_withdrawal_rlp(spec, withdrawal) for withdrawal in payload.withdrawals]
|
||||
withdrawals_trie_root = compute_trie_root_from_indexed_data(withdrawals_encoded)
|
||||
else:
|
||||
withdrawals_trie_root = None
|
||||
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)
|
||||
|
||||
payload_header = get_execution_payload_header(spec, payload)
|
||||
|
||||
|
@ -145,6 +168,7 @@ def compute_el_block_hash(spec, payload):
|
|||
payload_header,
|
||||
transactions_trie_root,
|
||||
withdrawals_trie_root,
|
||||
deposit_receipts_trie_root,
|
||||
)
|
||||
|
||||
|
||||
|
|
|
@ -47,17 +47,20 @@ def get_sample_genesis_execution_payload_header(spec,
|
|||
)
|
||||
|
||||
transactions_trie_root = bytes.fromhex("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421")
|
||||
withdrawals_trie_root = None
|
||||
deposit_receipts_trie_root = None
|
||||
|
||||
if is_post_capella(spec):
|
||||
withdrawals_trie_root = bytes.fromhex("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421")
|
||||
else:
|
||||
withdrawals_trie_root = None
|
||||
if is_post_eip6110(spec):
|
||||
deposit_receipts_trie_root = bytes.fromhex("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421")
|
||||
|
||||
payload_header.block_hash = compute_el_header_block_hash(
|
||||
spec,
|
||||
payload_header,
|
||||
transactions_trie_root,
|
||||
withdrawals_trie_root,
|
||||
deposit_receipts_trie_root,
|
||||
)
|
||||
return payload_header
|
||||
|
||||
|
|
Loading…
Reference in New Issue