diff --git a/infra/fast-time/testnet-object.mjs b/infra/fast-time/testnet-object.mjs index 11e7747e7..9aea178d1 100644 --- a/infra/fast-time/testnet-object.mjs +++ b/infra/fast-time/testnet-object.mjs @@ -88,6 +88,7 @@ const switches = { program_class_v3_activation_daa: num(objectText, 'program_class_v3_activation_daa'), program_class_v4_activation_daa: num(objectText, 'program_class_v4_activation_daa'), program_class_v4_signal_window_daa: num(objectText, 'program_class_v4_signal_window_daa'), + program_class_v5_activation_daa: num(objectText, 'program_class_v5_activation_daa'), latency_ladder_activation_daa: num(objectText, 'latency_ladder_activation_daa'), latency_ladder_window_daa: String(LADDER_WINDOW), fees_v1_activation_daa: num(objectText, 'fees_v1_activation_daa'), @@ -97,6 +98,10 @@ const switches = { proving_aggregator_id: JSON.stringify(str(objectText, 'proving_aggregator_id')), }; for (const [k, v] of Object.entries(switches)) if (v === undefined) { console.error(`the object has no ${k}`); process.exit(2); } +// the class every epoch's template must carry: 5 when the object holds class v5 from genesis (the go object 0d05e795 of +// 8 October 2026, byte 6), else 4 (the 5b673577 object, byte 7); before this the line copied only the v4 keys and ran +// class v4 under a class v5 object (row 9u of docs/plans/testnet-go.md) +const OBJECT_CLASS = String(switches.program_class_v5_activation_daa) === '0' ? 5 : 4; const ladderList = /"latency_ladder":\s*(\[[\s\S]*?\])/.exec(objectText)[1].replace(/\s+/g, ''); const feesObject = /"fees":\s*(\{[\s\S]*?\n \})/.exec(objectText)[1].replace(/\s+/g, ''); const emissionObject = /"emission":\s*(\{[\s\S]*?\n \})/.exec(objectText)[1].replace(/\s+/g, '').replace(/"launch_rate":"(\d+)"/, (_, r) => `"launch_rate":"${BigInt(r) / WEI_PER_SOMPI}"`); @@ -205,7 +210,9 @@ for (const n of nodes) log(`n${n.i}: ${Object.entries(START_LINES).map(([k, re]) // n0 and n1 vote (the key is the payout label's identity); n2 never votes: the silent key // the miners (and so the voters) outlive the run by five minutes and are stopped by the stop hook, so the final finality // read never sees a table nobody signs (pod 2 of 8 October 2026 read "0.00% signing" after the voters had exited with the run) -const miners = nodes.map((n, i) => miner(CPU_MINER, ['mine', n.grpc, '1', String(SECS + 300), `cpu${i}`, '--engine', 'igneum-pow', '--payout-label', LABELS[i], '--evm-address', EVM[i], '--dev-fee', '0', '--status-secs', '30', '--stall-secs', '0', ...(i === SILENT ? ['--no-vote'] : [])], `cpu${i}`, { IGNEUM_POW_DAY_MS: String(DAY_MS) })); +const miners = nodes.map((n, i) => miner(CPU_MINER, ['mine', n.grpc, '1', String(SECS + 300), `cpu${i}`, '--engine', 'igneum-pow', '--payout-label', LABELS[i], '--evm-address', EVM[i], '--dev-fee', '0', '--status-secs', '30', '--stall-secs', '0', '--exec-rpc', `http://127.0.0.1:${n.evmPort}`, ...(i === SILENT ? ['--no-vote'] : [])], `cpu${i}`, { IGNEUM_POW_DAY_MS: String(DAY_MS) })); +// --exec-rpc: the class v5 state provider's address; without it the 0.3.24-line miner asks the devnet port 26790 on every +// network (row 9t), and five one-box nodes have five exec ports const pay = devAddress('fast-time-testnet-object'); const epochs = new Map(); @@ -412,9 +419,10 @@ function longestInactiveStretchAfter(daa) { const checks = { start_lines_on_every_node: nodes.every(n => Object.entries(START_LINES).every(([k, re]) => k === 'class_v4' || n.grepLog(re).length > 0)), digest_equal_on_every_node: new Set(nodes.map(n => (n.grepLog(START_LINES.digest)[0] || '').replace(/^.*?digest: /, '').slice(0, 64))).size === 1, - every_epoch_class_v4_at_rung_0: epochs.size > 0 && [...epochs.values()].every(e => e.class === 4 && (e.step === 0 || e.step == null) && (e.reps === RUNG0 || e.reps == null)), - // the object byte every mined block stamps is the one the node's own start-up line names ("stamps object version N"; 7 on - // the 0.3.24 testnet object, the Devnet 3 shape with class signalling on; 0 when signalling is off); no ladder bits + every_epoch_object_class_at_rung_0: epochs.size > 0 && [...epochs.values()].every(e => e.class === OBJECT_CLASS && (e.step === 0 || e.step == null) && (e.reps === RUNG0 || e.reps == null)), + // the object byte every mined block stamps is the one the node's own start-up line names ("stamps object version N"; 6 on + // the go object with class v5 from genesis, 7 on the 5b673577 object, the Devnet 3 shape with class signalling on; 0 when + // signalling is off); no ladder bits no_ladder_bits_and_object_byte_as_stamped: blocks.length > 0 && Object.keys(ladderBits).every(k => k === 'none') && Object.keys(objectBytes).every(v => +v === stampedByte), zero_rejected_by_nodes: rejectedNode.every(c => c === 0), sinks_and_counts_agree: new Set(sinks).size === 1 && new Set(counts.map(String)).size === 1,