From 655094ee4a7026185f1962fc245dfa763735828a Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Fri, 28 Apr 2023 17:28:11 +0800 Subject: [PATCH 1/5] Add `test_zero_blob` test case --- .../eth2spec/test/deneb/sanity/test_blocks.py | 30 +++++++++---------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/tests/core/pyspec/eth2spec/test/deneb/sanity/test_blocks.py b/tests/core/pyspec/eth2spec/test/deneb/sanity/test_blocks.py index 5e65dbd4e..9a6c6a45b 100644 --- a/tests/core/pyspec/eth2spec/test/deneb/sanity/test_blocks.py +++ b/tests/core/pyspec/eth2spec/test/deneb/sanity/test_blocks.py @@ -16,13 +16,11 @@ from eth2spec.test.helpers.sharding import ( ) -@with_deneb_and_later -@spec_state_test -def test_one_blob(spec, state): +def run_block_with_blobs(spec, state, blob_count): yield 'pre', state block = build_empty_block_for_next_slot(spec, state) - opaque_tx, _, blob_kzg_commitments, _ = get_sample_opaque_tx(spec) + opaque_tx, _, blob_kzg_commitments, _ = get_sample_opaque_tx(spec, blob_count=blob_count) block.body.blob_kzg_commitments = blob_kzg_commitments block.body.execution_payload.transactions = [opaque_tx] block.body.execution_payload.block_hash = compute_el_block_hash(spec, block.body.execution_payload) @@ -32,17 +30,19 @@ def test_one_blob(spec, state): yield 'post', state +@with_deneb_and_later +@spec_state_test +def test_zero_blob(spec, state): + yield from run_block_with_blobs(spec, state, blob_count=0) + + +@with_deneb_and_later +@spec_state_test +def test_one_blob(spec, state): + yield from run_block_with_blobs(spec, state, blob_count=1) + + @with_deneb_and_later @spec_state_test def test_max_blobs(spec, state): - yield 'pre', state - - block = build_empty_block_for_next_slot(spec, state) - opaque_tx, _, blob_kzg_commitments, _ = get_sample_opaque_tx(spec, blob_count=spec.MAX_BLOBS_PER_BLOCK) - block.body.blob_kzg_commitments = blob_kzg_commitments - block.body.execution_payload.transactions = [opaque_tx] - 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 + yield from run_block_with_blobs(spec, state, blob_count=spec.MAX_BLOBS_PER_BLOCK) From 327ef095d0fe8f309dc42126a9b3abf64f31175d Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Fri, 28 Apr 2023 17:37:50 +0800 Subject: [PATCH 2/5] Add `test_incorrect_blob_tx_type` --- .../eth2spec/test/deneb/sanity/test_blocks.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/tests/core/pyspec/eth2spec/test/deneb/sanity/test_blocks.py b/tests/core/pyspec/eth2spec/test/deneb/sanity/test_blocks.py index 9a6c6a45b..50b975d3b 100644 --- a/tests/core/pyspec/eth2spec/test/deneb/sanity/test_blocks.py +++ b/tests/core/pyspec/eth2spec/test/deneb/sanity/test_blocks.py @@ -46,3 +46,20 @@ def test_one_blob(spec, state): @spec_state_test def test_max_blobs(spec, state): yield from run_block_with_blobs(spec, state, blob_count=spec.MAX_BLOBS_PER_BLOCK) + + +@with_deneb_and_later +@spec_state_test +def test_incorrect_blob_tx_type(spec, state): + yield 'pre', state + + block = build_empty_block_for_next_slot(spec, state) + opaque_tx, _, blob_kzg_commitments, _ = get_sample_opaque_tx(spec) + block.body.blob_kzg_commitments = blob_kzg_commitments + opaque_tx[0] == spec.uint8(0x04) # incorrect tx type + block.body.execution_payload.transactions = [opaque_tx] + 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 From 22da92e5979b72d6b2c37719c84ee66b9d909cc8 Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Fri, 28 Apr 2023 18:26:42 +0800 Subject: [PATCH 3/5] Refactor the spec and add more test cases --- specs/deneb/beacon-chain.md | 7 +- .../eth2spec/test/deneb/sanity/test_blocks.py | 90 ++++++++++++++++++- 2 files changed, 92 insertions(+), 5 deletions(-) diff --git a/specs/deneb/beacon-chain.md b/specs/deneb/beacon-chain.md index df1da8e2a..359c7fc95 100644 --- a/specs/deneb/beacon-chain.md +++ b/specs/deneb/beacon-chain.md @@ -173,6 +173,8 @@ def tx_peek_blob_versioned_hashes(opaque_tx: Transaction) -> Sequence[VersionedH message_offset + uint32.decode_bytes(opaque_tx[(message_offset + 188):(message_offset + 192)]) ) + # `VersionedHash` is a 32-byte object + assert (len(opaque_tx) - blob_versioned_hashes_offset) % 32 == 0 return [ VersionedHash(opaque_tx[x:(x + 32)]) for x in range(blob_versioned_hashes_offset, len(opaque_tx), 32) @@ -205,7 +207,7 @@ def process_block(state: BeaconState, block: BeaconBlock) -> None: process_eth1_data(state, block.body) process_operations(state, block.body) process_sync_aggregate(state, block.body.sync_aggregate) - process_blob_kzg_commitments(state, block.body) # [New in Deneb] + process_blob_kzg_commitments(block.body) # [New in Deneb] ``` #### Execution payload @@ -248,8 +250,7 @@ def process_execution_payload(state: BeaconState, payload: ExecutionPayload, exe #### Blob KZG commitments ```python -def process_blob_kzg_commitments(state: BeaconState, body: BeaconBlockBody) -> None: - # pylint: disable=unused-argument +def process_blob_kzg_commitments(body: BeaconBlockBody) -> None: assert verify_kzg_commitments_against_transactions(body.execution_payload.transactions, body.blob_kzg_commitments) ``` diff --git a/tests/core/pyspec/eth2spec/test/deneb/sanity/test_blocks.py b/tests/core/pyspec/eth2spec/test/deneb/sanity/test_blocks.py index 50b975d3b..0f8f8b3a4 100644 --- a/tests/core/pyspec/eth2spec/test/deneb/sanity/test_blocks.py +++ b/tests/core/pyspec/eth2spec/test/deneb/sanity/test_blocks.py @@ -1,3 +1,5 @@ +import random + from eth2spec.test.helpers.state import ( state_transition_and_sign_block ) @@ -50,15 +52,99 @@ def test_max_blobs(spec, state): @with_deneb_and_later @spec_state_test -def test_incorrect_blob_tx_type(spec, state): +def test_invalid_incorrect_blob_tx_type(spec, state): yield 'pre', state block = build_empty_block_for_next_slot(spec, state) opaque_tx, _, blob_kzg_commitments, _ = get_sample_opaque_tx(spec) block.body.blob_kzg_commitments = blob_kzg_commitments - opaque_tx[0] == spec.uint8(0x04) # incorrect tx type + opaque_tx = b'\x04' + opaque_tx[1:] # incorrect tx type block.body.execution_payload.transactions = [opaque_tx] 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, expect_fail=True) + + yield 'blocks', [signed_block] + yield 'post', None + + +@with_deneb_and_later +@spec_state_test +def test_invalid_incorrect_transaction_length_1_byte(spec, state): + yield 'pre', state + + block = build_empty_block_for_next_slot(spec, state) + opaque_tx, _, blob_kzg_commitments, _ = get_sample_opaque_tx(spec) + block.body.blob_kzg_commitments = blob_kzg_commitments + opaque_tx = opaque_tx + b'\x12' # incorrect tx length + block.body.execution_payload.transactions = [opaque_tx] + 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, expect_fail=True) + + yield 'blocks', [signed_block] + yield 'post', None + + +@with_deneb_and_later +@spec_state_test +def test_invalid_incorrect_transaction_length_32_bytes(spec, state): + yield 'pre', state + + block = build_empty_block_for_next_slot(spec, state) + opaque_tx, _, blob_kzg_commitments, _ = get_sample_opaque_tx(spec) + block.body.blob_kzg_commitments = blob_kzg_commitments + opaque_tx = opaque_tx + b'\x12' * 32 # incorrect tx length + block.body.execution_payload.transactions = [opaque_tx] + 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, expect_fail=True) + + yield 'blocks', [signed_block] + yield 'post', None + + +@with_deneb_and_later +@spec_state_test +def test_invalid_incorrect_commitment(spec, state): + yield 'pre', state + + block = build_empty_block_for_next_slot(spec, state) + opaque_tx, _, blob_kzg_commitments, _ = get_sample_opaque_tx(spec) + blob_kzg_commitments[0] = b'\x12' * 48 # incorrect commitment + block.body.blob_kzg_commitments = blob_kzg_commitments + block.body.execution_payload.transactions = [opaque_tx] + 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, expect_fail=True) + + yield 'blocks', [signed_block] + yield 'post', None + + +@with_deneb_and_later +@spec_state_test +def test_invalid_incorrect_commitments_order(spec, state): + yield 'pre', state + + block = build_empty_block_for_next_slot(spec, state) + opaque_tx, _, blob_kzg_commitments, _ = get_sample_opaque_tx(spec, blob_count=2, rng=random.Random(1111)) + block.body.blob_kzg_commitments = [blob_kzg_commitments[1], blob_kzg_commitments[0]] # incorrect order + block.body.execution_payload.transactions = [opaque_tx] + 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, expect_fail=True) + + yield 'blocks', [signed_block] + yield 'post', None + + +@with_deneb_and_later +@spec_state_test +def test_incorrect_block_hash(spec, state): + yield 'pre', state + + block = build_empty_block_for_next_slot(spec, state) + opaque_tx, _, blob_kzg_commitments, _ = get_sample_opaque_tx(spec) + block.body.blob_kzg_commitments = blob_kzg_commitments + block.body.execution_payload.transactions = [opaque_tx] + block.body.execution_payload.block_hash = b'\x12' * 32 # incorrect block hash + # CL itself doesn't verify EL block hash signed_block = state_transition_and_sign_block(spec, state, block) yield 'blocks', [signed_block] From 2a1d998594ba795c22ffd657292e2b0b87fe8850 Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Fri, 28 Apr 2023 19:01:19 +0800 Subject: [PATCH 4/5] Test non zero `excess_data_gas` --- tests/core/pyspec/eth2spec/test/deneb/sanity/test_blocks.py | 1 + tests/core/pyspec/eth2spec/test/helpers/execution_payload.py | 2 ++ 2 files changed, 3 insertions(+) diff --git a/tests/core/pyspec/eth2spec/test/deneb/sanity/test_blocks.py b/tests/core/pyspec/eth2spec/test/deneb/sanity/test_blocks.py index 0f8f8b3a4..2b99d6a72 100644 --- a/tests/core/pyspec/eth2spec/test/deneb/sanity/test_blocks.py +++ b/tests/core/pyspec/eth2spec/test/deneb/sanity/test_blocks.py @@ -25,6 +25,7 @@ def run_block_with_blobs(spec, state, blob_count): opaque_tx, _, blob_kzg_commitments, _ = get_sample_opaque_tx(spec, blob_count=blob_count) block.body.blob_kzg_commitments = blob_kzg_commitments block.body.execution_payload.transactions = [opaque_tx] + block.body.execution_payload.excess_data_gas = 2 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) diff --git a/tests/core/pyspec/eth2spec/test/helpers/execution_payload.py b/tests/core/pyspec/eth2spec/test/helpers/execution_payload.py index c0a70aca1..c8ef1cbf0 100644 --- a/tests/core/pyspec/eth2spec/test/helpers/execution_payload.py +++ b/tests/core/pyspec/eth2spec/test/helpers/execution_payload.py @@ -165,6 +165,8 @@ def build_empty_execution_payload(spec, state, randao_mix=None): ) if is_post_capella(spec): payload.withdrawals = spec.get_expected_withdrawals(state) + if is_post_deneb(spec): + payload.excess_data_gas = 0 payload.block_hash = compute_el_block_hash(spec, payload) From 4244dc8e139f299b0b0a2cdaf1f045b69a9b0917 Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Thu, 4 May 2023 17:55:14 +0800 Subject: [PATCH 5/5] Make `excess_data_gas` a param of `run_block_with_blobs` --- tests/core/pyspec/eth2spec/test/deneb/sanity/test_blocks.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/core/pyspec/eth2spec/test/deneb/sanity/test_blocks.py b/tests/core/pyspec/eth2spec/test/deneb/sanity/test_blocks.py index 2b99d6a72..111565cce 100644 --- a/tests/core/pyspec/eth2spec/test/deneb/sanity/test_blocks.py +++ b/tests/core/pyspec/eth2spec/test/deneb/sanity/test_blocks.py @@ -18,14 +18,14 @@ from eth2spec.test.helpers.sharding import ( ) -def run_block_with_blobs(spec, state, blob_count): +def run_block_with_blobs(spec, state, blob_count, excess_data_gas=1): yield 'pre', state block = build_empty_block_for_next_slot(spec, state) opaque_tx, _, blob_kzg_commitments, _ = get_sample_opaque_tx(spec, blob_count=blob_count) block.body.blob_kzg_commitments = blob_kzg_commitments block.body.execution_payload.transactions = [opaque_tx] - block.body.execution_payload.excess_data_gas = 2 + block.body.execution_payload.excess_data_gas = excess_data_gas 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)