Observer: one checkpoint_locked event per index (the poll claims the state before its first await; the FinalityLock notification path raced it and the live feed showed two locked lines 30 ms apart); a lock claimed by the notification gets its votes_seen from the next poll
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
parent
960cd75e66
commit
7de1bdb027
1 changed files with 11 additions and 4 deletions
|
|
@ -512,7 +512,8 @@ async function tick(rpc) {
|
|||
}
|
||||
|
||||
// ---------- Finality v2 (spec 03) ----------
|
||||
const checkpointStates = new Map(); // index -> last state written
|
||||
const checkpointStates = new Map(); // index -> last state written; set BEFORE any await, so the two lock paths never both record
|
||||
const checkpointDetailed = new Set(); // indices written with votesSeen (the FinalityLock notification carries none; the poll fills it in once)
|
||||
let finalitySupported = null; // null = unknown, false = the node has no finality RPC
|
||||
let lastWeightsAt = 0;
|
||||
let lastWeights = null;
|
||||
|
|
@ -554,16 +555,22 @@ async function finalityTick(rpc) {
|
|||
if (!certBackfillDone) backfillCertificate(rpc, cps).catch(e => log('certificate backfill failed', e.message));
|
||||
for (const cp of cps.checkpoints || []) {
|
||||
const prev = checkpointStates.get(cp.index);
|
||||
if (prev !== cp.state || prev === undefined) {
|
||||
await upsertCheckpoint(cp);
|
||||
if (cp.state === 'locked' && prev !== 'locked') await recordLock(cp);
|
||||
const changed = prev !== cp.state || prev === undefined;
|
||||
const detail = cp.votesSeen !== undefined && !checkpointDetailed.has(cp.index);
|
||||
if (changed || detail) {
|
||||
// claim the transition before the first await: the FinalityLock notification handler checks this map synchronously,
|
||||
// and until 4 October 2026 both paths recorded the same lock (two "locked" events 30 ms apart on the live feed)
|
||||
checkpointStates.set(cp.index, cp.state);
|
||||
if (cp.votesSeen !== undefined) checkpointDetailed.add(cp.index);
|
||||
await upsertCheckpoint(cp);
|
||||
if (changed && cp.state === 'locked' && prev !== 'locked') await recordLock(cp);
|
||||
} else if (cp.state !== 'locked' && (cp.index % 1 === 0)) {
|
||||
// vote counts move while a checkpoint is open: refresh it
|
||||
await upsertCheckpoint(cp);
|
||||
}
|
||||
}
|
||||
for (const k of checkpointStates.keys()) if (k + 500 < Number(cps.nextIndex)) checkpointStates.delete(k);
|
||||
for (const k of checkpointDetailed) if (k + 500 < Number(cps.nextIndex)) checkpointDetailed.delete(k);
|
||||
const now = Date.now();
|
||||
if (now - lastWeightsAt > 10_000) {
|
||||
lastWeightsAt = now;
|
||||
|
|
|
|||
Loading…
Reference in a new issue