Conversation
This is just in case.
When a block advances latest_justified during processing (interval 0), safe_target remains stale until interval 2. This causes get_attestation_target() to walk back past the new justified checkpoint, producing attestations where source.slot > target.slot. Clamp the target to latest_justified when it falls behind, matching Zeam's approach. Closes #97
🤖 Kimi Code ReviewSecurity & Correctness IssuesLine 477-485: The new condition Line 488-502: The clamping logic introduces inconsistency with the checkpoint's root. When Performance & SafetyLine 482-484: The Suggested Fixes
The logging addition (line 496-500) is good for debugging but doesn't address the underlying correctness issues. Automated review by Kimi (Moonshot AI) · custom prompt |
🤖 Codex Code ReviewFindings (ordered by severity)
If those invariants are already guaranteed elsewhere, the change looks good and the new clamp is a reasonable safety net. Possible next steps
Automated review by OpenAI Codex · custom prompt |
🤖 Claude Code ReviewNow I have enough context to provide a comprehensive review. Let me create the review document: PR #98 Review: Fix Attestation Target ClampingSummaryThis PR addresses a critical consensus bug where ethlambda produces invalid attestations with Root Cause Analysis ✅The PR description provides excellent analysis of the timing issue:
The diagnosis is sound and well-documented. Code Changes ReviewLocation:
|
Greptile OverviewGreptile SummaryFixes Key Changes:
Root Cause: Fix Approach: Confidence Score: 4/5
|
| Filename | Overview |
|---|---|
| crates/blockchain/src/store.rs | Adds clamp to ensure attestation target.slot >= source.slot, fixing race condition between justified checkpoint updates and safe_target updates |
Sequence Diagram
sequenceDiagram
participant Block as on_block()
participant Store as Store
participant SafeTarget as update_safe_target()
participant Attest as produce_attestation_data()
participant GetTarget as get_attestation_target()
Note over Block,Store: Interval 2: safe_target = slot 2
SafeTarget->>Store: set safe_target = slot 2
Note over Block,Store: Interval 0: Block advances justified
Block->>Store: on_block() processes new block
Block->>Store: update latest_justified = slot 3
Note over Store: safe_target still = slot 2 (stale)
Note over Attest,GetTarget: Interval 1: Produce attestation
Attest->>GetTarget: get_attestation_target()
GetTarget->>Store: read safe_target (slot 2)
GetTarget->>GetTarget: walk back from head to slot 2
Note over GetTarget: target_block.slot = 2
GetTarget->>Store: read latest_justified (slot 3)
alt target_block.slot < latest_justified.slot
GetTarget->>GetTarget: CLAMP: return latest_justified
Note over GetTarget: target = slot 3 (clamped)
else target_block.slot >= latest_justified.slot
GetTarget->>GetTarget: return target_block
Note over GetTarget: target = computed slot
end
GetTarget-->>Attest: return target checkpoint
Attest->>Store: read latest_justified (slot 3)
Note over Attest: source = slot 3, target = slot 3
Note over Attest: ✓ Invariant maintained: source.slot <= target.slot
Summary
Fixes the
SourceSlotExceedsTargetbug where ethlambda produces attestations withsource.slot > target.slot.Closes #97
Root Cause
The store has two fields with different update cadences:
latest_justifiedon_block()— any intervalsourcesafe_targetupdate_safe_target()targetcomputationWhen a block at interval 0 advances
latest_justified,safe_targetremains stale until the next interval 2. During attestation production at interval 1,get_attestation_target()walks back from head toward the stalesafe_target, landing on a slot behind the newlatest_justified:This is a spec-level gap — the leanSpec
get_attestation_target()does not enforcetarget.slot >= latest_justified.slot.Fix
Add a clamp guard at the end of
get_attestation_target(): if the computed target slot falls behindlatest_justified.slot, returnlatest_justifiedas the target instead. A warning is logged when clamping occurs.This matches Zeam's approach.
Test plan
make lintpassesmake test— all 35 spec tests passSourceSlotExceedsTargetwarnings disappear from peer logs"Attestation target walked behind justified source, clamping to justified"warning fires during the slots where clamping occurs