class v5 harness: the stale miner's fall-off is judged by the block's DAA score (a nonce found on a pre-boundary template and submitted after it is a flip-epoch block, valid; the wall-clock count failed the 20:4x UK run on one such block), nonces matched as the nearest double the JSON RPC carries
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
parent
d1ca2416fc
commit
6cf648e6ae
1 changed files with 25 additions and 4 deletions
|
|
@ -237,7 +237,7 @@ async function allBlocks(n) {
|
|||
const r = await n.rpc.call('getBlocks', { lowHash: low, includeBlocks: true, includeTransactions: false });
|
||||
const blocks = r.blocks || [];
|
||||
let added = 0;
|
||||
for (const b of blocks) { const h = b.verboseData?.hash || b.header?.hash; if (seen.has(h)) continue; seen.add(h); out.push({ hash: h, daa: +b.header.daaScore, version: +b.header.version, chain: !!b.verboseData?.isChainBlock }); added++; }
|
||||
for (const b of blocks) { const h = b.verboseData?.hash || b.header?.hash; if (seen.has(h)) continue; seen.add(h); out.push({ hash: h, daa: +b.header.daaScore, version: +b.header.version, nonce: Number(b.header.nonce ?? 0), chain: !!b.verboseData?.isChainBlock }); added++; }
|
||||
if (!blocks.length || added === 0) break;
|
||||
low = (r.blockHashes || []).at(-1) || blocks.at(-1).verboseData?.hash; if (!low) break;
|
||||
}
|
||||
|
|
@ -332,9 +332,30 @@ const statelessAcceptedAfterFlip = statelessNode ? acceptedAfter(statelessNode.i
|
|||
const honestAcceptedAfterFlip = SIGNALLING.filter(n => n.i !== STALE).map(n => acceptedAfter(n.i, flipAtMs));
|
||||
// the refusal reaches the miner as a template error and the node's log as the engine's line; either counts
|
||||
const statelessRefusals = statelessNode ? statelessNode.grepLog(REFUSAL_LINE).length + minerLog(statelessNode.i).filter(l => REFUSAL_LINE.test(l)).length : 0;
|
||||
// the stale miner: accepted after the FIRST REFRESH after the flip (one epoch later), and its rejections
|
||||
const refreshWall = flipAtMs == null ? null : flipAtMs + EPOCH * 1000;
|
||||
const staleAcceptedAfterRefresh = STALE == null ? null : acceptedAfter(STALE, refreshWall);
|
||||
// the stale miner: accepted blocks IN the first refresh epoch after the flip or later (its frozen leaves are the flip
|
||||
// epoch's; from the next epoch its blocks fail PoW), and its rejections. Judged by the block's DAA score, not the wall
|
||||
// clock: a nonce found on a template taken before the boundary and submitted a few seconds after it is a flip-epoch
|
||||
// block (the 20:4x UK run of 7 October 2026 read one such ACCEPTED line, "template 2 gens old", 4.7 s after the
|
||||
// boundary's wall time, and the wall-clock form of this count failed the case on a block that was valid). The miner's
|
||||
// ACCEPTED line carries the nonce; the chain carries the nonce and the DAA score of every block.
|
||||
const refreshDaa = firstV4 ? (firstV4.epoch + 1) * EPOCH : null;
|
||||
// the JSON RPC carries the 64-bit nonce as a JSON number, so the node's value arrives as the nearest double; Number(BigInt(hex))
|
||||
// of the miner's line is the nearest double to the same integer, so the two keys are equal (660 blocks never share one)
|
||||
const blockByNonce = new Map(blocks.map(b => [b.nonce, b]));
|
||||
function acceptedAtOrAboveDaa(i, daa) {
|
||||
if (daa == null) return 0;
|
||||
let count = 0, unmatched = 0;
|
||||
for (const l of minerLog(i)) {
|
||||
const m = /ACCEPTED block nonce=(0x[0-9a-f]+)/.exec(l);
|
||||
if (!m) continue;
|
||||
const b = blockByNonce.get(Number(BigInt(m[1])));
|
||||
if (!b) { unmatched++; continue; }
|
||||
if (b.daa >= daa) count++;
|
||||
}
|
||||
if (unmatched) log(`miner ${i}: ${unmatched} ACCEPTED nonce(s) not found on the chain read from n0 (pruned or a side block)`);
|
||||
return count;
|
||||
}
|
||||
const staleAcceptedAfterRefresh = STALE == null ? null : acceptedAtOrAboveDaa(STALE, refreshDaa);
|
||||
const staleRejected = STALE == null ? null : rejectedMiner[STALE].length;
|
||||
const daysSeen = [...new Set([...dayOfEpoch.values()])];
|
||||
const sinks = dag.map(d => String(d.sink || '?').slice(0, 16));
|
||||
|
|
|
|||
Loading…
Reference in a new issue