diff --git a/infra/fast-time/vote-or-burn.mjs b/infra/fast-time/vote-or-burn.mjs index 3859a9f43..c1ff6b455 100644 --- a/infra/fast-time/vote-or-burn.mjs +++ b/infra/fast-time/vote-or-burn.mjs @@ -65,8 +65,12 @@ export function swapFinality(text, which) { return text.replace(/"finality":\s*\{[^}]*\}/, block); } const REPLAY_BPS = flag('replay-bps', 0); +// --subsidy-per-block: ledger N8's switch at 0 (the execution layer credits each merged block the subsidy of its own +// DAA, as the UTXO coinbase pays it); the exact per-row bridge identity is then a failing check, not a reading +const SUBSIDY_PER_BLOCK = args.includes('--subsidy-per-block'); const REPLAY_WAIT = flag('replay-wait', 240); -const CASE = sflag('case') || `rule-${RULE}-expect-${EXPECT}${REPLAY ? (REPLAY_BPS ? `-replay-bps${REPLAY_BPS}` : '-replay') : ''}`; +const CASE_SUFFIX = SUBSIDY_PER_BLOCK ? '-per-block' : ''; +const CASE = sflag('case') || `rule-${RULE}-expect-${EXPECT}${REPLAY ? (REPLAY_BPS ? `-replay-bps${REPLAY_BPS}` : '-replay') : ''}${CASE_SUFFIX}`; const OUT = sflag('out') || `${ROOT}docs/plans/counter-asic-3-gate/vote-or-burn-${CASE}.json`; const FIGURES = { none: { producer: 1.0, pool_over_full_producer: 0.25 }, burn: { producer: 0.8, pool_over_full_producer: 0.25 }, bonus: { producer: 0.9, pool_over_full_producer: 0.35 } }; // vote-or-burn was removed from the node on 7 October 2026 (the project lead's word: the bonus at the testnet genesis, no burn); the @@ -91,7 +95,7 @@ const DAY_MS = field('pow_day_ms'); const override = `${TMP}/override.json`; writeFileSync(override, mergeOverrideText(swapFinality(baseText, FINALITY), { genesis_bits: GENESIS_BITS, skip_proof_of_work: false, - signing_bonus_activation_daa: RULE === 'bonus' ? '0' : NEVER, + signing_bonus_activation_daa: RULE === 'bonus' ? '0' : NEVER, ...(SUBSIDY_PER_BLOCK ? { subsidy_per_block_activation_daa: '0' } : {}), program_class_v3_activation_daa: NEVER, program_class_v4_activation_daa: NEVER, })); log(`case ${CASE}: finality ${FINALITY}, rule ${RULE}, expect ${EXPECT} (producer ratio ${FIGURES[EXPECT].producer}, pool ${FIGURES[EXPECT].pool_over_full_producer} of the full producer share), ${SECS} s, tail ${TAIL}`); @@ -266,6 +270,8 @@ const checks = { a_pool_is_a_quarter: poolA != null && medA && Math.abs(poolA / medA - 0.25) <= TOL, // ledger N7: the EVM side pays a silent key the bonus share too (B's credit over A's reads the rule's figure) evm_bonus_ratio_matches: bridge.evm_a.length >= PAIRS && bridge.evm_b.length >= PAIRS && evmRatio != null && Math.abs(evmRatio - want.producer) <= TOL && !bridge.error, + // ledger N8: with the per-block rule on, every pair row's EVM credit equals the UTXO coinbase's payment exactly + ...(SUBSIDY_PER_BLOCK ? { bridge_identity_exact: bridge.rows >= PAIRS && bridge.disagree.length === 0 && !bridge.error } : {}), }; if (REPLAY) { checks.replay_late_node_holds_every_block = !!replay?.synced;