Files
consensus/engine
zeekayandHanzo Dev 0c3beeb2e1 chain: request the cert catch-up the abandon path always promised
A follower that merely MISSED a cert stayed behind forever, and with 2 of 5 in
that state a 4-of-5 chain cannot reach α and halts. That is lux-testnet, stuck
at height 16821 with two validators holding 16818-16820 unfinalized.

rePollAllPending abandons a non-own block at maxRePollAttempts and logs

  "gossiped block abandoned after attempt cap — not re-soliciting further
   (recoverable via cert/catch-up)"

but nothing requested that recovery. Cert-gossip is send-once at assembly, so a
node that missed the broadcast never sees it again; and the BLOCK gate,
claimCatchupLocked, deliberately suppresses a fetch for a block already tracked
— which this block is. Its height-domain twin claimCertCatchupLocked exists for
exactly this case, says so in its own comment ("fetches the CERT for a block we
already hold"), and had ZERO callers. stuckRoundThreshold was defined and never
read. Runtime.requestCertCatchup, named in three comments, was never written.

Both ENDS were already built and live: the responder pairs each block with its
cert (encodeCatchupEntry), and the requester cert-accepts through
AcceptCatchupBlock, finalizing on the verified cert with no re-vote. Only the
ask was missing.

So ask. On abandon, claim the height-keyed gate under the lock and issue one
RequestAncestors after it — the same claim-under-lock / fire-after-unlock shape
the missing-bytes path already uses, because the transport takes its own locks.
chainID/networkID are fixed per-handler (every Catchup implementation ignores
them) and an empty `from` is the documented "no peer preference, node layer
samples" form.

Why it shipped: the unwired half was the untested half. catchup_selfheal_test.go
covered the missing-ANCESTOR arm — which is wired — and no test in engine/chain
referenced claimCertCatchupLocked, certCatchup or stuckRound at all. The new
test drives a TRACKED non-own block past the cap and asserts a fetch; it fails
on the parent commit with "got 0" and passes here.

Full ./engine/chain suite green (212s).

⚠ NOT verified under -race: this toolchain cannot build cgo (missing C headers),
so `go test -race` does not run here. The added lock discipline copies the
existing pattern verbatim — read t.catchup under t.mu alongside t.proposer, fire
outside — and certFetches is a function-local slice.

Hanzo Dev <[email protected]>

Co-authored-by: Hanzo Dev <[email protected]>
2026-08-01 00:58:56 -07:00
..
2025-12-19 08:49:11 -08:00