Skip to content

Commit 24874f3

Browse files
authored
Merge pull request #3953 from jtraglia/reject-invalid-dcs
2 parents f081b1b + 62c32da commit 24874f3

File tree

3 files changed

+193
-7
lines changed

3 files changed

+193
-7
lines changed

specs/_features/eip7594/fork-choice.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,8 @@ def is_data_available(beacon_block_root: Root) -> bool:
3131
# `MIN_EPOCHS_FOR_DATA_COLUMN_SIDECARS_REQUESTS` epochs.
3232
column_sidecars = retrieve_column_sidecars(beacon_block_root)
3333
return all(
34-
verify_data_column_sidecar_kzg_proofs(column_sidecar)
34+
verify_data_column_sidecar(column_sidecar)
35+
and verify_data_column_sidecar_kzg_proofs(column_sidecar)
3536
for column_sidecar in column_sidecars
3637
)
3738
```

specs/_features/eip7594/p2p-interface.md

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
- [Containers](#containers)
1515
- [`DataColumnIdentifier`](#datacolumnidentifier)
1616
- [Helpers](#helpers)
17+
- [`verify_data_column_sidecar`](#verify_data_column_sidecar)
1718
- [`verify_data_column_sidecar_kzg_proofs`](#verify_data_column_sidecar_kzg_proofs)
1819
- [`verify_data_column_sidecar_inclusion_proof`](#verify_data_column_sidecar_inclusion_proof)
1920
- [`compute_subnet_for_data_column_sidecar`](#compute_subnet_for_data_column_sidecar)
@@ -64,16 +65,35 @@ class DataColumnIdentifier(Container):
6465

6566
### Helpers
6667

68+
##### `verify_data_column_sidecar`
69+
70+
```python
71+
def verify_data_column_sidecar(sidecar: DataColumnSidecar) -> bool:
72+
"""
73+
Verify if the data column sidecar is valid.
74+
"""
75+
# The sidecar index must be within the valid range
76+
if sidecar.index >= NUMBER_OF_COLUMNS:
77+
return False
78+
79+
# A sidecar for zero blobs is invalid
80+
if len(sidecar.kzg_commitments) == 0:
81+
return False
82+
83+
# The column length must be equal to the number of commitments/proofs
84+
if len(sidecar.column) != len(sidecar.kzg_commitments) or len(sidecar.column) != len(sidecar.kzg_proofs):
85+
return False
86+
87+
return True
88+
```
89+
6790
##### `verify_data_column_sidecar_kzg_proofs`
6891

6992
```python
7093
def verify_data_column_sidecar_kzg_proofs(sidecar: DataColumnSidecar) -> bool:
7194
"""
72-
Verify if the proofs are correct.
95+
Verify if the KZG proofs are correct.
7396
"""
74-
assert sidecar.index < NUMBER_OF_COLUMNS
75-
assert len(sidecar.column) == len(sidecar.kzg_commitments) == len(sidecar.kzg_proofs)
76-
7797
# The column index also represents the cell index
7898
cell_indices = [CellIndex(sidecar.index)] * len(sidecar.column)
7999

@@ -148,7 +168,7 @@ The *type* of the payload of this topic is `DataColumnSidecar`.
148168

149169
The following validations MUST pass before forwarding the `sidecar: DataColumnSidecar` on the network, assuming the alias `block_header = sidecar.signed_block_header.message`:
150170

151-
- _[REJECT]_ The sidecar's index is consistent with `NUMBER_OF_COLUMNS` -- i.e. `sidecar.index < NUMBER_OF_COLUMNS`.
171+
- _[REJECT]_ The sidecar is valid as verified by `verify_data_column_sidecar(sidecar)`.
152172
- _[REJECT]_ The sidecar is for the correct subnet -- i.e. `compute_subnet_for_data_column_sidecar(sidecar.index) == subnet_id`.
153173
- _[IGNORE]_ The sidecar is not from a future slot (with a `MAXIMUM_GOSSIP_CLOCK_DISPARITY` allowance) -- i.e. validate that `block_header.slot <= current_slot` (a client MAY queue future sidecars for processing at the appropriate slot).
154174
- _[IGNORE]_ The sidecar is from a slot greater than the latest finalized slot -- i.e. validate that `block_header.slot > compute_start_slot_at_epoch(state.finalized_checkpoint.epoch)`

