refactor(blockchain): group on_tick conditionals by interval#450
refactor(blockchain): group on_tick conditionals by interval#450MegaRedHand wants to merge 4 commits into
Conversation
🤖 Kimi Code ReviewCritical Issue: Unawaited Async Operation Line 278: Verification: Check if Consensus Correctness: Interval Ordering The reordering of interval logic is correct and fixes a subtle sequencing bug:
This ensures aggregation sessions (Interval 2) start after attestations are produced (Interval 1), which is required for meaningful aggregation. Interval 4 Snapshot Timing Lines 259-262: The comment correctly identifies the race condition between snapshotting Minor Observations
Verdict: The structural refactoring improves readability and fixes the temporal ordering of consensus operations. Address the potential unawaited Future before merging. Automated review by Kimi (Moonshot AI) · kimi-k2.5 · custom prompt |
🤖 Codex Code ReviewNo findings. The change in crates/blockchain/src/lib.rs looks non-semantic: the interval-4 Residual gap: I could not complete a Automated review by OpenAI Codex · gpt-5.4 · custom prompt |
f8d6ec2 to
9e43879
Compare
🤖 Claude Code ReviewHere is the review output: PR Review:
|
on_tick ran its per-interval blocks out of order (4-snapshot, tick, 2, 0, 1). Regroup them into ascending interval order behind `==== interval N ====` markers so the slot timeline reads top to bottom and matches the duty schedule. Pure reorder, behavior unchanged. The interval-4 new_payloads snapshot is the one block that stays ahead of store::on_tick: the interval-4 tick promotes new_payloads out, so it cannot move into a post-tick group. A comment now pins that constraint.
Greptile SummaryThis PR reorders the per-interval blocks inside
Confidence Score: 4/5Safe to merge — the reorder is purely cosmetic because every block is guarded by its own interval predicate, and the one ordering constraint that matters (interval-4 snapshot before store::on_tick) is correctly preserved and now explicitly documented. The only actionable finding is that unconditional metrics calls (update_safe_target_slot, update_head_slot, advance_keys_to) land under the // ==== interval 3 ==== banner, which could mislead a future developer into treating them as interval-3-specific. This is a readability concern with no current behavioral impact. crates/blockchain/src/lib.rs — the tail of on_tick after the interval-2 block mixes unconditional per-tick calls under the interval-3 section label.
|
| Filename | Overview |
|---|---|
| crates/blockchain/src/lib.rs | Pure reorder of per-interval blocks in on_tick to ascending order (0→1→2→3), with the interval-4 snapshot correctly kept pre-tick; minor concern that unconditional metrics calls sit under the interval 3 banner, which could mislead future readers. |
Sequence Diagram
%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
participant T as on_tick
participant S as store::on_tick
participant C as coverage
participant M as metrics
Note over T: interval 4 (pre-tick)
T->>C: "snapshot_new_payloads() [if interval==4]"
T->>S: store::on_tick(timestamp_ms, has_proposer)
Note over S: accepts attestations (int 0)<br/>updates safe-target (int 3)<br/>promotes new_payloads (int 4)
Note over T: interval 0
T->>T: propose_block() [if proposer_validator_id]
Note over T: interval 1
T->>C: "emit_post_block_coverage() [if slot>0]"
T->>T: produce_attestations()
Note over T: interval 2
T->>C: emit_agg_start_new_coverage() [if is_aggregator]
T->>T: start_aggregation_session()
Note over T: interval 3
Note over S: (safe-target already updated inside store::on_tick)
T->>M: update_safe_target_slot()
T->>M: update_head_slot()
T->>T: advance_keys_to(slot+1)
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
participant T as on_tick
participant S as store::on_tick
participant C as coverage
participant M as metrics
Note over T: interval 4 (pre-tick)
T->>C: "snapshot_new_payloads() [if interval==4]"
T->>S: store::on_tick(timestamp_ms, has_proposer)
Note over S: accepts attestations (int 0)<br/>updates safe-target (int 3)<br/>promotes new_payloads (int 4)
Note over T: interval 0
T->>T: propose_block() [if proposer_validator_id]
Note over T: interval 1
T->>C: "emit_post_block_coverage() [if slot>0]"
T->>T: produce_attestations()
Note over T: interval 2
T->>C: emit_agg_start_new_coverage() [if is_aggregator]
T->>T: start_aggregation_session()
Note over T: interval 3
Note over S: (safe-target already updated inside store::on_tick)
T->>M: update_safe_target_slot()
T->>M: update_head_slot()
T->>T: advance_keys_to(slot+1)
Comments Outside Diff (1)
-
crates/blockchain/src/lib.rs, line 325-332 (link)Unconditional calls grouped under an interval-3 banner
metrics::update_safe_target_slotandmetrics::update_head_slotrun on every tick, not just at interval 3. Placing them under// ==== interval 3 ====might lead a future developer to assume they are interval-3-gated when refactoring, especially since the head-slot comment explicitly mentions "intervals 0/4". Consider pulling these (andkey_manager.advance_keys_to) into a trailing// ==== every tick ====section so the interval labels stay consistent in meaning.Prompt To Fix With AI
This is a comment left during a code review. Path: crates/blockchain/src/lib.rs Line: 325-332 Comment: **Unconditional calls grouped under an interval-3 banner** `metrics::update_safe_target_slot` and `metrics::update_head_slot` run on **every** tick, not just at interval 3. Placing them under `// ==== interval 3 ====` might lead a future developer to assume they are interval-3-gated when refactoring, especially since the head-slot comment explicitly mentions "intervals 0/4". Consider pulling these (and `key_manager.advance_keys_to`) into a trailing `// ==== every tick ====` section so the interval labels stay consistent in meaning. How can I resolve this? If you propose a fix, please make it concise.
Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!
Prompt To Fix All With AI
Fix the following 1 code review issue. Work through them one at a time, proposing concise fixes.
---
### Issue 1 of 1
crates/blockchain/src/lib.rs:325-332
**Unconditional calls grouped under an interval-3 banner**
`metrics::update_safe_target_slot` and `metrics::update_head_slot` run on **every** tick, not just at interval 3. Placing them under `// ==== interval 3 ====` might lead a future developer to assume they are interval-3-gated when refactoring, especially since the head-slot comment explicitly mentions "intervals 0/4". Consider pulling these (and `key_manager.advance_keys_to`) into a trailing `// ==== every tick ====` section so the interval labels stay consistent in meaning.
Reviews (1): Last reviewed commit: "refactor(blockchain): group on_tick cond..." | Re-trigger Greptile
c0d6ff0 to
f690ec7
Compare
…ick flag Compute scheduled_proposer just before store::on_tick and pass the raw is_proposer (= scheduled_proposer.is_some()) to it; gate the actual proposal on duties_allowed() at the call site instead. While syncing and scheduled to propose, on_tick now accepts attestations early at interval 0 (it did not before); the proposal itself is still skipped.
Split out of #445 (proposer pre-build). Stacked on #449 (
gate_proposerremoval) — review/merge that first; this PR's base retargets tomainonce #449 lands.on_tickran its per-interval blocks out of order (interval-4 snapshot, then tick, then 2, 0, 1). This regroups them into ascending interval order behind==== interval N ====markers so the slot timeline reads top-to-bottom and lines up with the duty schedule.Pure reorder, behavior unchanged.
One block intentionally does not move
The interval-4
new_payloadssnapshot stays ahead ofstore::on_tick. At interval 4 the tick runsaccept_new_attestations → promote_new_aggregated_payloads(), which drainsnew_payloads; snapshotting after the tick would capture an already-drained set and silently break the post-block coverage report's "timely" cohort. A comment now pins that ordering constraint.