mirror of
https://github.com/luxfi/consensus.git
synced 2026-09-24 00:26:58 +00:00
The pre-fix swallowed-VM.Accept bug let a node's durable decided-floor (vote-guard finalizedThrough) advance past every VM's last-accepted head. On reboot WithVoteGuard re-seeds that phantom floor, the sign gate treats the never-applied heights as decided, and the round-scoped view-change can never re-finalize them — the chain is wedged even after the liveness fix. Add a DELIBERATE, bounded recovery: - VoteGuardStore.Reconcile: the ONE writer permitted to LOWER finalizedThrough (Persist stays monotonic). DRY atomic write shared via writeSnapshot. - Transitive.ReconcilePhantomFloor(target): lowers decidedFloor to max(target, localVM) — an intrinsic guard that can never abandon a block THIS node applied — drops committedSlot/lockRounds/recoveredLocks above it, and durably rewrites the lowered floor. Fail-closed (nothing changes on a store error); idempotent; a zero target is a no-op. Safety (no observable double-cert): reconciling only heights strictly above the fleet-max VM-applied height abandons ONLY internal-only finalizations — no VM applied them (never externalized over RPC/bridge/light-client) and their cert material was in-memory and is gone post-restart, so no party can present a cert; re-finalizing fresh yields exactly one presentable cert. Committed heights at/below the floor are recovered by frontier-trust bootstrap, never re-finalized. Tests: floor lowered + phantom dropped + committed retained; durable monotonic bypass; intrinsic guard vs wrong-low target; behind-node target-governs; phantom-becomes-signable/committed-stays-decided; no-ops; idempotent; fail-closed. Full engine/chain suite green under -race. Co-authored-by: Hanzo Dev <[email protected]>