Skip to content

Commit e524a58

Browse files
authored
Load gossip validation state from the store (#5563)
@nflaig and I have been chatting about how the `state` being passed into gossip validation functions can be a bit ambiguous. This PR removes `state` as a parameter to the `validate_*_gossip` functions. It then gets the appropriate state from the forkchoice `Store`. I moved some other checks around because we need to ensure the head state is valid before getting it, otherwise it simply won't exist in `Store`.
1 parent 6bc6615 commit e524a58

41 files changed

Lines changed: 651 additions & 704 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

specs/altair/p2p-interface.md

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -224,13 +224,12 @@ Altair for further details.
224224
##### New `sync_committee_contribution_and_proof`
225225

226226
This topic is used to propagate partially aggregated sync committee messages to
227-
be included in future blocks. The `state` parameter is the head state.
227+
be included in future blocks.
228228

229229
```python
230230
def validate_sync_committee_contribution_and_proof_gossip(
231231
seen: Seen,
232232
store: Store,
233-
state: BeaconState,
234233
signed_contribution_and_proof: SignedContributionAndProof,
235234
current_time_ms: Uint64,
236235
) -> None:
@@ -257,6 +256,8 @@ def validate_sync_committee_contribution_and_proof_gossip(
257256
if not is_sync_committee_aggregator(contribution_and_proof.selection_proof):
258257
raise GossipReject("validator is not selected as aggregator")
259258

259+
state = store.block_states[get_head(store).root]
260+
260261
# [REJECT] The aggregator index is valid
261262
if contribution_and_proof.aggregator_index >= len(state.validators):
262263
raise GossipReject("aggregator index out of range")
@@ -341,14 +342,12 @@ messages to subsections of the network.
341342

342343
The `sync_committee_{subnet_id}` topics are used to propagate unaggregated sync
343344
committee messages to the subnet `subnet_id` to be aggregated before being
344-
gossiped to the global `sync_committee_contribution_and_proof` topic. The
345-
`state` parameter is the head state.
345+
gossiped to the global `sync_committee_contribution_and_proof` topic.
346346

347347
```python
348348
def validate_sync_committee_message_gossip(
349349
seen: Seen,
350350
store: Store,
351-
state: BeaconState,
352351
sync_committee_message: SyncCommitteeMessage,
353352
current_time_ms: Uint64,
354353
subnet_id: SubnetID,
@@ -361,6 +360,8 @@ def validate_sync_committee_message_gossip(
361360
if not is_current_slot(store, sync_committee_message.slot, current_time_ms):
362361
raise GossipIgnore("message is not for the current slot")
363362

363+
state = store.block_states[get_head(store).root]
364+
364365
# [REJECT] The validator index is valid
365366
if sync_committee_message.validator_index >= len(state.validators):
366367
raise GossipReject("validator index out of range")

specs/bellatrix/p2p-interface.md

Lines changed: 29 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -105,8 +105,7 @@ Bellatrix changes the type of the global beacon block topic.
105105
##### Modified `beacon_block`
106106

107107
The `beacon_block` topic is used solely for propagating new signed beacon blocks
108-
to all nodes on the networks. Signed blocks are sent in their entirety. The
109-
`state` parameter is the head state.
108+
to all nodes on the networks. Signed blocks are sent in their entirety.
110109

111110
*Note*: Blocks with execution enabled will be permitted to propagate regardless
112111
of the validity of the execution payload. This prevents network segregation
@@ -116,7 +115,6 @@ between [optimistic](./optimistic-sync.md) and non-optimistic nodes.
116115
def validate_beacon_block_gossip(
117116
seen: Seen,
118117
store: Store,
119-
state: BeaconState,
120118
signed_beacon_block: SignedBeaconBlock,
121119
current_time_ms: Uint64,
122120
# [New in Bellatrix]
@@ -146,6 +144,34 @@ def validate_beacon_block_gossip(
146144
if proposer_slot_key in seen.proposer_slots:
147145
raise GossipIgnore("block is not the first valid block for this slot and proposer")
148146

147+
# [IGNORE] The block's parent has been seen (via gossip or non-gossip sources)
148+
# (MAY be queued until parent is retrieved)
149+
if block.parent_root not in store.blocks:
150+
raise GossipIgnore("block's parent has not been seen")
151+
152+
# [New in Bellatrix]
153+
parent_payload_status = PAYLOAD_STATUS_NOT_VALIDATED
154+
if block.parent_root in block_payload_statuses:
155+
parent_payload_status = block_payload_statuses[block.parent_root]
156+
157+
# [New in Bellatrix]
158+
if block.parent_root not in store.block_states:
159+
# The parent has no post-state, so `is_execution_enabled` uses the
160+
# justified checkpoint (always imported). Merge-complete is monotonic.
161+
if is_execution_enabled(store.block_states[store.justified_checkpoint.root], block.body):
162+
if parent_payload_status == PAYLOAD_STATUS_NOT_VALIDATED:
163+
# [REJECT] The block's parent failed validation and its execution payload is optimistic
164+
raise GossipReject("block's parent is invalid and its payload is optimistic")
165+
166+
# [IGNORE] The block's parent failed validation and its execution payload is processed
167+
raise GossipIgnore("block's parent is invalid and its payload is processed")
168+
169+
# [Modified in Bellatrix]
170+
# [REJECT] The block's parent passes validation
171+
raise GossipReject("block's parent is invalid and execution is not enabled")
172+
173+
state = store.block_states[get_head(store).root]
174+
149175
# [REJECT] The proposer index is a valid validator index
150176
if block.proposer_index >= len(state.validators):
151177
raise GossipReject("proposer index out of range")
@@ -157,38 +183,16 @@ def validate_beacon_block_gossip(
157183
if not bls.Verify(proposer.pubkey, signing_root, signed_beacon_block.signature):
158184
raise GossipReject("invalid proposer signature")
159185

160-
# [IGNORE] The block's parent has been seen (via gossip or non-gossip sources)
161-
# (MAY be queued until parent is retrieved)
162-
if block.parent_root not in store.blocks:
163-
raise GossipIgnore("block's parent has not been seen")
164-
165186
# [New in Bellatrix]
166187
if is_execution_enabled(state, block.body):
167188
# [REJECT] The block's execution payload timestamp is correct with respect to the slot
168189
if execution_payload.timestamp != compute_time_at_slot(state, block.slot):
169190
raise GossipReject("incorrect execution payload timestamp")
170191

171-
parent_payload_status = PAYLOAD_STATUS_NOT_VALIDATED
172-
if block.parent_root in block_payload_statuses:
173-
parent_payload_status = block_payload_statuses[block.parent_root]
174-
175-
if block.parent_root not in store.block_states:
176-
if parent_payload_status == PAYLOAD_STATUS_NOT_VALIDATED:
177-
# [REJECT] The block's parent failed validation and its execution payload is optimistic
178-
raise GossipReject("block's parent is invalid and its payload is optimistic")
179-
180-
# [IGNORE] The block's parent failed validation and its execution payload is processed
181-
raise GossipIgnore("block's parent is invalid and its payload is processed")
182-
183192
# [IGNORE] The block's parent passed validation but its execution payload is invalid
184193
if parent_payload_status == PAYLOAD_STATUS_INVALIDATED:
185194
raise GossipIgnore("block's parent is valid and its payload is invalid")
186195

187-
# [REJECT] The block's parent passes validation
188-
elif block.parent_root not in store.block_states:
189-
# [Modified in Bellatrix]
190-
raise GossipReject("block's parent is invalid and execution is not enabled")
191-
192196
# [REJECT] The block is from a higher slot than its parent
193197
if block.slot <= store.blocks[block.parent_root].slot:
194198
raise GossipReject("block is not from a higher slot than its parent")

specs/capella/p2p-interface.md

Lines changed: 22 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,6 @@ unconditionally enabled after The Merge, which happens before Capella.
107107
def validate_beacon_block_gossip(
108108
seen: Seen,
109109
store: Store,
110-
state: BeaconState,
111110
signed_beacon_block: SignedBeaconBlock,
112111
current_time_ms: Uint64,
113112
block_payload_statuses: Dict[Root, PayloadValidationStatus],
@@ -136,26 +135,11 @@ def validate_beacon_block_gossip(
136135
if proposer_slot_key in seen.proposer_slots:
137136
raise GossipIgnore("block is not the first valid block for this slot and proposer")
138137

139-
# [REJECT] The proposer index is a valid validator index
140-
if block.proposer_index >= len(state.validators):
141-
raise GossipReject("proposer index out of range")
142-
143-
# [REJECT] The proposer signature is valid
144-
proposer = state.validators[block.proposer_index]
145-
domain = get_domain(state, DOMAIN_BEACON_PROPOSER, compute_epoch_at_slot(block.slot))
146-
signing_root = compute_signing_root(block, domain)
147-
if not bls.Verify(proposer.pubkey, signing_root, signed_beacon_block.signature):
148-
raise GossipReject("invalid proposer signature")
149-
150138
# [IGNORE] The block's parent has been seen (via gossip or non-gossip sources)
151139
# (MAY be queued until parent is retrieved)
152140
if block.parent_root not in store.blocks:
153141
raise GossipIgnore("block's parent has not been seen")
154142

155-
# [REJECT] The block's execution payload timestamp is correct with respect to the slot
156-
if execution_payload.timestamp != compute_time_at_slot(state, block.slot):
157-
raise GossipReject("incorrect execution payload timestamp")
158-
159143
parent_payload_status = PAYLOAD_STATUS_NOT_VALIDATED
160144
if block.parent_root in block_payload_statuses:
161145
parent_payload_status = block_payload_statuses[block.parent_root]
@@ -172,6 +156,23 @@ def validate_beacon_block_gossip(
172156
if parent_payload_status == PAYLOAD_STATUS_INVALIDATED:
173157
raise GossipIgnore("block's parent is valid and its payload is invalid")
174158

159+
state = store.block_states[get_head(store).root]
160+
161+
# [REJECT] The proposer index is a valid validator index
162+
if block.proposer_index >= len(state.validators):
163+
raise GossipReject("proposer index out of range")
164+
165+
# [REJECT] The proposer signature is valid
166+
proposer = state.validators[block.proposer_index]
167+
domain = get_domain(state, DOMAIN_BEACON_PROPOSER, compute_epoch_at_slot(block.slot))
168+
signing_root = compute_signing_root(block, domain)
169+
if not bls.Verify(proposer.pubkey, signing_root, signed_beacon_block.signature):
170+
raise GossipReject("invalid proposer signature")
171+
172+
# [REJECT] The block's execution payload timestamp is correct with respect to the slot
173+
if execution_payload.timestamp != compute_time_at_slot(state, block.slot):
174+
raise GossipReject("incorrect execution payload timestamp")
175+
175176
# [REJECT] The block is from a higher slot than its parent
176177
if block.slot <= store.blocks[block.parent_root].slot:
177178
raise GossipReject("block is not from a higher slot than its parent")
@@ -198,12 +199,12 @@ def validate_beacon_block_gossip(
198199

199200
The `bls_to_execution_change` topic is used solely for propagating signed BLS to
200201
execution change messages on the network. Signed messages are sent in their
201-
entirety. The `state` parameter is the head state.
202+
entirety.
202203

203204
```python
204205
def validate_bls_to_execution_change_gossip(
205206
seen: Seen,
206-
state: BeaconState,
207+
store: Store,
207208
signed_bls_to_execution_change: SignedBLSToExecutionChange,
208209
current_time_ms: Uint64,
209210
) -> None:
@@ -216,7 +217,7 @@ def validate_bls_to_execution_change_gossip(
216217

217218
# [IGNORE] The current epoch is at or after the Capella fork epoch
218219
# (where current_epoch is defined by the current wall-clock time)
219-
time_since_genesis_ms = current_time_ms - state.genesis_time * 1000
220+
time_since_genesis_ms = current_time_ms - store.genesis_time * 1000
220221
current_slot = Slot(time_since_genesis_ms // SLOT_DURATION_MS)
221222
current_epoch = compute_epoch_at_slot(current_slot)
222223
if current_epoch < CAPELLA_FORK_EPOCH:
@@ -226,6 +227,8 @@ def validate_bls_to_execution_change_gossip(
226227
if validator_index in seen.bls_to_execution_change_indices:
227228
raise GossipIgnore("already seen BLS to execution change for this validator")
228229

230+
state = store.block_states[get_head(store).root]
231+
229232
# [REJECT] The validator index is valid
230233
if validator_index >= len(state.validators):
231234
raise GossipReject("validator index out of range")

0 commit comments

Comments
 (0)