Merge pull request #3463 from ethereum/deneb-fc-tests-take-2
Deneb fork choice tests - take 2
This commit is contained in:
commit
56d6d1a51e
|
@ -21,9 +21,9 @@ T = TypeVar('T') # For generic function
|
||||||
@classmethod
|
@classmethod
|
||||||
def sundry_functions(cls) -> str:
|
def sundry_functions(cls) -> str:
|
||||||
return '''
|
return '''
|
||||||
def retrieve_blobs_and_proofs(beacon_block_root: Root) -> PyUnion[Tuple[Blob, KZGProof], Tuple[str, str]]:
|
def retrieve_blobs_and_proofs(beacon_block_root: Root) -> Tuple[Sequence[Blob], Sequence[KZGProof]]:
|
||||||
# pylint: disable=unused-argument
|
# pylint: disable=unused-argument
|
||||||
return ("TEST", "TEST")'''
|
return [], []'''
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def execution_engine_cls(cls) -> str:
|
def execution_engine_cls(cls) -> str:
|
||||||
|
|
|
@ -55,11 +55,6 @@ def is_data_available(beacon_block_root: Root, blob_kzg_commitments: Sequence[KZ
|
||||||
# `MIN_EPOCHS_FOR_BLOB_SIDECARS_REQUESTS`
|
# `MIN_EPOCHS_FOR_BLOB_SIDECARS_REQUESTS`
|
||||||
blobs, proofs = retrieve_blobs_and_proofs(beacon_block_root)
|
blobs, proofs = retrieve_blobs_and_proofs(beacon_block_root)
|
||||||
|
|
||||||
# For testing, `retrieve_blobs_and_proofs` returns ("TEST", "TEST").
|
|
||||||
# TODO: Remove it once we have a way to inject `BlobSidecar` into tests.
|
|
||||||
if isinstance(blobs, str) or isinstance(proofs, str):
|
|
||||||
return True
|
|
||||||
|
|
||||||
return verify_blob_kzg_proof_batch(blobs, blob_kzg_commitments, proofs)
|
return verify_blob_kzg_proof_batch(blobs, blob_kzg_commitments, proofs)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,182 @@
|
||||||
|
from random import Random
|
||||||
|
|
||||||
|
from eth2spec.test.context import (
|
||||||
|
spec_state_test,
|
||||||
|
with_deneb_and_later,
|
||||||
|
)
|
||||||
|
|
||||||
|
from eth2spec.test.helpers.block import (
|
||||||
|
build_empty_block_for_next_slot,
|
||||||
|
)
|
||||||
|
from eth2spec.test.helpers.execution_payload import (
|
||||||
|
compute_el_block_hash,
|
||||||
|
)
|
||||||
|
from eth2spec.test.helpers.fork_choice import (
|
||||||
|
BlobData,
|
||||||
|
get_genesis_forkchoice_store_and_block,
|
||||||
|
on_tick_and_append_step,
|
||||||
|
tick_and_add_block_with_data,
|
||||||
|
)
|
||||||
|
from eth2spec.test.helpers.state import (
|
||||||
|
state_transition_and_sign_block,
|
||||||
|
)
|
||||||
|
from eth2spec.test.helpers.sharding import (
|
||||||
|
get_sample_opaque_tx,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def get_block_with_blob(spec, state, rng=None):
|
||||||
|
block = build_empty_block_for_next_slot(spec, state)
|
||||||
|
opaque_tx, blobs, blob_kzg_commitments, blob_kzg_proofs = get_sample_opaque_tx(spec, blob_count=1, rng=rng)
|
||||||
|
block.body.execution_payload.transactions = [opaque_tx]
|
||||||
|
block.body.execution_payload.block_hash = compute_el_block_hash(spec, block.body.execution_payload)
|
||||||
|
block.body.blob_kzg_commitments = blob_kzg_commitments
|
||||||
|
return block, blobs, blob_kzg_proofs
|
||||||
|
|
||||||
|
|
||||||
|
@with_deneb_and_later
|
||||||
|
@spec_state_test
|
||||||
|
def test_simple_blob_data(spec, state):
|
||||||
|
rng = Random(1234)
|
||||||
|
|
||||||
|
test_steps = []
|
||||||
|
# Initialization
|
||||||
|
store, anchor_block = get_genesis_forkchoice_store_and_block(spec, state)
|
||||||
|
yield 'anchor_state', state
|
||||||
|
yield 'anchor_block', anchor_block
|
||||||
|
current_time = state.slot * spec.config.SECONDS_PER_SLOT + store.genesis_time
|
||||||
|
on_tick_and_append_step(spec, store, current_time, test_steps)
|
||||||
|
assert store.time == current_time
|
||||||
|
|
||||||
|
# On receiving a block of `GENESIS_SLOT + 1` slot
|
||||||
|
block, blobs, blob_kzg_proofs = get_block_with_blob(spec, state, rng=rng)
|
||||||
|
signed_block = state_transition_and_sign_block(spec, state, block)
|
||||||
|
blob_data = BlobData(blobs, blob_kzg_proofs)
|
||||||
|
|
||||||
|
yield from tick_and_add_block_with_data(spec, store, signed_block, test_steps, blob_data)
|
||||||
|
|
||||||
|
assert spec.get_head(store) == signed_block.message.hash_tree_root()
|
||||||
|
|
||||||
|
# On receiving a block of next epoch
|
||||||
|
store.time = current_time + spec.config.SECONDS_PER_SLOT * spec.SLOTS_PER_EPOCH
|
||||||
|
block, blobs, blob_kzg_proofs = get_block_with_blob(spec, state, rng=rng)
|
||||||
|
signed_block = state_transition_and_sign_block(spec, state, block)
|
||||||
|
blob_data = BlobData(blobs, blob_kzg_proofs)
|
||||||
|
|
||||||
|
yield from tick_and_add_block_with_data(spec, store, signed_block, test_steps, blob_data)
|
||||||
|
|
||||||
|
assert spec.get_head(store) == signed_block.message.hash_tree_root()
|
||||||
|
|
||||||
|
yield 'steps', test_steps
|
||||||
|
|
||||||
|
|
||||||
|
@with_deneb_and_later
|
||||||
|
@spec_state_test
|
||||||
|
def test_invalid_incorrect_proof(spec, state):
|
||||||
|
rng = Random(1234)
|
||||||
|
|
||||||
|
test_steps = []
|
||||||
|
# Initialization
|
||||||
|
store, anchor_block = get_genesis_forkchoice_store_and_block(spec, state)
|
||||||
|
yield 'anchor_state', state
|
||||||
|
yield 'anchor_block', anchor_block
|
||||||
|
current_time = state.slot * spec.config.SECONDS_PER_SLOT + store.genesis_time
|
||||||
|
on_tick_and_append_step(spec, store, current_time, test_steps)
|
||||||
|
assert store.time == current_time
|
||||||
|
|
||||||
|
# On receiving a block of `GENESIS_SLOT + 1` slot
|
||||||
|
block, blobs, _ = get_block_with_blob(spec, state, rng=rng)
|
||||||
|
signed_block = state_transition_and_sign_block(spec, state, block)
|
||||||
|
# Insert incorrect proof
|
||||||
|
blob_kzg_proofs = [b'\xc0' + b'\x00' * 47]
|
||||||
|
blob_data = BlobData(blobs, blob_kzg_proofs)
|
||||||
|
|
||||||
|
yield from tick_and_add_block_with_data(spec, store, signed_block, test_steps, blob_data, valid=False)
|
||||||
|
|
||||||
|
assert spec.get_head(store) != signed_block.message.hash_tree_root()
|
||||||
|
|
||||||
|
yield 'steps', test_steps
|
||||||
|
|
||||||
|
|
||||||
|
@with_deneb_and_later
|
||||||
|
@spec_state_test
|
||||||
|
def test_invalid_data_unavailable(spec, state):
|
||||||
|
rng = Random(1234)
|
||||||
|
|
||||||
|
test_steps = []
|
||||||
|
# Initialization
|
||||||
|
store, anchor_block = get_genesis_forkchoice_store_and_block(spec, state)
|
||||||
|
yield 'anchor_state', state
|
||||||
|
yield 'anchor_block', anchor_block
|
||||||
|
current_time = state.slot * spec.config.SECONDS_PER_SLOT + store.genesis_time
|
||||||
|
on_tick_and_append_step(spec, store, current_time, test_steps)
|
||||||
|
assert store.time == current_time
|
||||||
|
|
||||||
|
# On receiving a block of `GENESIS_SLOT + 1` slot
|
||||||
|
block, _, _ = get_block_with_blob(spec, state, rng=rng)
|
||||||
|
signed_block = state_transition_and_sign_block(spec, state, block)
|
||||||
|
|
||||||
|
# data unavailable
|
||||||
|
blob_data = BlobData([], [])
|
||||||
|
|
||||||
|
yield from tick_and_add_block_with_data(spec, store, signed_block, test_steps, blob_data, valid=False)
|
||||||
|
|
||||||
|
assert spec.get_head(store) != signed_block.message.hash_tree_root()
|
||||||
|
|
||||||
|
yield 'steps', test_steps
|
||||||
|
|
||||||
|
|
||||||
|
@with_deneb_and_later
|
||||||
|
@spec_state_test
|
||||||
|
def test_invalid_wrong_proofs_length(spec, state):
|
||||||
|
rng = Random(1234)
|
||||||
|
|
||||||
|
test_steps = []
|
||||||
|
# Initialization
|
||||||
|
store, anchor_block = get_genesis_forkchoice_store_and_block(spec, state)
|
||||||
|
yield 'anchor_state', state
|
||||||
|
yield 'anchor_block', anchor_block
|
||||||
|
current_time = state.slot * spec.config.SECONDS_PER_SLOT + store.genesis_time
|
||||||
|
on_tick_and_append_step(spec, store, current_time, test_steps)
|
||||||
|
assert store.time == current_time
|
||||||
|
|
||||||
|
# On receiving a block of `GENESIS_SLOT + 1` slot
|
||||||
|
block, blobs, _ = get_block_with_blob(spec, state, rng=rng)
|
||||||
|
signed_block = state_transition_and_sign_block(spec, state, block)
|
||||||
|
|
||||||
|
# unavailable proofs
|
||||||
|
blob_data = BlobData(blobs, [])
|
||||||
|
|
||||||
|
yield from tick_and_add_block_with_data(spec, store, signed_block, test_steps, blob_data, valid=False)
|
||||||
|
|
||||||
|
assert spec.get_head(store) != signed_block.message.hash_tree_root()
|
||||||
|
|
||||||
|
yield 'steps', test_steps
|
||||||
|
|
||||||
|
|
||||||
|
@with_deneb_and_later
|
||||||
|
@spec_state_test
|
||||||
|
def test_invalid_wrong_blobs_length(spec, state):
|
||||||
|
rng = Random(1234)
|
||||||
|
|
||||||
|
test_steps = []
|
||||||
|
# Initialization
|
||||||
|
store, anchor_block = get_genesis_forkchoice_store_and_block(spec, state)
|
||||||
|
yield 'anchor_state', state
|
||||||
|
yield 'anchor_block', anchor_block
|
||||||
|
current_time = state.slot * spec.config.SECONDS_PER_SLOT + store.genesis_time
|
||||||
|
on_tick_and_append_step(spec, store, current_time, test_steps)
|
||||||
|
assert store.time == current_time
|
||||||
|
|
||||||
|
# On receiving a block of `GENESIS_SLOT + 1` slot
|
||||||
|
block, _, blob_kzg_proofs = get_block_with_blob(spec, state, rng=rng)
|
||||||
|
signed_block = state_transition_and_sign_block(spec, state, block)
|
||||||
|
|
||||||
|
# unavailable blobs
|
||||||
|
blob_data = BlobData([], blob_kzg_proofs)
|
||||||
|
|
||||||
|
yield from tick_and_add_block_with_data(spec, store, signed_block, test_steps, blob_data, valid=False)
|
||||||
|
|
||||||
|
assert spec.get_head(store) != signed_block.message.hash_tree_root()
|
||||||
|
|
||||||
|
yield 'steps', test_steps
|
|
@ -1,3 +1,5 @@
|
||||||
|
from typing import NamedTuple, Sequence, Any
|
||||||
|
|
||||||
from eth_utils import encode_hex
|
from eth_utils import encode_hex
|
||||||
from eth2spec.test.exceptions import BlockNotFoundException
|
from eth2spec.test.exceptions import BlockNotFoundException
|
||||||
from eth2spec.test.helpers.attestations import (
|
from eth2spec.test.helpers.attestations import (
|
||||||
|
@ -7,6 +9,40 @@ from eth2spec.test.helpers.attestations import (
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class BlobData(NamedTuple):
|
||||||
|
"""
|
||||||
|
The return values of ``retrieve_blobs_and_proofs`` helper.
|
||||||
|
"""
|
||||||
|
blobs: Sequence[Any]
|
||||||
|
proofs: Sequence[bytes]
|
||||||
|
|
||||||
|
|
||||||
|
def with_blob_data(spec, blob_data, func):
|
||||||
|
"""
|
||||||
|
This helper runs the given ``func`` with monkeypatched ``retrieve_blobs_and_proofs``
|
||||||
|
that returns ``blob_data.blobs, blob_data.proofs``.
|
||||||
|
"""
|
||||||
|
def retrieve_blobs_and_proofs(beacon_block_root):
|
||||||
|
return blob_data.blobs, blob_data.proofs
|
||||||
|
|
||||||
|
retrieve_blobs_and_proofs_backup = spec.retrieve_blobs_and_proofs
|
||||||
|
spec.retrieve_blobs_and_proofs = retrieve_blobs_and_proofs
|
||||||
|
|
||||||
|
class AtomicBoolean():
|
||||||
|
value = False
|
||||||
|
is_called = AtomicBoolean()
|
||||||
|
|
||||||
|
def wrap(flag: AtomicBoolean):
|
||||||
|
yield from func()
|
||||||
|
flag.value = True
|
||||||
|
|
||||||
|
try:
|
||||||
|
yield from wrap(is_called)
|
||||||
|
finally:
|
||||||
|
spec.retrieve_blobs_and_proofs = retrieve_blobs_and_proofs_backup
|
||||||
|
assert is_called.value
|
||||||
|
|
||||||
|
|
||||||
def get_anchor_root(spec, state):
|
def get_anchor_root(spec, state):
|
||||||
anchor_block_header = state.latest_block_header.copy()
|
anchor_block_header = state.latest_block_header.copy()
|
||||||
if anchor_block_header.state_root == spec.Bytes32():
|
if anchor_block_header.state_root == spec.Bytes32():
|
||||||
|
@ -15,7 +51,8 @@ def get_anchor_root(spec, state):
|
||||||
|
|
||||||
|
|
||||||
def tick_and_add_block(spec, store, signed_block, test_steps, valid=True,
|
def tick_and_add_block(spec, store, signed_block, test_steps, valid=True,
|
||||||
merge_block=False, block_not_found=False, is_optimistic=False):
|
merge_block=False, block_not_found=False, is_optimistic=False,
|
||||||
|
blob_data=None):
|
||||||
pre_state = store.block_states[signed_block.message.parent_root]
|
pre_state = store.block_states[signed_block.message.parent_root]
|
||||||
if merge_block:
|
if merge_block:
|
||||||
assert spec.is_merge_transition_block(pre_state, signed_block.message.body)
|
assert spec.is_merge_transition_block(pre_state, signed_block.message.body)
|
||||||
|
@ -30,11 +67,19 @@ def tick_and_add_block(spec, store, signed_block, test_steps, valid=True,
|
||||||
valid=valid,
|
valid=valid,
|
||||||
block_not_found=block_not_found,
|
block_not_found=block_not_found,
|
||||||
is_optimistic=is_optimistic,
|
is_optimistic=is_optimistic,
|
||||||
|
blob_data=blob_data,
|
||||||
)
|
)
|
||||||
|
|
||||||
return post_state
|
return post_state
|
||||||
|
|
||||||
|
|
||||||
|
def tick_and_add_block_with_data(spec, store, signed_block, test_steps, blob_data, valid=True):
|
||||||
|
def run_func():
|
||||||
|
yield from tick_and_add_block(spec, store, signed_block, test_steps, blob_data=blob_data, valid=valid)
|
||||||
|
|
||||||
|
yield from with_blob_data(spec, blob_data, run_func)
|
||||||
|
|
||||||
|
|
||||||
def add_attestation(spec, store, attestation, test_steps, is_from_block=False):
|
def add_attestation(spec, store, attestation, test_steps, is_from_block=False):
|
||||||
spec.on_attestation(store, attestation, is_from_block=is_from_block)
|
spec.on_attestation(store, attestation, is_from_block=is_from_block)
|
||||||
yield get_attestation_file_name(attestation), attestation
|
yield get_attestation_file_name(attestation), attestation
|
||||||
|
@ -94,6 +139,13 @@ def get_attester_slashing_file_name(attester_slashing):
|
||||||
return f"attester_slashing_{encode_hex(attester_slashing.hash_tree_root())}"
|
return f"attester_slashing_{encode_hex(attester_slashing.hash_tree_root())}"
|
||||||
|
|
||||||
|
|
||||||
|
def get_blobs_file_name(blobs=None, blobs_root=None):
|
||||||
|
if blobs:
|
||||||
|
return f"blobs_{encode_hex(blobs.hash_tree_root())}"
|
||||||
|
else:
|
||||||
|
return f"blobs_{encode_hex(blobs_root)}"
|
||||||
|
|
||||||
|
|
||||||
def on_tick_and_append_step(spec, store, time, test_steps):
|
def on_tick_and_append_step(spec, store, time, test_steps):
|
||||||
spec.on_tick(store, time)
|
spec.on_tick(store, time)
|
||||||
test_steps.append({'tick': int(time)})
|
test_steps.append({'tick': int(time)})
|
||||||
|
@ -119,35 +171,52 @@ def add_block(spec,
|
||||||
test_steps,
|
test_steps,
|
||||||
valid=True,
|
valid=True,
|
||||||
block_not_found=False,
|
block_not_found=False,
|
||||||
is_optimistic=False):
|
is_optimistic=False,
|
||||||
|
blob_data=None):
|
||||||
"""
|
"""
|
||||||
Run on_block and on_attestation
|
Run on_block and on_attestation
|
||||||
"""
|
"""
|
||||||
yield get_block_file_name(signed_block), signed_block
|
yield get_block_file_name(signed_block), signed_block
|
||||||
|
|
||||||
|
# Check blob_data
|
||||||
|
if blob_data is not None:
|
||||||
|
blobs = spec.List[spec.Blob, spec.MAX_BLOBS_PER_BLOCK](blob_data.blobs)
|
||||||
|
blobs_root = blobs.hash_tree_root()
|
||||||
|
yield get_blobs_file_name(blobs_root=blobs_root), blobs
|
||||||
|
|
||||||
|
is_blob_data_test = blob_data is not None
|
||||||
|
|
||||||
|
def _append_step(is_blob_data_test, valid=True):
|
||||||
|
if is_blob_data_test:
|
||||||
|
test_steps.append({
|
||||||
|
'block': get_block_file_name(signed_block),
|
||||||
|
'blobs': get_blobs_file_name(blobs_root=blobs_root),
|
||||||
|
'proofs': [encode_hex(proof) for proof in blob_data.proofs],
|
||||||
|
'valid': valid,
|
||||||
|
})
|
||||||
|
else:
|
||||||
|
test_steps.append({
|
||||||
|
'block': get_block_file_name(signed_block),
|
||||||
|
'valid': valid,
|
||||||
|
})
|
||||||
|
|
||||||
if not valid:
|
if not valid:
|
||||||
if is_optimistic:
|
if is_optimistic:
|
||||||
run_on_block(spec, store, signed_block, valid=True)
|
run_on_block(spec, store, signed_block, valid=True)
|
||||||
test_steps.append({
|
_append_step(is_blob_data_test, valid=False)
|
||||||
'block': get_block_file_name(signed_block),
|
|
||||||
'valid': False,
|
|
||||||
})
|
|
||||||
else:
|
else:
|
||||||
try:
|
try:
|
||||||
run_on_block(spec, store, signed_block, valid=True)
|
run_on_block(spec, store, signed_block, valid=True)
|
||||||
except (AssertionError, BlockNotFoundException) as e:
|
except (AssertionError, BlockNotFoundException) as e:
|
||||||
if isinstance(e, BlockNotFoundException) and not block_not_found:
|
if isinstance(e, BlockNotFoundException) and not block_not_found:
|
||||||
assert False
|
assert False
|
||||||
test_steps.append({
|
_append_step(is_blob_data_test, valid=False)
|
||||||
'block': get_block_file_name(signed_block),
|
|
||||||
'valid': False,
|
|
||||||
})
|
|
||||||
return
|
return
|
||||||
else:
|
else:
|
||||||
assert False
|
assert False
|
||||||
else:
|
else:
|
||||||
run_on_block(spec, store, signed_block, valid=True)
|
run_on_block(spec, store, signed_block, valid=True)
|
||||||
test_steps.append({'block': get_block_file_name(signed_block)})
|
_append_step(is_blob_data_test)
|
||||||
|
|
||||||
# An on_block step implies receiving block's attestations
|
# An on_block step implies receiving block's attestations
|
||||||
for attestation in signed_block.message.body.attestations:
|
for attestation in signed_block.message.body.attestations:
|
||||||
|
|
|
@ -34,9 +34,6 @@ from eth2spec.test.helpers.state import (
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
rng = random.Random(1001)
|
|
||||||
|
|
||||||
|
|
||||||
@with_altair_and_later
|
@with_altair_and_later
|
||||||
@spec_state_test
|
@spec_state_test
|
||||||
def test_genesis(spec, state):
|
def test_genesis(spec, state):
|
||||||
|
@ -271,6 +268,7 @@ def test_proposer_boost_correct_head(spec, state):
|
||||||
next_slots(spec, state_2, 2)
|
next_slots(spec, state_2, 2)
|
||||||
block_2 = build_empty_block_for_next_slot(spec, state_2)
|
block_2 = build_empty_block_for_next_slot(spec, state_2)
|
||||||
signed_block_2 = state_transition_and_sign_block(spec, state_2.copy(), block_2)
|
signed_block_2 = state_transition_and_sign_block(spec, state_2.copy(), block_2)
|
||||||
|
rng = random.Random(1001)
|
||||||
while spec.hash_tree_root(block_1) >= spec.hash_tree_root(block_2):
|
while spec.hash_tree_root(block_1) >= spec.hash_tree_root(block_2):
|
||||||
block_2.body.graffiti = spec.Bytes32(hex(rng.getrandbits(8 * 32))[2:].zfill(64))
|
block_2.body.graffiti = spec.Bytes32(hex(rng.getrandbits(8 * 32))[2:].zfill(64))
|
||||||
signed_block_2 = state_transition_and_sign_block(spec, state_2.copy(), block_2)
|
signed_block_2 = state_transition_and_sign_block(spec, state_2.copy(), block_2)
|
||||||
|
@ -339,6 +337,7 @@ def test_discard_equivocations_on_attester_slashing(spec, state):
|
||||||
next_slots(spec, state_2, 2)
|
next_slots(spec, state_2, 2)
|
||||||
block_2 = build_empty_block_for_next_slot(spec, state_2)
|
block_2 = build_empty_block_for_next_slot(spec, state_2)
|
||||||
signed_block_2 = state_transition_and_sign_block(spec, state_2.copy(), block_2)
|
signed_block_2 = state_transition_and_sign_block(spec, state_2.copy(), block_2)
|
||||||
|
rng = random.Random(1001)
|
||||||
while spec.hash_tree_root(block_1) >= spec.hash_tree_root(block_2):
|
while spec.hash_tree_root(block_1) >= spec.hash_tree_root(block_2):
|
||||||
block_2.body.graffiti = spec.Bytes32(hex(rng.getrandbits(8 * 32))[2:].zfill(64))
|
block_2.body.graffiti = spec.Bytes32(hex(rng.getrandbits(8 * 32))[2:].zfill(64))
|
||||||
signed_block_2 = state_transition_and_sign_block(spec, state_2.copy(), block_2)
|
signed_block_2 = state_transition_and_sign_block(spec, state_2.copy(), block_2)
|
||||||
|
|
|
@ -2,6 +2,30 @@
|
||||||
|
|
||||||
The aim of the fork choice tests is to provide test coverage of the various components of the fork choice.
|
The aim of the fork choice tests is to provide test coverage of the various components of the fork choice.
|
||||||
|
|
||||||
|
## Table of contents
|
||||||
|
<!-- TOC -->
|
||||||
|
<!-- START doctoc generated TOC please keep comment here to allow auto update -->
|
||||||
|
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
|
||||||
|
|
||||||
|
- [Test case format](#test-case-format)
|
||||||
|
- [`meta.yaml`](#metayaml)
|
||||||
|
- [`anchor_state.ssz_snappy`](#anchor_statessz_snappy)
|
||||||
|
- [`anchor_block.ssz_snappy`](#anchor_blockssz_snappy)
|
||||||
|
- [`steps.yaml`](#stepsyaml)
|
||||||
|
- [`on_tick` execution step](#on_tick-execution-step)
|
||||||
|
- [`on_attestation` execution step](#on_attestation-execution-step)
|
||||||
|
- [`on_block` execution step](#on_block-execution-step)
|
||||||
|
- [`on_merge_block` execution step](#on_merge_block-execution-step)
|
||||||
|
- [`on_attester_slashing` execution step](#on_attester_slashing-execution-step)
|
||||||
|
- [`on_payload_info` execution step](#on_payload_info-execution-step)
|
||||||
|
- [Checks step](#checks-step)
|
||||||
|
- [`attestation_<32-byte-root>.ssz_snappy`](#attestation_32-byte-rootssz_snappy)
|
||||||
|
- [`block_<32-byte-root>.ssz_snappy`](#block_32-byte-rootssz_snappy)
|
||||||
|
- [Condition](#condition)
|
||||||
|
|
||||||
|
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
|
||||||
|
<!-- /TOC -->
|
||||||
|
|
||||||
## Test case format
|
## Test case format
|
||||||
|
|
||||||
### `meta.yaml`
|
### `meta.yaml`
|
||||||
|
@ -59,14 +83,20 @@ The parameter that is required for executing `on_block(store, block)`.
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
{
|
{
|
||||||
block: string -- the name of the `block_<32-byte-root>.ssz_snappy` file.
|
block: string -- the name of the `block_<32-byte-root>.ssz_snappy` file.
|
||||||
To execute `on_block(store, block)` with the given attestation.
|
To execute `on_block(store, block)` with the given attestation.
|
||||||
valid: bool -- optional, default to `true`.
|
blobs: string -- optional, the name of the `blobs_<32-byte-root>.ssz_snappy` file.
|
||||||
If it's `false`, this execution step is expected to be invalid.
|
The blobs file content is a `List[Blob, MAX_BLOBS_PER_BLOCK]` SSZ object.
|
||||||
|
proofs: array of byte48 hex string -- optional, the proofs of blob commitments.
|
||||||
|
valid: bool -- optional, default to `true`.
|
||||||
|
If it's `false`, this execution step is expected to be invalid.
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
The file is located in the same folder (see below).
|
The file is located in the same folder (see below).
|
||||||
|
|
||||||
|
`blobs` and `proofs` are new fields from Deneb EIP-4844. These fields indicate the expected values from `retrieve_blobs_and_proofs()` helper inside `is_data_available()` helper. If these two fields are not provided, `retrieve_blobs_and_proofs()` returns empty lists.
|
||||||
|
|
||||||
After this step, the `store` object may have been updated.
|
After this step, the `store` object may have been updated.
|
||||||
|
|
||||||
#### `on_merge_block` execution step
|
#### `on_merge_block` execution step
|
||||||
|
|
|
@ -19,7 +19,13 @@ if __name__ == "__main__":
|
||||||
]}
|
]}
|
||||||
bellatrix_mods = combine_mods(_new_bellatrix_mods, altair_mods)
|
bellatrix_mods = combine_mods(_new_bellatrix_mods, altair_mods)
|
||||||
capella_mods = bellatrix_mods # No additional Capella specific fork choice tests
|
capella_mods = bellatrix_mods # No additional Capella specific fork choice tests
|
||||||
deneb_mods = capella_mods # No additional Deneb specific fork choice tests
|
|
||||||
|
# Deneb adds `is_data_available` tests
|
||||||
|
_new_deneb_mods = {key: 'eth2spec.test.deneb.fork_choice.test_' + key for key in [
|
||||||
|
'on_block',
|
||||||
|
]}
|
||||||
|
deneb_mods = combine_mods(_new_deneb_mods, capella_mods)
|
||||||
|
|
||||||
eip6110_mods = deneb_mods # No additional EIP6110 specific fork choice tests
|
eip6110_mods = deneb_mods # No additional EIP6110 specific fork choice tests
|
||||||
|
|
||||||
all_mods = {
|
all_mods = {
|
||||||
|
|
Loading…
Reference in New Issue