tests/core/pyspec/eth2spec/test/eip7594/unittests/test_networking.py

Lines changed: 166 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,173 @@
1+
import random
12
from eth2spec.test.context import (
2-
spec_test,
33
single_phase,
4+
spec_state_test,
5+
spec_test,
46
with_eip7594_and_later,
57
)
8+
from eth2spec.debug.random_value import (
9+
RandomizationMode,
10+
get_random_ssz_object,
11+
)
12+
from eth2spec.test.helpers.block import (
13+
sign_block,
14+
)
15+
from eth2spec.test.helpers.execution_payload import (
16+
compute_el_block_hash,
17+
)
18+
from eth2spec.test.helpers.sharding import (
19+
get_sample_opaque_tx,
20+
)
21+
22+
23+
# Helper functions
24+
25+
26+
def compute_data_column_sidecar(spec, state):
27+
rng = random.Random(5566)
28+
opaque_tx, blobs, blob_kzg_commitments, _ = get_sample_opaque_tx(spec, blob_count=2)
29+
block = get_random_ssz_object(
30+
rng,
31+
spec.BeaconBlock,
32+
max_bytes_length=2000,
33+
max_list_length=2000,
34+
mode=RandomizationMode,
35+
chaos=True,
36+
)
37+
block.body.blob_kzg_commitments = blob_kzg_commitments
38+
block.body.execution_payload.transactions = [opaque_tx]
39+
block.body.execution_payload.block_hash = compute_el_block_hash(spec, block.body.execution_payload, state)
40+
signed_block = sign_block(spec, state, block, proposer_index=0)
41+
cells_and_kzg_proofs = [spec.compute_cells_and_kzg_proofs(blob) for blob in blobs]
42+
return spec.get_data_column_sidecars(signed_block, cells_and_kzg_proofs)[0]
43+
44+
45+
# Tests for verify_data_column_sidecar
46+
47+
48+
@with_eip7594_and_later
49+
@spec_state_test
50+
@single_phase
51+
def test_verify_data_column_sidecar__valid(spec, state):
52+
sidecar = compute_data_column_sidecar(spec, state)
53+
assert spec.verify_data_column_sidecar(sidecar)
54+
55+
56+
@with_eip7594_and_later
57+
@spec_state_test
58+
@single_phase
59+
def test_verify_data_column_sidecar__invalid_zero_blobs(spec, state):
60+
sidecar = compute_data_column_sidecar(spec, state)
61+
sidecar.column = []
62+
sidecar.kzg_commitments = []
63+
sidecar.kzg_proofs = []
64+
assert not spec.verify_data_column_sidecar(sidecar)
65+
66+
67+
@with_eip7594_and_later
68+
@spec_state_test
69+
@single_phase
70+
def test_verify_data_column_sidecar__invalid_index(spec, state):
71+
sidecar = compute_data_column_sidecar(spec, state)
72+
sidecar.index = 128
73+
assert not spec.verify_data_column_sidecar(sidecar)
74+
75+
76+
@with_eip7594_and_later
77+
@spec_state_test
78+
@single_phase
79+
def test_verify_data_column_sidecar__invalid_mismatch_len_column(spec, state):
80+
sidecar = compute_data_column_sidecar(spec, state)
81+
sidecar.column = sidecar.column[1:]
82+
assert not spec.verify_data_column_sidecar(sidecar)
83+
84+
85+
@with_eip7594_and_later
86+
@spec_state_test
87+
@single_phase
88+
def test_verify_data_column_sidecar__invalid_mismatch_len_kzg_commitments(spec, state):
89+
sidecar = compute_data_column_sidecar(spec, state)
90+
sidecar.kzg_commitments = sidecar.kzg_commitments[1:]
91+
assert not spec.verify_data_column_sidecar(sidecar)
92+
93+
94+
@with_eip7594_and_later
95+
@spec_state_test
96+
@single_phase
97+
def test_verify_data_column_sidecars__invalid_mismatch_len_kzg_proofs(spec, state):
98+
sidecar = compute_data_column_sidecar(spec, state)
99+
sidecar.kzg_proofs = sidecar.kzg_proofs[1:]
100+
assert not spec.verify_data_column_sidecar(sidecar)
101+
102+
103+
# Tests for verify_data_column_sidecar_kzg_proofs
104+
105+
106+
@with_eip7594_and_later
107+
@spec_state_test
108+
@single_phase
109+
def test_verify_data_column_sidecar_kzg_proofs__valid(spec, state):
110+
sidecar = compute_data_column_sidecar(spec, state)
111+
assert spec.verify_data_column_sidecar_kzg_proofs(sidecar)
112+
113+
114+
@with_eip7594_and_later
115+
@spec_state_test
116+
@single_phase
117+
def test_verify_data_column_sidecar_kzg_proofs__invalid_wrong_column(spec, state):
118+
sidecar = compute_data_column_sidecar(spec, state)
119+
sidecar.column[0] = sidecar.column[1]
120+
assert not spec.verify_data_column_sidecar_kzg_proofs(sidecar)
121+
122+
123+
@with_eip7594_and_later
124+
@spec_state_test
125+
@single_phase
126+
def test_verify_data_column_sidecar_kzg_proofs__invalid_wrong_commitment(spec, state):
127+
sidecar = compute_data_column_sidecar(spec, state)
128+
sidecar.kzg_commitments[0] = sidecar.kzg_commitments[1]
129+
assert not spec.verify_data_column_sidecar_kzg_proofs(sidecar)
130+
131+
132+
@with_eip7594_and_later
133+
@spec_state_test
134+
@single_phase
135+
def test_verify_data_column_sidecar_kzg_proofs__invalid_wrong_proof(spec, state):
136+
sidecar = compute_data_column_sidecar(spec, state)
137+
sidecar.kzg_proofs[0] = sidecar.kzg_proofs[1]
138+
assert not spec.verify_data_column_sidecar_kzg_proofs(sidecar)
139+
140+
141+
# Tests for verify_data_column_sidecar_inclusion_proof
142+
143+
144+
@with_eip7594_and_later
145+
@spec_state_test
146+
@single_phase
147+
def test_verify_data_column_sidecar_inclusion_proof__valid(spec, state):
148+
sidecar = compute_data_column_sidecar(spec, state)
149+
assert spec.verify_data_column_sidecar_inclusion_proof(sidecar)
150+
151+
152+
@with_eip7594_and_later
153+
@spec_state_test
154+
@single_phase
155+
def test_verify_data_column_sidecar_inclusion_proof__invalid_missing_commitment(spec, state):
156+
sidecar = compute_data_column_sidecar(spec, state)
157+
sidecar.kzg_commitments = sidecar.kzg_commitments[1:]
158+
assert not spec.verify_data_column_sidecar_inclusion_proof(sidecar)
159+
160+
161+
@with_eip7594_and_later
162+
@spec_state_test
163+
@single_phase
164+
def test_verify_data_column_sidecar_inclusion_proof__invalid_duplicate_commitment(spec, state):
165+
sidecar = compute_data_column_sidecar(spec, state)
166+
sidecar.kzg_commitments = sidecar.kzg_commitments + [sidecar.kzg_commitments[0]]
167+
assert not spec.verify_data_column_sidecar_inclusion_proof(sidecar)
168+
169+
170+
# Tests for compute_subnet_for_data_column_sidecar
6171

7172

8173
@with_eip7594_and_later

0 commit comments

Comments
 (0)