You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Attestation target can walk behind the head's justified checkpoint; other clients clamp, Verity skips the vote #44
The attestation duty is skipped with SOURCE_AFTER_TARGET when the target walk-back lands behind the head chain's justified checkpoint. In the 2026-09-11 three-node devnet5 run (PR #42) it fired at slots 16 and 64 (twice):
WARN duty not performed slot=64 interval=321 error=the duty would produce a rejected value: SOURCE_AFTER_TARGET
Why
Verity's attestation_target / attestation_data are a faithful transcription of leanSpec validator_duties.py (0b7d33ec), including the spot where leanSpec assertssource.slot <= target.slot. The assert condition is reachable: the persisted fork-choice tree of that run (dumped from the node's RocksDB) shows the head chain 62 → 59 → 51 → 50 → 49 → 45 → 42 with finalized 42 and the head state's justified at 49. The three-step walk-back from 62 lands on 50; 50 and 49 are not justifiable relative to finalized 42 (deltas 8 and 7), so the justifiability walk continues to 45 — behind the source at 49. Nothing in the spec bounds the second walk by the justified slot, and a sparse chain (three nodes, one proposer per slot, many orphans) makes the three-step walk cover many slots.
ethlambda (crates/blockchain/src/store.rs, get_attestation_target_with_checkpoints) and ream (crates/common/fork_choice/lean/src/store.rs) both clamp the target to the head's justified checkpoint in this case, with a comment that it is "not in the spec" (ethlambda cites zeam doing the same). Verity returns the vote as a rejection and casts nothing, so its validator's weight is missing from those slots.
Fix direction
Match the other clients: when the walked target's slot is below the head state's justified slot, return the justified checkpoint as the target (and log it). Keep the SourceAfterTarget rejection as the assertion it is, now unreachable from the duty path. Worth raising upstream on leanSpec as well, since the reference implementation would assert here.
Activity
adust09 commentedon Sep 11, 2026
Upstream: leanSpec issue leanEthereum/leanSpec#1206 and PR leanEthereum/leanSpec#1207 propose the same clamp in
produce_attestation_data. Verity fix: #47.