fix(spice): read execution heads only on spice-enabled code paths#15977
fix(spice): read execution heads only on spice-enabled code paths#15977shreyan-gupta wants to merge 1 commit into
Conversation
There was a problem hiding this comment.
Pull request overview
This PR makes spice_execution_head / spice_final_execution_head a guaranteed invariant on all nodes by (1) seeding them unconditionally at genesis and (2) backfilling older DBs at startup, allowing call sites to drop DBNotFound-style defensive fallbacks.
Changes:
- Seed SPICE execution heads at genesis unconditionally (no protocol-version gate).
- Backfill missing SPICE execution heads for existing databases on startup.
- Simplify multiple read sites to assume SPICE execution heads exist (remove
DBNotFoundfallbacks).
Reviewed changes
Copilot reviewed 7 out of 7 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| chain/client/src/spice/data_distributor_actor.rs | Removes fallback logic and requires spice_final_execution_head to exist when starting missing-data search. |
| chain/client/src/spice/chunk_executor_actor/receipt_tracker.rs | Removes “absent on non-spice” early return; now relies on the seeded/backfilled final execution head. |
| chain/client/src/spice/chunk_executor_actor/per_shard.rs | Switches to an invariant-based read of spice_final_execution_head for descendant checks. |
| chain/client/src/spice/chunk_executor_actor/coordinator.rs | Removes fallback-to-genesis scanning; starts from spice_final_execution_head directly. |
| chain/chain/src/spice/chain.rs | Makes find_first_executed_ancestor require the final execution head instead of treating it as optional. |
| chain/chain/src/genesis.rs | Seeds SPICE execution heads at genesis for all nodes. |
| chain/chain/src/chain.rs | Backfills missing SPICE execution heads on startup for DBs created before the invariant existed. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| let final_execution_head = | ||
| chain_store.spice_final_execution_head().expect("failed to find final execution head"); |
There was a problem hiding this comment.
Don't think this is an issue.
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## master #15977 +/- ##
==========================================
- Coverage 72.60% 72.59% -0.01%
==========================================
Files 952 952
Lines 205109 205094 -15
Branches 205109 205094 -15
==========================================
- Hits 148914 148898 -16
- Misses 51218 51219 +1
Partials 4977 4977
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
32aee7a to
d4d8662
Compare
d4d8662 to
8b970eb
Compare
Background
The SPICE execution heads (
spice_execution_head/spice_final_execution_head) track the execution frontier and are meaningful only when SPICE is enabled, so every reader should sit behind aProtocolFeature::Spice.enabledcheck. One didn't: the node Status handler calledfind_first_executed_ancestorunconditionally — on non-spice nodes too. That ungated read is the only reason the read sites carried defensive.ok()/DBNotFoundfallbacks.Change
ProtocolFeature::Spice.enabled(from the head's epoch), falling back to the head block header otherwise — mirroring the already-correctview_client_actorpath. Non-spice nodes no longer read the spice head.find_first_executed_ancestor,prune_below_final_head,is_descendant_of_final_execution_head,process_all_ready_blocks,start_waiting_on_missing_data.The chunk-executor / data-distributor read sites are gated at compile time (
cfg(protocol_feature_spice)) rather than at runtime, so their now-unconditional reads rely on the head being seeded at genesis — which holds because SPICE is enabled from genesis wherever these actors run.is_descendant_of_final_execution_headdocuments this invariant and fails loud if it is ever violated.Context
Supersedes the earlier "always seed the execution heads" approach: seeding a head for non-spice nodes that then never updates is a wart; gating the one ungated reader is the cleaner fix.