igneum/site/lib/emission.test.mjs
igneum-labs 82973eb499 Observer: explorer detail per block from the notification, chain block number from the shard plan, RPC load counter, hourly coinbase check against spec 2.5
site/lib/emission.mjs is the emission rule as igneum.rs computes it (block_subsidy, launch_ramp, an exact floor-sum for
minted-so-far); its tests reproduce the node's own test values and a devnet coinbase (block 2622db76: payload 454,486,399
at DAA 125,064, outputs 454,485,299 = E(125,063), what the merged parent declared). Every live_blocks row gains tx_count,
evm_miner (the IGNA tag, else the vote key's low 20 bytes), proof_records (IGNP section), subsidy_sompi, paid_sompi,
selected_parent, number, detail. No extra RPC per block: measured 282 against 283 wRPC and 785 against 776 EVM calls
per minute before and after. live_state.rpc_load and live_state.supply_check are new.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-05 19:35:40 +00:00

56 lines
3.1 KiB
JavaScript

import { test } from 'node:test';
import assert from 'node:assert/strict';
import * as E from './emission.mjs';
test('constants match igneum.rs and spec 2.5', () => {
assert.equal(E.BASE_SUBSIDY_PER_SECOND_SOMPI, 3_168_808_781n); // igneum.rs test: assert_eq!(BASE_SUBSIDY_PER_SECOND_SOMPI, 3_168_808_781)
assert.equal(E.HALVING_INTERVAL_SECONDS, 63_115_200n);
assert.equal(E.LAUNCH_RAMP_SECONDS, 2_592_000n);
assert.equal(E.SUPPLY_CAP_SOMPI, 400_000_000_000_000_000n);
});
test('blockSubsidy reproduces the node tests (igneum.rs)', () => {
assert.equal(E.blockSubsidy(2_592_000, 1), 3_168_808_781n); // ramp over
assert.equal(E.blockSubsidy(63_115_200 - 1, 1), 3_168_808_781n);
assert.equal(E.blockSubsidy(63_115_200, 1), 1_584_404_390n);
assert.equal(E.blockSubsidy(2 * 63_115_200, 1), 792_202_195n);
assert.equal(E.blockSubsidy(31 * 63_115_200, 1), 1n);
assert.equal(E.blockSubsidy(32 * 63_115_200, 1), 0n);
assert.equal(E.blockSubsidy(2_592_000 * 10, 10), 316_880_878n);
assert.equal(E.blockSubsidy(63_115_200 * 10, 10), 158_440_439n);
assert.equal(E.launchRamp(1_000_000n, 1_296_000), 550_000n);
assert.equal(E.launchRamp(1_000_000n, 2_591_999), 999_999n);
});
test('blockSubsidy matches a devnet coinbase payload (block 2622db76, DAA 125,064, 5 Oct 2026)', () => {
assert.equal(E.blockSubsidy(125_064, 1), 454_486_399n); // payload bytes 8..16 = 0x1b16e97f
assert.equal(E.blockSubsidy(125_063, 1), 454_485_299n); // what its merged parent declared and it paid: 363,588,240 + 90,897,059
});
test('mintedByRule equals the brute-force sum and respects the cap', () => {
let s = 0n; for (let t = 0; t < 3000; t++) { if (t === 777) assert.equal(E.mintedByRule(777), s); s += E.blockSubsidy(t, 1); }
assert.equal(E.mintedByRule(3000), s);
assert.equal(E.mintedByRule(0), 0n);
const end = E.mintedAtEnd();
assert.ok(end < E.SUPPLY_CAP_SOMPI);
assert.equal(E.sompiToIgn(end), '3963038988.86765648'); // the cap less the ramp's withheld part (about 37 million) and the floors
// the ramp withholds 0.45 x 2,592,000 / 31,557,600 x 10^9 = 36,961,... IGN (spec 2.5 "about 37 million")
const withheld = E.SUPPLY_CAP_SOMPI - end;
assert.ok(withheld > 36_900_000n * E.SOMPI_PER_IGN && withheld < 37_000_000n * E.SOMPI_PER_IGN, withheld.toString());
});
test('floorSum against a loop', () => {
for (const [n, m, a, b] of [[10n, 7n, 3n, 5n], [1000n, 13n, 17n, 0n], [5n, 1n, 0n, 0n], [333n, 1000n, 999n, 999n]]) {
let s = 0n; for (let i = 0n; i < n; i++) s += (a * i + b) / m;
assert.equal(E.floorSum(n, m, a, b), s);
}
});
test('halvingTable has 33 rows and halves per second', () => {
const t = E.halvingTable();
assert.equal(t.length, 33);
assert.equal(t[0].per_second_sompi, 3_168_808_781n);
assert.equal(t[1].per_second_sompi, 1_584_404_390n);
assert.equal(t[32].per_second_sompi, 0n);
assert.equal(t[1].start_daa, 63_115_200n);
});
test('sompiToIgn and weiToIgn', () => {
assert.equal(E.sompiToIgn(454_485_299n), '4.54485299');
assert.equal(E.sompiToIgn(100_000_000n), '1');
assert.equal(E.weiToIgn('0x3275f7e5ad621000'), '3.636084');
});