From 6720d629af2a6624cc67cc16ca84d296f77ad76c Mon Sep 17 00:00:00 2001 From: igneum-labs <337424239+igneum-labs@users.noreply.github.com> Date: Fri, 9 Oct 2026 08:25:53 +0000 Subject: [PATCH 1/9] TV-01 Phase 0: the supply spec (cap as the invariant under D01, two schedule profiles in exact integers, 13 litepaper-versus-code rows, 4 BLOCKED) supply-spec.json and supply-spec.md under docs/plans/igneum-2.0-master/token-value/phase0/tv-01/; the generator (tools/token-value/tv-01/gen-spec.py, anchored to every cited line at release-2.0.2-node a284380b and release-2.0.3-node-k6 bf60948a, and equal on every field to the consensus code's own dump run on build-9); the checker (tools/token-value/tv-01/check-spec.py: four known-failed cases first, then total + shortfall = cap exactly); the registry batch tools/ci/batches/tv-01-20261009-01.json (TV-01 NOT RUN, for the CI steward). Mainnet as compiled issues 3,963,038,999.610200467816224 IGN in all, 36,961,000.39 IGN under the cap, zero from DAA 39,131,424,000. The litepaper's year-five tail-vote sentence is named superseded by D01. Documents and tests only; nothing activates. Co-Authored-By: Claude Opus 5.5 --- .../token-value/phase0/tv-01/README.md | 47 + .../token-value/phase0/tv-01/supply-spec.json | 3181 +++++++++++++++++ .../token-value/phase0/tv-01/supply-spec.md | 170 + tools/ci/batches/tv-01-20261009-01.json | 19 + tools/token-value/tv-01/check-spec.py | 250 ++ .../tv-01/code-dump/schedule-bf60948a.jsonl | 139 + .../tv-01/code-dump/tv01_schedule.rs | 60 + tools/token-value/tv-01/gen-spec.py | 573 +++ 8 files changed, 4439 insertions(+) create mode 100644 docs/plans/igneum-2.0-master/token-value/phase0/tv-01/README.md create mode 100644 docs/plans/igneum-2.0-master/token-value/phase0/tv-01/supply-spec.json create mode 100644 docs/plans/igneum-2.0-master/token-value/phase0/tv-01/supply-spec.md create mode 100644 tools/ci/batches/tv-01-20261009-01.json create mode 100644 tools/token-value/tv-01/check-spec.py create mode 100644 tools/token-value/tv-01/code-dump/schedule-bf60948a.jsonl create mode 100644 tools/token-value/tv-01/code-dump/tv01_schedule.rs create mode 100644 tools/token-value/tv-01/gen-spec.py diff --git a/docs/plans/igneum-2.0-master/token-value/phase0/tv-01/README.md b/docs/plans/igneum-2.0-master/token-value/phase0/tv-01/README.md new file mode 100644 index 000000000..1512dd89e --- /dev/null +++ b/docs/plans/igneum-2.0-master/token-value/phase0/tv-01/README.md @@ -0,0 +1,47 @@ +# TV-01, Phase 0: the supply spec + +Gate TV-01 ("Resolve and freeze the monetary contract", rules-and-gates.json sha256 `10ce307329e1663dcb6dce849317c9276c19252de5f483e9ee06015fc77cbe3d`). Verdict: **NOT RUN**. This is a document and its tests. Nothing here activates anything. + +## Files + +| File | What it is | +|---|---| +| `supply-spec.json` | the machine-readable spec: a schema block, the cap, the rules, the activation clocks, two schedule profiles (each an ordered list of phases with start DAA score, per-block subsidy integer, rule name and source line), the coinbase split, fees, supply accounting, the superseded tail-vote text, the conflicts table, and the sources by sha | +| `supply-spec.md` | the same in words, with the conflicts table, the D01 resolution and the founder's four questions | +| `../../../../../../tools/token-value/tv-01/gen-spec.py` | the generator; every figure in both files is its output | +| `../../../../../../tools/token-value/tv-01/check-spec.py` | the checker: four known-failed cases first, then the spec summed to the cap in exact integers | +| `../../../../../../tools/token-value/tv-01/code-dump/` | the consensus code's own schedule (`tv01_schedule.rs`, run on build-9 against bf60948a) and its output, `schedule-bf60948a.jsonl` (sha256 `3e4b5ac3c2f43057a13ace7d781ad714e385a94105623c0e0dac4adc417d8056`) | + +## Sources + +| Source | Revision | sha256 | +|---|---|---| +| site/litepaper.html | igneum master 6824d49cc32def4463b643293a5622545618f7a9 | `35ac65e151339089ef6ddeea3842b24d95e00d327a2b12faa9ea190ff85e463f` | +| igneum-node, release-2.0.2-node | a284380bdd62d5d0d972cb38f2cbd1daeedda69d | per file in `supply-spec.json` `sources.node.files` | +| igneum-node, release-2.0.3-node-k6 | bf60948a01467bb54eaab9e50d32b91058f11242 | the same files, byte-identical except kaspad/src/daemon.rs, whose override refusal is the same rule | +| pool/src/payout.rs, config.rs, pplns.rs | igneum master 6824d49c | in `supply-spec.json` `sources.pool` | + +## Method + +1. I read the volume's VR-01, VR-02, TV-01, TV-04 and D01, and the litepaper's supply, fee and security sections. +2. I grepped the node fork's consensus crate and execution crate for subsidy, coinbase, deflationary and emission, then read the emission table, the coinbase manager, the network objects, the genesis blocks and the EVM reward rule. +3. I transcribed the schedule constants into the generator. Each one is anchored to its line at both node revisions. +4. The generator computes both profiles in exact integers. It compares every phase, both ramps and both totals with the code dump, and they agree on every field. +5. The checker regenerates the phases from the spec's own rules, as a third implementation, and reconciles total + shortfall = cap exactly. + +## Results + +- **Mainnet as compiled (10 blocks a second)**: issuance totals 3,963,038,999.610200467816224 IGN. The shortfall under the cap is exactly 36,961,000,389,799,532,183,776,000 base units. The subsidy is zero from DAA 39,131,424,000, the start of year 125. +- **Devnet 4 profile (1 block a second)**: the same curve per second. The total differs from mainnet by 15,473,592,000 base units of per-block flooring. +- **Conflicts table**: 13 rows. Nine are resolved: C01 by D01, C12 by D01, and seven taken to the code with a text correction where one is owed. Four are BLOCKED on questions for the founder, each with a default: C04 the block rate, C08 the per-block crediting rule, C09 the mainnet genesis clock, C11 the pool's custody. + +## Commands + +``` +python3 tools/token-value/tv-01/gen-spec.py --node-git --igneum-root . \ + --igneum-rev 6824d49cc32def4463b643293a5622545618f7a9 \ + --code-dump tools/token-value/tv-01/code-dump/schedule-bf60948a.jsonl \ + --out docs/plans/igneum-2.0-master/token-value/phase0/tv-01/supply-spec.json \ + --md docs/plans/igneum-2.0-master/token-value/phase0/tv-01/supply-spec.md +python3 tools/token-value/tv-01/check-spec.py +``` diff --git a/docs/plans/igneum-2.0-master/token-value/phase0/tv-01/supply-spec.json b/docs/plans/igneum-2.0-master/token-value/phase0/tv-01/supply-spec.json new file mode 100644 index 000000000..7a4fadbd5 --- /dev/null +++ b/docs/plans/igneum-2.0-master/token-value/phase0/tv-01/supply-spec.json @@ -0,0 +1,3181 @@ +{ + "schema": { + "name": "igneum-supply-spec", + "version": "1.0.0", + "integers": "every amount is a decimal string of base units (amounts reach 4 x 10^27, past JSON's exact range); DAA scores are JSON integers (all under 2^53)", + "phase_fields": { + "index": "0-based, contiguous", + "kind": "ramp | constant | terminal", + "rule": "the rule's name", + "start_daa_score": "inclusive", + "end_daa_score": "exclusive; null for the terminal phase", + "per_block_subsidy": "base units per block at every DAA score of the phase (null for the ramp, whose per-block value is its formula)", + "phase_sum": "base units the phase issues at one subsidy per DAA score", + "source": "file:line in the node fork at both named revisions" + }, + "checker": "tools/token-value/tv-01/check-spec.py" + }, + "gate": "TV-01", + "verdict": "NOT RUN", + "status": "Phase 0 document. Activates nothing; changes no node, no chain and no served page. The verdict stays NOT RUN until the independent panel reads it.", + "decision": { + "id": "D01", + "title": "Cap and tail", + "ruling": "capped issuance, subject to TV-04 (the founder's ratification, 9 October 2026, 09:2x UK)", + "effect": "the cap is the invariant; the litepaper's year-five tail-vote sentence is superseded (C01)" + }, + "invariant": { + "rule": "sum over all blocks of the per-block subsidy <= cap, with no tail, no vote, no price or revenue trigger and no emergency mint", + "how_enforced": "by the schedule, not by a running counter: every block's coinbase must carry exactly the scheduled subsidy (coinbase.rs:262) and the EVM state credits by the same rule (executor.rs:181 to 211); the cap constant itself is only compared in tests (igneum.rs:154). The schedule sums to the cap minus the shortfall below, so the cap is never reached.", + "change_policy": "the schedule is a compiled genesis parameter on mainnet; the daemon refuses an override file there (kaspad/src/daemon.rs, network.rs:266); a change is a new release with a new consensus digest and an explicit incompatible-policy process (VR-06)" + }, + "units": { + "coin": "IGN", + "base_unit": "wei (one consensus base unit is one EVM wei)", + "decimals": 18, + "base_units_per_coin": "1000000000000000000", + "source": [ + "consensus/core/src/unit.rs:38", + "consensus/core/src/config/params.rs:1816" + ] + }, + "cap": { + "base_units": "4000000000000000000000000000", + "coins": "4000000000", + "kind": "invariant", + "source": [ + "consensus/core/src/igneum.rs:37", + "consensus/core/src/igneum.rs:154" + ] + }, + "rules": { + "launch_rate_per_second": "31688087810000000000", + "launch_rate_note": "floor(10^9 x 10^8 / 31,557,600) = 3,168,808,781 at 8 decimals, times 10^10: 31.68808781 IGN a DAA second", + "year_seconds": 31557600, + "ramp_seconds": 2592000, + "ramp_start_percent": 10, + "step_seconds": 63115200, + "step_decay_q32": 2147483648, + "decay_rule": "rate[k+1] = floor(rate[k] x step_decay_q32 / 2^32) (a halving every two years)", + "per_block": "per_block(d) = ramp(floor(rate[floor(s / step_seconds)] / bps), s), s = floor(d / bps)", + "tail": "cap", + "source": [ + "consensus/core/src/emission.rs:103 to 110", + "consensus/core/src/emission.rs:225", + "consensus/core/src/emission.rs:316 to 333", + "consensus/core/src/config/params.rs:1858" + ] + }, + "activation_clocks": { + "genesis": "DAA score 0 (C09: the compiled mainnet genesis still carries Kaspa's 1,312,860; BLOCKED)", + "ramp_end": { + "mainnet": 25920000, + "devnet-4": 2592000, + "seconds": 2592000 + }, + "halvings": "every 63,115,200 DAA seconds (2 years of 365.25 days): DAA score k x 631,152,000 at 10 blocks/s, k x 63,115,200 at 1 block/s", + "terminal": { + "mainnet": 39131424000, + "devnet-4": 4102488000 + }, + "signing_bonus": "mainnet never (params.rs:1809); testnet-1 from 0", + "pool_split": "mainnet never (params.rs:1851)", + "per_block_rule_N8": "mainnet never (params.rs:1812; C08 BLOCKED); testnet-1 from 0" + }, + "schedules": [ + { + "profile": "mainnet", + "network": "mainnet (MAINNET_PARAMS as compiled)", + "bps": 10, + "decimals": 18, + "genesis_daa_score": 0, + "time_key": "seconds = floor(daa_score / bps); the per-block subsidy is constant inside a DAA second", + "phases": [ + { + "index": 0, + "kind": "ramp", + "rule": "launch-ramp", + "start_daa_score": 0, + "end_daa_score": 25920000, + "per_block_subsidy": null, + "ramp": { + "full_per_block": "3168808781000000000", + "start_percent": 10, + "ramp_seconds": 2592000, + "first_block": "316880878100000000", + "last_block": "3168807680719173263", + "formula": "per_block(d) = floor(full_per_block x (start_percent x ramp_seconds + (100 - start_percent) x s) / (100 x ramp_seconds)), s = floor(d / bps)" + }, + "phase_sum": "45174523722296485488480000", + "source": [ + "consensus/core/src/emission.rs:316", + "consensus/core/src/emission.rs:329" + ] + }, + { + "index": 1, + "kind": "constant", + "rule": "full-rate-after-ramp", + "start_daa_score": 25920000, + "end_daa_score": 631152000, + "per_block_subsidy": "3168808781000000000", + "decay_step": 0, + "rate_per_second": "31688087810000000000", + "phase_sum": "1917864476142192000000000000", + "source": [ + "consensus/core/src/emission.rs:107", + "consensus/core/src/emission.rs:225", + "consensus/core/src/emission.rs:331" + ] + }, + { + "index": 2, + "kind": "constant", + "rule": "halving-1", + "start_daa_score": 631152000, + "end_daa_score": 1262304000, + "per_block_subsidy": "1584404390500000000", + "decay_step": 1, + "rate_per_second": "15844043905000000000", + "phase_sum": "999999999872856000000000000", + "source": [ + "consensus/core/src/emission.rs:107", + "consensus/core/src/emission.rs:225", + "consensus/core/src/emission.rs:331" + ] + }, + { + "index": 3, + "kind": "constant", + "rule": "halving-2", + "start_daa_score": 1262304000, + "end_daa_score": 1893456000, + "per_block_subsidy": "792202195250000000", + "decay_step": 2, + "rate_per_second": "7922021952500000000", + "phase_sum": "499999999936428000000000000", + "source": [ + "consensus/core/src/emission.rs:107", + "consensus/core/src/emission.rs:225", + "consensus/core/src/emission.rs:331" + ] + }, + { + "index": 4, + "kind": "constant", + "rule": "halving-3", + "start_daa_score": 1893456000, + "end_daa_score": 2524608000, + "per_block_subsidy": "396101097625000000", + "decay_step": 3, + "rate_per_second": "3961010976250000000", + "phase_sum": "249999999968214000000000000", + "source": [ + "consensus/core/src/emission.rs:107", + "consensus/core/src/emission.rs:225", + "consensus/core/src/emission.rs:331" + ] + }, + { + "index": 5, + "kind": "constant", + "rule": "halving-4", + "start_daa_score": 2524608000, + "end_daa_score": 3155760000, + "per_block_subsidy": "198050548812500000", + "decay_step": 4, + "rate_per_second": "1980505488125000000", + "phase_sum": "124999999984107000000000000", + "source": [ + "consensus/core/src/emission.rs:107", + "consensus/core/src/emission.rs:225", + "consensus/core/src/emission.rs:331" + ] + }, + { + "index": 6, + "kind": "constant", + "rule": "halving-5", + "start_daa_score": 3155760000, + "end_daa_score": 3786912000, + "per_block_subsidy": "99025274406250000", + "decay_step": 5, + "rate_per_second": "990252744062500000", + "phase_sum": "62499999992053500000000000", + "source": [ + "consensus/core/src/emission.rs:107", + "consensus/core/src/emission.rs:225", + "consensus/core/src/emission.rs:331" + ] + }, + { + "index": 7, + "kind": "constant", + "rule": "halving-6", + "start_daa_score": 3786912000, + "end_daa_score": 4418064000, + "per_block_subsidy": "49512637203125000", + "decay_step": 6, + "rate_per_second": "495126372031250000", + "phase_sum": "31249999996026750000000000", + "source": [ + "consensus/core/src/emission.rs:107", + "consensus/core/src/emission.rs:225", + "consensus/core/src/emission.rs:331" + ] + }, + { + "index": 8, + "kind": "constant", + "rule": "halving-7", + "start_daa_score": 4418064000, + "end_daa_score": 5049216000, + "per_block_subsidy": "24756318601562500", + "decay_step": 7, + "rate_per_second": "247563186015625000", + "phase_sum": "15624999998013375000000000", + "source": [ + "consensus/core/src/emission.rs:107", + "consensus/core/src/emission.rs:225", + "consensus/core/src/emission.rs:331" + ] + }, + { + "index": 9, + "kind": "constant", + "rule": "halving-8", + "start_daa_score": 5049216000, + "end_daa_score": 5680368000, + "per_block_subsidy": "12378159300781250", + "decay_step": 8, + "rate_per_second": "123781593007812500", + "phase_sum": "7812499999006687500000000", + "source": [ + "consensus/core/src/emission.rs:107", + "consensus/core/src/emission.rs:225", + "consensus/core/src/emission.rs:331" + ] + }, + { + "index": 10, + "kind": "constant", + "rule": "halving-9", + "start_daa_score": 5680368000, + "end_daa_score": 6311520000, + "per_block_subsidy": "6189079650390625", + "decay_step": 9, + "rate_per_second": "61890796503906250", + "phase_sum": "3906249999503343750000000", + "source": [ + "consensus/core/src/emission.rs:107", + "consensus/core/src/emission.rs:225", + "consensus/core/src/emission.rs:331" + ] + }, + { + "index": 11, + "kind": "constant", + "rule": "halving-10", + "start_daa_score": 6311520000, + "end_daa_score": 6942672000, + "per_block_subsidy": "3094539825195312", + "decay_step": 10, + "rate_per_second": "30945398251953125", + "phase_sum": "1953124999751671559424000", + "source": [ + "consensus/core/src/emission.rs:107", + "consensus/core/src/emission.rs:225", + "consensus/core/src/emission.rs:331" + ] + }, + { + "index": 12, + "kind": "constant", + "rule": "halving-11", + "start_daa_score": 6942672000, + "end_daa_score": 7573824000, + "per_block_subsidy": "1547269912597656", + "decay_step": 11, + "rate_per_second": "15472699125976562", + "phase_sum": "976562499875835779712000", + "source": [ + "consensus/core/src/emission.rs:107", + "consensus/core/src/emission.rs:225", + "consensus/core/src/emission.rs:331" + ] + }, + { + "index": 13, + "kind": "constant", + "rule": "halving-12", + "start_daa_score": 7573824000, + "end_daa_score": 8204976000, + "per_block_subsidy": "773634956298828", + "decay_step": 12, + "rate_per_second": "7736349562988281", + "phase_sum": "488281249937917889856000", + "source": [ + "consensus/core/src/emission.rs:107", + "consensus/core/src/emission.rs:225", + "consensus/core/src/emission.rs:331" + ] + }, + { + "index": 14, + "kind": "constant", + "rule": "halving-13", + "start_daa_score": 8204976000, + "end_daa_score": 8836128000, + "per_block_subsidy": "386817478149414", + "decay_step": 13, + "rate_per_second": "3868174781494140", + "phase_sum": "244140624968958944928000", + "source": [ + "consensus/core/src/emission.rs:107", + "consensus/core/src/emission.rs:225", + "consensus/core/src/emission.rs:331" + ] + }, + { + "index": 15, + "kind": "constant", + "rule": "halving-14", + "start_daa_score": 8836128000, + "end_daa_score": 9467280000, + "per_block_subsidy": "193408739074707", + "decay_step": 14, + "rate_per_second": "1934087390747070", + "phase_sum": "122070312484479472464000", + "source": [ + "consensus/core/src/emission.rs:107", + "consensus/core/src/emission.rs:225", + "consensus/core/src/emission.rs:331" + ] + }, + { + "index": 16, + "kind": "constant", + "rule": "halving-15", + "start_daa_score": 9467280000, + "end_daa_score": 10098432000, + "per_block_subsidy": "96704369537353", + "decay_step": 15, + "rate_per_second": "967043695373535", + "phase_sum": "61035156242239420656000", + "source": [ + "consensus/core/src/emission.rs:107", + "consensus/core/src/emission.rs:225", + "consensus/core/src/emission.rs:331" + ] + }, + { + "index": 17, + "kind": "constant", + "rule": "halving-16", + "start_daa_score": 10098432000, + "end_daa_score": 10729584000, + "per_block_subsidy": "48352184768676", + "decay_step": 16, + "rate_per_second": "483521847686767", + "phase_sum": "30517578121119394752000", + "source": [ + "consensus/core/src/emission.rs:107", + "consensus/core/src/emission.rs:225", + "consensus/core/src/emission.rs:331" + ] + }, + { + "index": 18, + "kind": "constant", + "rule": "halving-17", + "start_daa_score": 10729584000, + "end_daa_score": 11360736000, + "per_block_subsidy": "24176092384338", + "decay_step": 17, + "rate_per_second": "241760923843383", + "phase_sum": "15258789060559697376000", + "source": [ + "consensus/core/src/emission.rs:107", + "consensus/core/src/emission.rs:225", + "consensus/core/src/emission.rs:331" + ] + }, + { + "index": 19, + "kind": "constant", + "rule": "halving-18", + "start_daa_score": 11360736000, + "end_daa_score": 11991888000, + "per_block_subsidy": "12088046192169", + "decay_step": 18, + "rate_per_second": "120880461921691", + "phase_sum": "7629394530279848688000", + "source": [ + "consensus/core/src/emission.rs:107", + "consensus/core/src/emission.rs:225", + "consensus/core/src/emission.rs:331" + ] + }, + { + "index": 20, + "kind": "constant", + "rule": "halving-19", + "start_daa_score": 11991888000, + "end_daa_score": 12623040000, + "per_block_subsidy": "6044023096084", + "decay_step": 19, + "rate_per_second": "60440230960845", + "phase_sum": "3814697265139608768000", + "source": [ + "consensus/core/src/emission.rs:107", + "consensus/core/src/emission.rs:225", + "consensus/core/src/emission.rs:331" + ] + }, + { + "index": 21, + "kind": "constant", + "rule": "halving-20", + "start_daa_score": 12623040000, + "end_daa_score": 13254192000, + "per_block_subsidy": "3022011548042", + "decay_step": 20, + "rate_per_second": "30220115480422", + "phase_sum": "1907348632569804384000", + "source": [ + "consensus/core/src/emission.rs:107", + "consensus/core/src/emission.rs:225", + "consensus/core/src/emission.rs:331" + ] + }, + { + "index": 22, + "kind": "constant", + "rule": "halving-21", + "start_daa_score": 13254192000, + "end_daa_score": 13885344000, + "per_block_subsidy": "1511005774021", + "decay_step": 21, + "rate_per_second": "15110057740211", + "phase_sum": "953674316284902192000", + "source": [ + "consensus/core/src/emission.rs:107", + "consensus/core/src/emission.rs:225", + "consensus/core/src/emission.rs:331" + ] + }, + { + "index": 23, + "kind": "constant", + "rule": "halving-22", + "start_daa_score": 13885344000, + "end_daa_score": 14516496000, + "per_block_subsidy": "755502887010", + "decay_step": 22, + "rate_per_second": "7555028870105", + "phase_sum": "476837158142135520000", + "source": [ + "consensus/core/src/emission.rs:107", + "consensus/core/src/emission.rs:225", + "consensus/core/src/emission.rs:331" + ] + }, + { + "index": 24, + "kind": "constant", + "rule": "halving-23", + "start_daa_score": 14516496000, + "end_daa_score": 15147648000, + "per_block_subsidy": "377751443505", + "decay_step": 23, + "rate_per_second": "3777514435052", + "phase_sum": "238418579071067760000", + "source": [ + "consensus/core/src/emission.rs:107", + "consensus/core/src/emission.rs:225", + "consensus/core/src/emission.rs:331" + ] + }, + { + "index": 25, + "kind": "constant", + "rule": "halving-24", + "start_daa_score": 15147648000, + "end_daa_score": 15778800000, + "per_block_subsidy": "188875721752", + "decay_step": 24, + "rate_per_second": "1888757217526", + "phase_sum": "119209289535218304000", + "source": [ + "consensus/core/src/emission.rs:107", + "consensus/core/src/emission.rs:225", + "consensus/core/src/emission.rs:331" + ] + }, + { + "index": 26, + "kind": "constant", + "rule": "halving-25", + "start_daa_score": 15778800000, + "end_daa_score": 16409952000, + "per_block_subsidy": "94437860876", + "decay_step": 25, + "rate_per_second": "944378608763", + "phase_sum": "59604644767609152000", + "source": [ + "consensus/core/src/emission.rs:107", + "consensus/core/src/emission.rs:225", + "consensus/core/src/emission.rs:331" + ] + }, + { + "index": 27, + "kind": "constant", + "rule": "halving-26", + "start_daa_score": 16409952000, + "end_daa_score": 17041104000, + "per_block_subsidy": "47218930438", + "decay_step": 26, + "rate_per_second": "472189304381", + "phase_sum": "29802322383804576000", + "source": [ + "consensus/core/src/emission.rs:107", + "consensus/core/src/emission.rs:225", + "consensus/core/src/emission.rs:331" + ] + }, + { + "index": 28, + "kind": "constant", + "rule": "halving-27", + "start_daa_score": 17041104000, + "end_daa_score": 17672256000, + "per_block_subsidy": "23609465219", + "decay_step": 27, + "rate_per_second": "236094652190", + "phase_sum": "14901161191902288000", + "source": [ + "consensus/core/src/emission.rs:107", + "consensus/core/src/emission.rs:225", + "consensus/core/src/emission.rs:331" + ] + }, + { + "index": 29, + "kind": "constant", + "rule": "halving-28", + "start_daa_score": 17672256000, + "end_daa_score": 18303408000, + "per_block_subsidy": "11804732609", + "decay_step": 28, + "rate_per_second": "118047326095", + "phase_sum": "7450580595635568000", + "source": [ + "consensus/core/src/emission.rs:107", + "consensus/core/src/emission.rs:225", + "consensus/core/src/emission.rs:331" + ] + }, + { + "index": 30, + "kind": "constant", + "rule": "halving-29", + "start_daa_score": 18303408000, + "end_daa_score": 18934560000, + "per_block_subsidy": "5902366304", + "decay_step": 29, + "rate_per_second": "59023663047", + "phase_sum": "3725290297502208000", + "source": [ + "consensus/core/src/emission.rs:107", + "consensus/core/src/emission.rs:225", + "consensus/core/src/emission.rs:331" + ] + }, + { + "index": 31, + "kind": "constant", + "rule": "halving-30", + "start_daa_score": 18934560000, + "end_daa_score": 19565712000, + "per_block_subsidy": "2951183152", + "decay_step": 30, + "rate_per_second": "29511831523", + "phase_sum": "1862645148751104000", + "source": [ + "consensus/core/src/emission.rs:107", + "consensus/core/src/emission.rs:225", + "consensus/core/src/emission.rs:331" + ] + }, + { + "index": 32, + "kind": "constant", + "rule": "halving-31", + "start_daa_score": 19565712000, + "end_daa_score": 20196864000, + "per_block_subsidy": "1475591576", + "decay_step": 31, + "rate_per_second": "14755915761", + "phase_sum": "931322574375552000", + "source": [ + "consensus/core/src/emission.rs:107", + "consensus/core/src/emission.rs:225", + "consensus/core/src/emission.rs:331" + ] + }, + { + "index": 33, + "kind": "constant", + "rule": "halving-32", + "start_daa_score": 20196864000, + "end_daa_score": 20828016000, + "per_block_subsidy": "737795788", + "decay_step": 32, + "rate_per_second": "7377957880", + "phase_sum": "465661287187776000", + "source": [ + "consensus/core/src/emission.rs:107", + "consensus/core/src/emission.rs:225", + "consensus/core/src/emission.rs:331" + ] + }, + { + "index": 34, + "kind": "constant", + "rule": "halving-33", + "start_daa_score": 20828016000, + "end_daa_score": 21459168000, + "per_block_subsidy": "368897894", + "decay_step": 33, + "rate_per_second": "3688978940", + "phase_sum": "232830643593888000", + "source": [ + "consensus/core/src/emission.rs:107", + "consensus/core/src/emission.rs:225", + "consensus/core/src/emission.rs:331" + ] + }, + { + "index": 35, + "kind": "constant", + "rule": "halving-34", + "start_daa_score": 21459168000, + "end_daa_score": 22090320000, + "per_block_subsidy": "184448947", + "decay_step": 34, + "rate_per_second": "1844489470", + "phase_sum": "116415321796944000", + "source": [ + "consensus/core/src/emission.rs:107", + "consensus/core/src/emission.rs:225", + "consensus/core/src/emission.rs:331" + ] + }, + { + "index": 36, + "kind": "constant", + "rule": "halving-35", + "start_daa_score": 22090320000, + "end_daa_score": 22721472000, + "per_block_subsidy": "92224473", + "decay_step": 35, + "rate_per_second": "922244735", + "phase_sum": "58207660582896000", + "source": [ + "consensus/core/src/emission.rs:107", + "consensus/core/src/emission.rs:225", + "consensus/core/src/emission.rs:331" + ] + }, + { + "index": 37, + "kind": "constant", + "rule": "halving-36", + "start_daa_score": 22721472000, + "end_daa_score": 23352624000, + "per_block_subsidy": "46112236", + "decay_step": 36, + "rate_per_second": "461122367", + "phase_sum": "29103829975872000", + "source": [ + "consensus/core/src/emission.rs:107", + "consensus/core/src/emission.rs:225", + "consensus/core/src/emission.rs:331" + ] + }, + { + "index": 38, + "kind": "constant", + "rule": "halving-37", + "start_daa_score": 23352624000, + "end_daa_score": 23983776000, + "per_block_subsidy": "23056118", + "decay_step": 37, + "rate_per_second": "230561183", + "phase_sum": "14551914987936000", + "source": [ + "consensus/core/src/emission.rs:107", + "consensus/core/src/emission.rs:225", + "consensus/core/src/emission.rs:331" + ] + }, + { + "index": 39, + "kind": "constant", + "rule": "halving-38", + "start_daa_score": 23983776000, + "end_daa_score": 24614928000, + "per_block_subsidy": "11528059", + "decay_step": 38, + "rate_per_second": "115280591", + "phase_sum": "7275957493968000", + "source": [ + "consensus/core/src/emission.rs:107", + "consensus/core/src/emission.rs:225", + "consensus/core/src/emission.rs:331" + ] + }, + { + "index": 40, + "kind": "constant", + "rule": "halving-39", + "start_daa_score": 24614928000, + "end_daa_score": 25246080000, + "per_block_subsidy": "5764029", + "decay_step": 39, + "rate_per_second": "57640295", + "phase_sum": "3637978431408000", + "source": [ + "consensus/core/src/emission.rs:107", + "consensus/core/src/emission.rs:225", + "consensus/core/src/emission.rs:331" + ] + }, + { + "index": 41, + "kind": "constant", + "rule": "halving-40", + "start_daa_score": 25246080000, + "end_daa_score": 25877232000, + "per_block_subsidy": "2882014", + "decay_step": 40, + "rate_per_second": "28820147", + "phase_sum": "1818988900128000", + "source": [ + "consensus/core/src/emission.rs:107", + "consensus/core/src/emission.rs:225", + "consensus/core/src/emission.rs:331" + ] + }, + { + "index": 42, + "kind": "constant", + "rule": "halving-41", + "start_daa_score": 25877232000, + "end_daa_score": 26508384000, + "per_block_subsidy": "1441007", + "decay_step": 41, + "rate_per_second": "14410073", + "phase_sum": "909494450064000", + "source": [ + "consensus/core/src/emission.rs:107", + "consensus/core/src/emission.rs:225", + "consensus/core/src/emission.rs:331" + ] + }, + { + "index": 43, + "kind": "constant", + "rule": "halving-42", + "start_daa_score": 26508384000, + "end_daa_score": 27139536000, + "per_block_subsidy": "720503", + "decay_step": 42, + "rate_per_second": "7205036", + "phase_sum": "454746909456000", + "source": [ + "consensus/core/src/emission.rs:107", + "consensus/core/src/emission.rs:225", + "consensus/core/src/emission.rs:331" + ] + }, + { + "index": 44, + "kind": "constant", + "rule": "halving-43", + "start_daa_score": 27139536000, + "end_daa_score": 27770688000, + "per_block_subsidy": "360251", + "decay_step": 43, + "rate_per_second": "3602518", + "phase_sum": "227373139152000", + "source": [ + "consensus/core/src/emission.rs:107", + "consensus/core/src/emission.rs:225", + "consensus/core/src/emission.rs:331" + ] + }, + { + "index": 45, + "kind": "constant", + "rule": "halving-44", + "start_daa_score": 27770688000, + "end_daa_score": 28401840000, + "per_block_subsidy": "180125", + "decay_step": 44, + "rate_per_second": "1801259", + "phase_sum": "113686254000000", + "source": [ + "consensus/core/src/emission.rs:107", + "consensus/core/src/emission.rs:225", + "consensus/core/src/emission.rs:331" + ] + }, + { + "index": 46, + "kind": "constant", + "rule": "halving-45", + "start_daa_score": 28401840000, + "end_daa_score": 29032992000, + "per_block_subsidy": "90062", + "decay_step": 45, + "rate_per_second": "900629", + "phase_sum": "56842811424000", + "source": [ + "consensus/core/src/emission.rs:107", + "consensus/core/src/emission.rs:225", + "consensus/core/src/emission.rs:331" + ] + }, + { + "index": 47, + "kind": "constant", + "rule": "halving-46", + "start_daa_score": 29032992000, + "end_daa_score": 29664144000, + "per_block_subsidy": "45031", + "decay_step": 46, + "rate_per_second": "450314", + "phase_sum": "28421405712000", + "source": [ + "consensus/core/src/emission.rs:107", + "consensus/core/src/emission.rs:225", + "consensus/core/src/emission.rs:331" + ] + }, + { + "index": 48, + "kind": "constant", + "rule": "halving-47", + "start_daa_score": 29664144000, + "end_daa_score": 30295296000, + "per_block_subsidy": "22515", + "decay_step": 47, + "rate_per_second": "225157", + "phase_sum": "14210387280000", + "source": [ + "consensus/core/src/emission.rs:107", + "consensus/core/src/emission.rs:225", + "consensus/core/src/emission.rs:331" + ] + }, + { + "index": 49, + "kind": "constant", + "rule": "halving-48", + "start_daa_score": 30295296000, + "end_daa_score": 30926448000, + "per_block_subsidy": "11257", + "decay_step": 48, + "rate_per_second": "112578", + "phase_sum": "7104878064000", + "source": [ + "consensus/core/src/emission.rs:107", + "consensus/core/src/emission.rs:225", + "consensus/core/src/emission.rs:331" + ] + }, + { + "index": 50, + "kind": "constant", + "rule": "halving-49", + "start_daa_score": 30926448000, + "end_daa_score": 31557600000, + "per_block_subsidy": "5628", + "decay_step": 49, + "rate_per_second": "56289", + "phase_sum": "3552123456000", + "source": [ + "consensus/core/src/emission.rs:107", + "consensus/core/src/emission.rs:225", + "consensus/core/src/emission.rs:331" + ] + }, + { + "index": 51, + "kind": "constant", + "rule": "halving-50", + "start_daa_score": 31557600000, + "end_daa_score": 32188752000, + "per_block_subsidy": "2814", + "decay_step": 50, + "rate_per_second": "28144", + "phase_sum": "1776061728000", + "source": [ + "consensus/core/src/emission.rs:107", + "consensus/core/src/emission.rs:225", + "consensus/core/src/emission.rs:331" + ] + }, + { + "index": 52, + "kind": "constant", + "rule": "halving-51", + "start_daa_score": 32188752000, + "end_daa_score": 32819904000, + "per_block_subsidy": "1407", + "decay_step": 51, + "rate_per_second": "14072", + "phase_sum": "888030864000", + "source": [ + "consensus/core/src/emission.rs:107", + "consensus/core/src/emission.rs:225", + "consensus/core/src/emission.rs:331" + ] + }, + { + "index": 53, + "kind": "constant", + "rule": "halving-52", + "start_daa_score": 32819904000, + "end_daa_score": 33451056000, + "per_block_subsidy": "703", + "decay_step": 52, + "rate_per_second": "7036", + "phase_sum": "443699856000", + "source": [ + "consensus/core/src/emission.rs:107", + "consensus/core/src/emission.rs:225", + "consensus/core/src/emission.rs:331" + ] + }, + { + "index": 54, + "kind": "constant", + "rule": "halving-53", + "start_daa_score": 33451056000, + "end_daa_score": 34082208000, + "per_block_subsidy": "351", + "decay_step": 53, + "rate_per_second": "3518", + "phase_sum": "221534352000", + "source": [ + "consensus/core/src/emission.rs:107", + "consensus/core/src/emission.rs:225", + "consensus/core/src/emission.rs:331" + ] + }, + { + "index": 55, + "kind": "constant", + "rule": "halving-54", + "start_daa_score": 34082208000, + "end_daa_score": 34713360000, + "per_block_subsidy": "175", + "decay_step": 54, + "rate_per_second": "1759", + "phase_sum": "110451600000", + "source": [ + "consensus/core/src/emission.rs:107", + "consensus/core/src/emission.rs:225", + "consensus/core/src/emission.rs:331" + ] + }, + { + "index": 56, + "kind": "constant", + "rule": "halving-55", + "start_daa_score": 34713360000, + "end_daa_score": 35344512000, + "per_block_subsidy": "87", + "decay_step": 55, + "rate_per_second": "879", + "phase_sum": "54910224000", + "source": [ + "consensus/core/src/emission.rs:107", + "consensus/core/src/emission.rs:225", + "consensus/core/src/emission.rs:331" + ] + }, + { + "index": 57, + "kind": "constant", + "rule": "halving-56", + "start_daa_score": 35344512000, + "end_daa_score": 35975664000, + "per_block_subsidy": "43", + "decay_step": 56, + "rate_per_second": "439", + "phase_sum": "27139536000", + "source": [ + "consensus/core/src/emission.rs:107", + "consensus/core/src/emission.rs:225", + "consensus/core/src/emission.rs:331" + ] + }, + { + "index": 58, + "kind": "constant", + "rule": "halving-57", + "start_daa_score": 35975664000, + "end_daa_score": 36606816000, + "per_block_subsidy": "21", + "decay_step": 57, + "rate_per_second": "219", + "phase_sum": "13254192000", + "source": [ + "consensus/core/src/emission.rs:107", + "consensus/core/src/emission.rs:225", + "consensus/core/src/emission.rs:331" + ] + }, + { + "index": 59, + "kind": "constant", + "rule": "halving-58", + "start_daa_score": 36606816000, + "end_daa_score": 37237968000, + "per_block_subsidy": "10", + "decay_step": 58, + "rate_per_second": "109", + "phase_sum": "6311520000", + "source": [ + "consensus/core/src/emission.rs:107", + "consensus/core/src/emission.rs:225", + "consensus/core/src/emission.rs:331" + ] + }, + { + "index": 60, + "kind": "constant", + "rule": "halving-59", + "start_daa_score": 37237968000, + "end_daa_score": 37869120000, + "per_block_subsidy": "5", + "decay_step": 59, + "rate_per_second": "54", + "phase_sum": "3155760000", + "source": [ + "consensus/core/src/emission.rs:107", + "consensus/core/src/emission.rs:225", + "consensus/core/src/emission.rs:331" + ] + }, + { + "index": 61, + "kind": "constant", + "rule": "halving-60", + "start_daa_score": 37869120000, + "end_daa_score": 38500272000, + "per_block_subsidy": "2", + "decay_step": 60, + "rate_per_second": "27", + "phase_sum": "1262304000", + "source": [ + "consensus/core/src/emission.rs:107", + "consensus/core/src/emission.rs:225", + "consensus/core/src/emission.rs:331" + ] + }, + { + "index": 62, + "kind": "constant", + "rule": "halving-61", + "start_daa_score": 38500272000, + "end_daa_score": 39131424000, + "per_block_subsidy": "1", + "decay_step": 61, + "rate_per_second": "13", + "phase_sum": "631152000", + "source": [ + "consensus/core/src/emission.rs:107", + "consensus/core/src/emission.rs:225", + "consensus/core/src/emission.rs:331" + ] + }, + { + "index": 63, + "kind": "terminal", + "rule": "terminal-zero", + "start_daa_score": 39131424000, + "end_daa_score": null, + "per_block_subsidy": "0", + "decay_step": 62, + "rate_per_second": "6", + "phase_sum": "0", + "source": [ + "consensus/core/src/emission.rs:109", + "consensus/core/src/emission.rs:225", + "consensus/core/src/emission.rs:331" + ] + } + ], + "phase_count": 64, + "last_nonzero_phase": { + "index": 62, + "per_block_subsidy": "1", + "start_daa_score": 38500272000, + "end_daa_score": 39131424000 + }, + "terminal": { + "start_daa_score": 39131424000, + "decay_step": 62, + "start_year": 124, + "behaviour": "per-block subsidy 0 at every later DAA score; the cap is never reached; blocks are paid by fees alone" + }, + "total_issuance": "3963038999610200467816224000", + "cap_shortfall": "36961000389799532183776000", + "scheduled_supply_at_year_end": { + "1": "963038999991632485488480000", + "2": "1963038999864488485488480000", + "5": "3213038999705558485488480000", + "10": "3838038999626093485488480000", + "12": "3900538999618146985488480000", + "20": "3959132749610697141738480000", + "50": "3963038880400910946483264000", + "100": "3963038999610196921373136000" + } + }, + { + "profile": "devnet-4", + "network": "Devnet 4 (devnet4_params, 1 block a second, the litepaper's launch rate)", + "bps": 1, + "decimals": 18, + "genesis_daa_score": 0, + "time_key": "seconds = floor(daa_score / bps); the per-block subsidy is constant inside a DAA second", + "phases": [ + { + "index": 0, + "kind": "ramp", + "rule": "launch-ramp", + "start_daa_score": 0, + "end_daa_score": 2592000, + "per_block_subsidy": null, + "ramp": { + "full_per_block": "31688087810000000000", + "start_percent": 10, + "ramp_seconds": 2592000, + "first_block": "3168808781000000000", + "last_block": "31688076807191732638", + "formula": "per_block(d) = floor(full_per_block x (start_percent x ramp_seconds + (100 - start_percent) x s) / (100 x ramp_seconds)), s = floor(d / bps)" + }, + "phase_sum": "45174523722296485498848000", + "source": [ + "consensus/core/src/emission.rs:316", + "consensus/core/src/emission.rs:329" + ] + }, + { + "index": 1, + "kind": "constant", + "rule": "full-rate-after-ramp", + "start_daa_score": 2592000, + "end_daa_score": 63115200, + "per_block_subsidy": "31688087810000000000", + "decay_step": 0, + "rate_per_second": "31688087810000000000", + "phase_sum": "1917864476142192000000000000", + "source": [ + "consensus/core/src/emission.rs:107", + "consensus/core/src/emission.rs:225", + "consensus/core/src/emission.rs:331" + ] + }, + { + "index": 2, + "kind": "constant", + "rule": "halving-1", + "start_daa_score": 63115200, + "end_daa_score": 126230400, + "per_block_subsidy": "15844043905000000000", + "decay_step": 1, + "rate_per_second": "15844043905000000000", + "phase_sum": "999999999872856000000000000", + "source": [ + "consensus/core/src/emission.rs:107", + "consensus/core/src/emission.rs:225", + "consensus/core/src/emission.rs:331" + ] + }, + { + "index": 3, + "kind": "constant", + "rule": "halving-2", + "start_daa_score": 126230400, + "end_daa_score": 189345600, + "per_block_subsidy": "7922021952500000000", + "decay_step": 2, + "rate_per_second": "7922021952500000000", + "phase_sum": "499999999936428000000000000", + "source": [ + "consensus/core/src/emission.rs:107", + "consensus/core/src/emission.rs:225", + "consensus/core/src/emission.rs:331" + ] + }, + { + "index": 4, + "kind": "constant", + "rule": "halving-3", + "start_daa_score": 189345600, + "end_daa_score": 252460800, + "per_block_subsidy": "3961010976250000000", + "decay_step": 3, + "rate_per_second": "3961010976250000000", + "phase_sum": "249999999968214000000000000", + "source": [ + "consensus/core/src/emission.rs:107", + "consensus/core/src/emission.rs:225", + "consensus/core/src/emission.rs:331" + ] + }, + { + "index": 5, + "kind": "constant", + "rule": "halving-4", + "start_daa_score": 252460800, + "end_daa_score": 315576000, + "per_block_subsidy": "1980505488125000000", + "decay_step": 4, + "rate_per_second": "1980505488125000000", + "phase_sum": "124999999984107000000000000", + "source": [ + "consensus/core/src/emission.rs:107", + "consensus/core/src/emission.rs:225", + "consensus/core/src/emission.rs:331" + ] + }, + { + "index": 6, + "kind": "constant", + "rule": "halving-5", + "start_daa_score": 315576000, + "end_daa_score": 378691200, + "per_block_subsidy": "990252744062500000", + "decay_step": 5, + "rate_per_second": "990252744062500000", + "phase_sum": "62499999992053500000000000", + "source": [ + "consensus/core/src/emission.rs:107", + "consensus/core/src/emission.rs:225", + "consensus/core/src/emission.rs:331" + ] + }, + { + "index": 7, + "kind": "constant", + "rule": "halving-6", + "start_daa_score": 378691200, + "end_daa_score": 441806400, + "per_block_subsidy": "495126372031250000", + "decay_step": 6, + "rate_per_second": "495126372031250000", + "phase_sum": "31249999996026750000000000", + "source": [ + "consensus/core/src/emission.rs:107", + "consensus/core/src/emission.rs:225", + "consensus/core/src/emission.rs:331" + ] + }, + { + "index": 8, + "kind": "constant", + "rule": "halving-7", + "start_daa_score": 441806400, + "end_daa_score": 504921600, + "per_block_subsidy": "247563186015625000", + "decay_step": 7, + "rate_per_second": "247563186015625000", + "phase_sum": "15624999998013375000000000", + "source": [ + "consensus/core/src/emission.rs:107", + "consensus/core/src/emission.rs:225", + "consensus/core/src/emission.rs:331" + ] + }, + { + "index": 9, + "kind": "constant", + "rule": "halving-8", + "start_daa_score": 504921600, + "end_daa_score": 568036800, + "per_block_subsidy": "123781593007812500", + "decay_step": 8, + "rate_per_second": "123781593007812500", + "phase_sum": "7812499999006687500000000", + "source": [ + "consensus/core/src/emission.rs:107", + "consensus/core/src/emission.rs:225", + "consensus/core/src/emission.rs:331" + ] + }, + { + "index": 10, + "kind": "constant", + "rule": "halving-9", + "start_daa_score": 568036800, + "end_daa_score": 631152000, + "per_block_subsidy": "61890796503906250", + "decay_step": 9, + "rate_per_second": "61890796503906250", + "phase_sum": "3906249999503343750000000", + "source": [ + "consensus/core/src/emission.rs:107", + "consensus/core/src/emission.rs:225", + "consensus/core/src/emission.rs:331" + ] + }, + { + "index": 11, + "kind": "constant", + "rule": "halving-10", + "start_daa_score": 631152000, + "end_daa_score": 694267200, + "per_block_subsidy": "30945398251953125", + "decay_step": 10, + "rate_per_second": "30945398251953125", + "phase_sum": "1953124999751671875000000", + "source": [ + "consensus/core/src/emission.rs:107", + "consensus/core/src/emission.rs:225", + "consensus/core/src/emission.rs:331" + ] + }, + { + "index": 12, + "kind": "constant", + "rule": "halving-11", + "start_daa_score": 694267200, + "end_daa_score": 757382400, + "per_block_subsidy": "15472699125976562", + "decay_step": 11, + "rate_per_second": "15472699125976562", + "phase_sum": "976562499875835905942400", + "source": [ + "consensus/core/src/emission.rs:107", + "consensus/core/src/emission.rs:225", + "consensus/core/src/emission.rs:331" + ] + }, + { + "index": 13, + "kind": "constant", + "rule": "halving-12", + "start_daa_score": 757382400, + "end_daa_score": 820497600, + "per_block_subsidy": "7736349562988281", + "decay_step": 12, + "rate_per_second": "7736349562988281", + "phase_sum": "488281249937917952971200", + "source": [ + "consensus/core/src/emission.rs:107", + "consensus/core/src/emission.rs:225", + "consensus/core/src/emission.rs:331" + ] + }, + { + "index": 14, + "kind": "constant", + "rule": "halving-13", + "start_daa_score": 820497600, + "end_daa_score": 883612800, + "per_block_subsidy": "3868174781494140", + "decay_step": 13, + "rate_per_second": "3868174781494140", + "phase_sum": "244140624968958944928000", + "source": [ + "consensus/core/src/emission.rs:107", + "consensus/core/src/emission.rs:225", + "consensus/core/src/emission.rs:331" + ] + }, + { + "index": 15, + "kind": "constant", + "rule": "halving-14", + "start_daa_score": 883612800, + "end_daa_score": 946728000, + "per_block_subsidy": "1934087390747070", + "decay_step": 14, + "rate_per_second": "1934087390747070", + "phase_sum": "122070312484479472464000", + "source": [ + "consensus/core/src/emission.rs:107", + "consensus/core/src/emission.rs:225", + "consensus/core/src/emission.rs:331" + ] + }, + { + "index": 16, + "kind": "constant", + "rule": "halving-15", + "start_daa_score": 946728000, + "end_daa_score": 1009843200, + "per_block_subsidy": "967043695373535", + "decay_step": 15, + "rate_per_second": "967043695373535", + "phase_sum": "61035156242239736232000", + "source": [ + "consensus/core/src/emission.rs:107", + "consensus/core/src/emission.rs:225", + "consensus/core/src/emission.rs:331" + ] + }, + { + "index": 17, + "kind": "constant", + "rule": "halving-16", + "start_daa_score": 1009843200, + "end_daa_score": 1072958400, + "per_block_subsidy": "483521847686767", + "decay_step": 16, + "rate_per_second": "483521847686767", + "phase_sum": "30517578121119836558400", + "source": [ + "consensus/core/src/emission.rs:107", + "consensus/core/src/emission.rs:225", + "consensus/core/src/emission.rs:331" + ] + }, + { + "index": 18, + "kind": "constant", + "rule": "halving-17", + "start_daa_score": 1072958400, + "end_daa_score": 1136073600, + "per_block_subsidy": "241760923843383", + "decay_step": 17, + "rate_per_second": "241760923843383", + "phase_sum": "15258789060559886721600", + "source": [ + "consensus/core/src/emission.rs:107", + "consensus/core/src/emission.rs:225", + "consensus/core/src/emission.rs:331" + ] + }, + { + "index": 19, + "kind": "constant", + "rule": "halving-18", + "start_daa_score": 1136073600, + "end_daa_score": 1199188800, + "per_block_subsidy": "120880461921691", + "decay_step": 18, + "rate_per_second": "120880461921691", + "phase_sum": "7629394530279911803200", + "source": [ + "consensus/core/src/emission.rs:107", + "consensus/core/src/emission.rs:225", + "consensus/core/src/emission.rs:331" + ] + }, + { + "index": 20, + "kind": "constant", + "rule": "halving-19", + "start_daa_score": 1199188800, + "end_daa_score": 1262304000, + "per_block_subsidy": "60440230960845", + "decay_step": 19, + "rate_per_second": "60440230960845", + "phase_sum": "3814697265139924344000", + "source": [ + "consensus/core/src/emission.rs:107", + "consensus/core/src/emission.rs:225", + "consensus/core/src/emission.rs:331" + ] + }, + { + "index": 21, + "kind": "constant", + "rule": "halving-20", + "start_daa_score": 1262304000, + "end_daa_score": 1325419200, + "per_block_subsidy": "30220115480422", + "decay_step": 20, + "rate_per_second": "30220115480422", + "phase_sum": "1907348632569930614400", + "source": [ + "consensus/core/src/emission.rs:107", + "consensus/core/src/emission.rs:225", + "consensus/core/src/emission.rs:331" + ] + }, + { + "index": 22, + "kind": "constant", + "rule": "halving-21", + "start_daa_score": 1325419200, + "end_daa_score": 1388534400, + "per_block_subsidy": "15110057740211", + "decay_step": 21, + "rate_per_second": "15110057740211", + "phase_sum": "953674316284965307200", + "source": [ + "consensus/core/src/emission.rs:107", + "consensus/core/src/emission.rs:225", + "consensus/core/src/emission.rs:331" + ] + }, + { + "index": 23, + "kind": "constant", + "rule": "halving-22", + "start_daa_score": 1388534400, + "end_daa_score": 1451649600, + "per_block_subsidy": "7555028870105", + "decay_step": 22, + "rate_per_second": "7555028870105", + "phase_sum": "476837158142451096000", + "source": [ + "consensus/core/src/emission.rs:107", + "consensus/core/src/emission.rs:225", + "consensus/core/src/emission.rs:331" + ] + }, + { + "index": 24, + "kind": "constant", + "rule": "halving-23", + "start_daa_score": 1451649600, + "end_daa_score": 1514764800, + "per_block_subsidy": "3777514435052", + "decay_step": 23, + "rate_per_second": "3777514435052", + "phase_sum": "238418579071193990400", + "source": [ + "consensus/core/src/emission.rs:107", + "consensus/core/src/emission.rs:225", + "consensus/core/src/emission.rs:331" + ] + }, + { + "index": 25, + "kind": "constant", + "rule": "halving-24", + "start_daa_score": 1514764800, + "end_daa_score": 1577880000, + "per_block_subsidy": "1888757217526", + "decay_step": 24, + "rate_per_second": "1888757217526", + "phase_sum": "119209289535596995200", + "source": [ + "consensus/core/src/emission.rs:107", + "consensus/core/src/emission.rs:225", + "consensus/core/src/emission.rs:331" + ] + }, + { + "index": 26, + "kind": "constant", + "rule": "halving-25", + "start_daa_score": 1577880000, + "end_daa_score": 1640995200, + "per_block_subsidy": "944378608763", + "decay_step": 25, + "rate_per_second": "944378608763", + "phase_sum": "59604644767798497600", + "source": [ + "consensus/core/src/emission.rs:107", + "consensus/core/src/emission.rs:225", + "consensus/core/src/emission.rs:331" + ] + }, + { + "index": 27, + "kind": "constant", + "rule": "halving-26", + "start_daa_score": 1640995200, + "end_daa_score": 1704110400, + "per_block_subsidy": "472189304381", + "decay_step": 26, + "rate_per_second": "472189304381", + "phase_sum": "29802322383867691200", + "source": [ + "consensus/core/src/emission.rs:107", + "consensus/core/src/emission.rs:225", + "consensus/core/src/emission.rs:331" + ] + }, + { + "index": 28, + "kind": "constant", + "rule": "halving-27", + "start_daa_score": 1704110400, + "end_daa_score": 1767225600, + "per_block_subsidy": "236094652190", + "decay_step": 27, + "rate_per_second": "236094652190", + "phase_sum": "14901161191902288000", + "source": [ + "consensus/core/src/emission.rs:107", + "consensus/core/src/emission.rs:225", + "consensus/core/src/emission.rs:331" + ] + }, + { + "index": 29, + "kind": "constant", + "rule": "halving-28", + "start_daa_score": 1767225600, + "end_daa_score": 1830340800, + "per_block_subsidy": "118047326095", + "decay_step": 28, + "rate_per_second": "118047326095", + "phase_sum": "7450580595951144000", + "source": [ + "consensus/core/src/emission.rs:107", + "consensus/core/src/emission.rs:225", + "consensus/core/src/emission.rs:331" + ] + }, + { + "index": 30, + "kind": "constant", + "rule": "halving-29", + "start_daa_score": 1830340800, + "end_daa_score": 1893456000, + "per_block_subsidy": "59023663047", + "decay_step": 29, + "rate_per_second": "59023663047", + "phase_sum": "3725290297944014400", + "source": [ + "consensus/core/src/emission.rs:107", + "consensus/core/src/emission.rs:225", + "consensus/core/src/emission.rs:331" + ] + }, + { + "index": 31, + "kind": "constant", + "rule": "halving-30", + "start_daa_score": 1893456000, + "end_daa_score": 1956571200, + "per_block_subsidy": "29511831523", + "decay_step": 30, + "rate_per_second": "29511831523", + "phase_sum": "1862645148940449600", + "source": [ + "consensus/core/src/emission.rs:107", + "consensus/core/src/emission.rs:225", + "consensus/core/src/emission.rs:331" + ] + }, + { + "index": 32, + "kind": "constant", + "rule": "halving-31", + "start_daa_score": 1956571200, + "end_daa_score": 2019686400, + "per_block_subsidy": "14755915761", + "decay_step": 31, + "rate_per_second": "14755915761", + "phase_sum": "931322574438667200", + "source": [ + "consensus/core/src/emission.rs:107", + "consensus/core/src/emission.rs:225", + "consensus/core/src/emission.rs:331" + ] + }, + { + "index": 33, + "kind": "constant", + "rule": "halving-32", + "start_daa_score": 2019686400, + "end_daa_score": 2082801600, + "per_block_subsidy": "7377957880", + "decay_step": 32, + "rate_per_second": "7377957880", + "phase_sum": "465661287187776000", + "source": [ + "consensus/core/src/emission.rs:107", + "consensus/core/src/emission.rs:225", + "consensus/core/src/emission.rs:331" + ] + }, + { + "index": 34, + "kind": "constant", + "rule": "halving-33", + "start_daa_score": 2082801600, + "end_daa_score": 2145916800, + "per_block_subsidy": "3688978940", + "decay_step": 33, + "rate_per_second": "3688978940", + "phase_sum": "232830643593888000", + "source": [ + "consensus/core/src/emission.rs:107", + "consensus/core/src/emission.rs:225", + "consensus/core/src/emission.rs:331" + ] + }, + { + "index": 35, + "kind": "constant", + "rule": "halving-34", + "start_daa_score": 2145916800, + "end_daa_score": 2209032000, + "per_block_subsidy": "1844489470", + "decay_step": 34, + "rate_per_second": "1844489470", + "phase_sum": "116415321796944000", + "source": [ + "consensus/core/src/emission.rs:107", + "consensus/core/src/emission.rs:225", + "consensus/core/src/emission.rs:331" + ] + }, + { + "index": 36, + "kind": "constant", + "rule": "halving-35", + "start_daa_score": 2209032000, + "end_daa_score": 2272147200, + "per_block_subsidy": "922244735", + "decay_step": 35, + "rate_per_second": "922244735", + "phase_sum": "58207660898472000", + "source": [ + "consensus/core/src/emission.rs:107", + "consensus/core/src/emission.rs:225", + "consensus/core/src/emission.rs:331" + ] + }, + { + "index": 37, + "kind": "constant", + "rule": "halving-36", + "start_daa_score": 2272147200, + "end_daa_score": 2335262400, + "per_block_subsidy": "461122367", + "decay_step": 36, + "rate_per_second": "461122367", + "phase_sum": "29103830417678400", + "source": [ + "consensus/core/src/emission.rs:107", + "consensus/core/src/emission.rs:225", + "consensus/core/src/emission.rs:331" + ] + }, + { + "index": 38, + "kind": "constant", + "rule": "halving-37", + "start_daa_score": 2335262400, + "end_daa_score": 2398377600, + "per_block_subsidy": "230561183", + "decay_step": 37, + "rate_per_second": "230561183", + "phase_sum": "14551915177281600", + "source": [ + "consensus/core/src/emission.rs:107", + "consensus/core/src/emission.rs:225", + "consensus/core/src/emission.rs:331" + ] + }, + { + "index": 39, + "kind": "constant", + "rule": "halving-38", + "start_daa_score": 2398377600, + "end_daa_score": 2461492800, + "per_block_subsidy": "115280591", + "decay_step": 38, + "rate_per_second": "115280591", + "phase_sum": "7275957557083200", + "source": [ + "consensus/core/src/emission.rs:107", + "consensus/core/src/emission.rs:225", + "consensus/core/src/emission.rs:331" + ] + }, + { + "index": 40, + "kind": "constant", + "rule": "halving-39", + "start_daa_score": 2461492800, + "end_daa_score": 2524608000, + "per_block_subsidy": "57640295", + "decay_step": 39, + "rate_per_second": "57640295", + "phase_sum": "3637978746984000", + "source": [ + "consensus/core/src/emission.rs:107", + "consensus/core/src/emission.rs:225", + "consensus/core/src/emission.rs:331" + ] + }, + { + "index": 41, + "kind": "constant", + "rule": "halving-40", + "start_daa_score": 2524608000, + "end_daa_score": 2587723200, + "per_block_subsidy": "28820147", + "decay_step": 40, + "rate_per_second": "28820147", + "phase_sum": "1818989341934400", + "source": [ + "consensus/core/src/emission.rs:107", + "consensus/core/src/emission.rs:225", + "consensus/core/src/emission.rs:331" + ] + }, + { + "index": 42, + "kind": "constant", + "rule": "halving-41", + "start_daa_score": 2587723200, + "end_daa_score": 2650838400, + "per_block_subsidy": "14410073", + "decay_step": 41, + "rate_per_second": "14410073", + "phase_sum": "909494639409600", + "source": [ + "consensus/core/src/emission.rs:107", + "consensus/core/src/emission.rs:225", + "consensus/core/src/emission.rs:331" + ] + }, + { + "index": 43, + "kind": "constant", + "rule": "halving-42", + "start_daa_score": 2650838400, + "end_daa_score": 2713953600, + "per_block_subsidy": "7205036", + "decay_step": 42, + "rate_per_second": "7205036", + "phase_sum": "454747288147200", + "source": [ + "consensus/core/src/emission.rs:107", + "consensus/core/src/emission.rs:225", + "consensus/core/src/emission.rs:331" + ] + }, + { + "index": 44, + "kind": "constant", + "rule": "halving-43", + "start_daa_score": 2713953600, + "end_daa_score": 2777068800, + "per_block_subsidy": "3602518", + "decay_step": 43, + "rate_per_second": "3602518", + "phase_sum": "227373644073600", + "source": [ + "consensus/core/src/emission.rs:107", + "consensus/core/src/emission.rs:225", + "consensus/core/src/emission.rs:331" + ] + }, + { + "index": 45, + "kind": "constant", + "rule": "halving-44", + "start_daa_score": 2777068800, + "end_daa_score": 2840184000, + "per_block_subsidy": "1801259", + "decay_step": 44, + "rate_per_second": "1801259", + "phase_sum": "113686822036800", + "source": [ + "consensus/core/src/emission.rs:107", + "consensus/core/src/emission.rs:225", + "consensus/core/src/emission.rs:331" + ] + }, + { + "index": 46, + "kind": "constant", + "rule": "halving-45", + "start_daa_score": 2840184000, + "end_daa_score": 2903299200, + "per_block_subsidy": "900629", + "decay_step": 45, + "rate_per_second": "900629", + "phase_sum": "56843379460800", + "source": [ + "consensus/core/src/emission.rs:107", + "consensus/core/src/emission.rs:225", + "consensus/core/src/emission.rs:331" + ] + }, + { + "index": 47, + "kind": "constant", + "rule": "halving-46", + "start_daa_score": 2903299200, + "end_daa_score": 2966414400, + "per_block_subsidy": "450314", + "decay_step": 46, + "rate_per_second": "450314", + "phase_sum": "28421658172800", + "source": [ + "consensus/core/src/emission.rs:107", + "consensus/core/src/emission.rs:225", + "consensus/core/src/emission.rs:331" + ] + }, + { + "index": 48, + "kind": "constant", + "rule": "halving-47", + "start_daa_score": 2966414400, + "end_daa_score": 3029529600, + "per_block_subsidy": "225157", + "decay_step": 47, + "rate_per_second": "225157", + "phase_sum": "14210829086400", + "source": [ + "consensus/core/src/emission.rs:107", + "consensus/core/src/emission.rs:225", + "consensus/core/src/emission.rs:331" + ] + }, + { + "index": 49, + "kind": "constant", + "rule": "halving-48", + "start_daa_score": 3029529600, + "end_daa_score": 3092644800, + "per_block_subsidy": "112578", + "decay_step": 48, + "rate_per_second": "112578", + "phase_sum": "7105382985600", + "source": [ + "consensus/core/src/emission.rs:107", + "consensus/core/src/emission.rs:225", + "consensus/core/src/emission.rs:331" + ] + }, + { + "index": 50, + "kind": "constant", + "rule": "halving-49", + "start_daa_score": 3092644800, + "end_daa_score": 3155760000, + "per_block_subsidy": "56289", + "decay_step": 49, + "rate_per_second": "56289", + "phase_sum": "3552691492800", + "source": [ + "consensus/core/src/emission.rs:107", + "consensus/core/src/emission.rs:225", + "consensus/core/src/emission.rs:331" + ] + }, + { + "index": 51, + "kind": "constant", + "rule": "halving-50", + "start_daa_score": 3155760000, + "end_daa_score": 3218875200, + "per_block_subsidy": "28144", + "decay_step": 50, + "rate_per_second": "28144", + "phase_sum": "1776314188800", + "source": [ + "consensus/core/src/emission.rs:107", + "consensus/core/src/emission.rs:225", + "consensus/core/src/emission.rs:331" + ] + }, + { + "index": 52, + "kind": "constant", + "rule": "halving-51", + "start_daa_score": 3218875200, + "end_daa_score": 3281990400, + "per_block_subsidy": "14072", + "decay_step": 51, + "rate_per_second": "14072", + "phase_sum": "888157094400", + "source": [ + "consensus/core/src/emission.rs:107", + "consensus/core/src/emission.rs:225", + "consensus/core/src/emission.rs:331" + ] + }, + { + "index": 53, + "kind": "constant", + "rule": "halving-52", + "start_daa_score": 3281990400, + "end_daa_score": 3345105600, + "per_block_subsidy": "7036", + "decay_step": 52, + "rate_per_second": "7036", + "phase_sum": "444078547200", + "source": [ + "consensus/core/src/emission.rs:107", + "consensus/core/src/emission.rs:225", + "consensus/core/src/emission.rs:331" + ] + }, + { + "index": 54, + "kind": "constant", + "rule": "halving-53", + "start_daa_score": 3345105600, + "end_daa_score": 3408220800, + "per_block_subsidy": "3518", + "decay_step": 53, + "rate_per_second": "3518", + "phase_sum": "222039273600", + "source": [ + "consensus/core/src/emission.rs:107", + "consensus/core/src/emission.rs:225", + "consensus/core/src/emission.rs:331" + ] + }, + { + "index": 55, + "kind": "constant", + "rule": "halving-54", + "start_daa_score": 3408220800, + "end_daa_score": 3471336000, + "per_block_subsidy": "1759", + "decay_step": 54, + "rate_per_second": "1759", + "phase_sum": "111019636800", + "source": [ + "consensus/core/src/emission.rs:107", + "consensus/core/src/emission.rs:225", + "consensus/core/src/emission.rs:331" + ] + }, + { + "index": 56, + "kind": "constant", + "rule": "halving-55", + "start_daa_score": 3471336000, + "end_daa_score": 3534451200, + "per_block_subsidy": "879", + "decay_step": 55, + "rate_per_second": "879", + "phase_sum": "55478260800", + "source": [ + "consensus/core/src/emission.rs:107", + "consensus/core/src/emission.rs:225", + "consensus/core/src/emission.rs:331" + ] + }, + { + "index": 57, + "kind": "constant", + "rule": "halving-56", + "start_daa_score": 3534451200, + "end_daa_score": 3597566400, + "per_block_subsidy": "439", + "decay_step": 56, + "rate_per_second": "439", + "phase_sum": "27707572800", + "source": [ + "consensus/core/src/emission.rs:107", + "consensus/core/src/emission.rs:225", + "consensus/core/src/emission.rs:331" + ] + }, + { + "index": 58, + "kind": "constant", + "rule": "halving-57", + "start_daa_score": 3597566400, + "end_daa_score": 3660681600, + "per_block_subsidy": "219", + "decay_step": 57, + "rate_per_second": "219", + "phase_sum": "13822228800", + "source": [ + "consensus/core/src/emission.rs:107", + "consensus/core/src/emission.rs:225", + "consensus/core/src/emission.rs:331" + ] + }, + { + "index": 59, + "kind": "constant", + "rule": "halving-58", + "start_daa_score": 3660681600, + "end_daa_score": 3723796800, + "per_block_subsidy": "109", + "decay_step": 58, + "rate_per_second": "109", + "phase_sum": "6879556800", + "source": [ + "consensus/core/src/emission.rs:107", + "consensus/core/src/emission.rs:225", + "consensus/core/src/emission.rs:331" + ] + }, + { + "index": 60, + "kind": "constant", + "rule": "halving-59", + "start_daa_score": 3723796800, + "end_daa_score": 3786912000, + "per_block_subsidy": "54", + "decay_step": 59, + "rate_per_second": "54", + "phase_sum": "3408220800", + "source": [ + "consensus/core/src/emission.rs:107", + "consensus/core/src/emission.rs:225", + "consensus/core/src/emission.rs:331" + ] + }, + { + "index": 61, + "kind": "constant", + "rule": "halving-60", + "start_daa_score": 3786912000, + "end_daa_score": 3850027200, + "per_block_subsidy": "27", + "decay_step": 60, + "rate_per_second": "27", + "phase_sum": "1704110400", + "source": [ + "consensus/core/src/emission.rs:107", + "consensus/core/src/emission.rs:225", + "consensus/core/src/emission.rs:331" + ] + }, + { + "index": 62, + "kind": "constant", + "rule": "halving-61", + "start_daa_score": 3850027200, + "end_daa_score": 3913142400, + "per_block_subsidy": "13", + "decay_step": 61, + "rate_per_second": "13", + "phase_sum": "820497600", + "source": [ + "consensus/core/src/emission.rs:107", + "consensus/core/src/emission.rs:225", + "consensus/core/src/emission.rs:331" + ] + }, + { + "index": 63, + "kind": "constant", + "rule": "halving-62", + "start_daa_score": 3913142400, + "end_daa_score": 3976257600, + "per_block_subsidy": "6", + "decay_step": 62, + "rate_per_second": "6", + "phase_sum": "378691200", + "source": [ + "consensus/core/src/emission.rs:107", + "consensus/core/src/emission.rs:225", + "consensus/core/src/emission.rs:331" + ] + }, + { + "index": 64, + "kind": "constant", + "rule": "halving-63", + "start_daa_score": 3976257600, + "end_daa_score": 4039372800, + "per_block_subsidy": "3", + "decay_step": 63, + "rate_per_second": "3", + "phase_sum": "189345600", + "source": [ + "consensus/core/src/emission.rs:107", + "consensus/core/src/emission.rs:225", + "consensus/core/src/emission.rs:331" + ] + }, + { + "index": 65, + "kind": "constant", + "rule": "halving-64", + "start_daa_score": 4039372800, + "end_daa_score": 4102488000, + "per_block_subsidy": "1", + "decay_step": 64, + "rate_per_second": "1", + "phase_sum": "63115200", + "source": [ + "consensus/core/src/emission.rs:107", + "consensus/core/src/emission.rs:225", + "consensus/core/src/emission.rs:331" + ] + }, + { + "index": 66, + "kind": "terminal", + "rule": "terminal-zero", + "start_daa_score": 4102488000, + "end_daa_score": null, + "per_block_subsidy": "0", + "decay_step": 65, + "rate_per_second": "0", + "phase_sum": "0", + "source": [ + "consensus/core/src/emission.rs:109", + "consensus/core/src/emission.rs:225", + "consensus/core/src/emission.rs:331" + ] + } + ], + "phase_count": 67, + "last_nonzero_phase": { + "index": 65, + "per_block_subsidy": "1", + "start_daa_score": 4039372800, + "end_daa_score": 4102488000 + }, + "terminal": { + "start_daa_score": 4102488000, + "decay_step": 65, + "start_year": 130, + "behaviour": "per-block subsidy 0 at every later DAA score; the cap is never reached; blocks are paid by fees alone" + }, + "total_issuance": "3963038999610200483289816000", + "cap_shortfall": "36961000389799516710184000", + "scheduled_supply_at_year_end": { + "1": "963038999991632485498848000", + "2": "1963038999864488485498848000", + "5": "3213038999705558485498848000", + "10": "3838038999626093485498848000", + "12": "3900538999618146985498848000", + "20": "3959132749610697141748848000", + "50": "3963038880400910949333816000", + "100": "3963038999610196931229475200" + } + } + ], + "coinbase_split": [ + { + "rule": "producer and proving pool", + "producer": "subsidy - floor(subsidy x 20 / 100)", + "proving_pool": "floor(subsidy x 20 / 100)", + "source": [ + "consensus/core/src/igneum.rs:44", + "consensus/core/src/igneum.rs:201 to 208" + ] + }, + { + "rule": "signing bonus", + "effect": "a silent producer's share loses floor(share x 1,000 / 10,000) to the proving pool; nothing destroyed; fees untouched", + "mainnet": "off (never)", + "source": [ + "consensus/core/src/igneum.rs:110", + "consensus/core/src/config/params.rs:1809 to 1810" + ] + }, + { + "rule": "native ledger", + "effect": "the EVM state credits the producer share to the block's IGNA address (or by its IGNW split once pool_split is active) and the pool share to escrow 0x0000000000000000000000000000000000000220, blue blocks only", + "source": [ + "igneum/exec/src/executor.rs:181 to 211", + "igneum/exec/src/config.rs:59" + ] + }, + { + "rule": "shadow ledger", + "effect": "the UTXO coinbase pays the producer outputs and one OP_RETURN pool output tagged igneum-proving-pool-v0; no UTXO transaction but the coinbase is valid, so none of it is ever spent", + "source": [ + "consensus/src/processes/coinbase.rs:126 to 168", + "consensus/src/pipeline/body_processor/body_validation_in_isolation.rs:54" + ] + }, + { + "rule": "pool", + "effect": "none in consensus; the reference pool keeps fee_percent (default 1.0) of the 80% it receives and pays members PPLNS from its address", + "source": [ + "pool/src/payout.rs:1 to 6", + "pool/src/config.rs:58", + "pool/src/pplns.rs:76" + ] + }, + { + "rule": "dev fee", + "effect": "none in consensus; the miner software requests 1 template in 100 with the dev address (off with --dev-fee 0); it moves the producer share of those blocks, creates nothing", + "source": [ + "site/litepaper.html:625" + ] + }, + { + "rule": "treasury, foundation, team, stake", + "effect": "none: no output, credit or address in consensus", + "source": [ + "consensus/src/processes/coinbase.rs:126 to 168", + "igneum/exec/src/executor.rs:181 to 211" + ] + }, + { + "rule": "genesis", + "effect": "the genesis coinbase has no outputs; its payload subsidy field is data; no premine", + "source": [ + "consensus/core/src/config/genesis.rs:26" + ] + } + ], + "fees": [ + { + "route": "execution base fee", + "effect": "burned (not credited)", + "source": "igneum/exec/src/executor.rs:319 to 321" + }, + { + "route": "proving charge", + "effect": "burned", + "source": "igneum/exec/src/executor.rs:319 to 321" + }, + { + "route": "priority fee", + "effect": "80% to the block's miner; 20% to the payees registered for the frames' code by own gas, unregistered parts burned", + "source": "igneum/exec/src/executor.rs:362 to 371; igneum/exec/src/pgas.rs:290" + }, + { + "route": "external job after the proof bridge", + "effect": "not in code (Designed, phase two): 90% provers, 10% burned per the litepaper", + "source": "site/litepaper.html:624" + } + ], + "supply_accounting": { + "issued": "the EVM state's subsidy credits (producer plus escrow), blue blocks only; bounded above by the schedule's per-DAA-score sum", + "burned": "execution base fees, proving charges and unregistered developer shares (EVM side); the UTXO OP_RETURN output is NOT counted as a burn (C06)", + "locked": "the proving escrow's balance: credited, not yet paid against a valid proof; unclaimed credit is stranded today (litepaper line 609, no rule returns it)", + "not_supply": "UTXO coinbase outputs (unspendable shadow record); any bridged or wrapped IGN on another chain (VR-02)", + "replay_model": "one scheduled subsidy per DAA score (the schedules above); a block is paid at its own DAA score, parallel blocks may share a score and a score may have no block, so the measured issuance differs from the model only near phase boundaries and only by the blocks merged across them; TV-02 reconciles the measured ledgers to this model in exact integers" + }, + "superseded": [ + { + "text": "One rule sits beside the cap. If external proving revenue is under one fifth of the block subsidy over any 90-day window after year 5, the question of a tail reward goes to the miners' signalling vote. The protocol never changes emission by itself.", + "where": "site/litepaper.html:630", + "by": "D01 (capped issuance, subject to TV-04)", + "status": "SUPERSEDED" + } + ], + "conflicts": [ + { + "id": "C01", + "topic": "cap versus the year-five tail vote", + "litepaper": { + "line": 630, + "words": "One rule sits beside the cap. If external proving revenue is under one fifth of the block subsidy over any 90-day window after year 5, the question of a tail reward goes to the miners' signalling vote. The protocol never changes emission by itself." + }, + "code": { + "where": "consensus/core/src/emission.rs:109 (Tail::Cap in EmissionSchedule::CURRENT); consensus/core/src/config/params.rs:1858 (mainnet carries CURRENT); kaspad/src/daemon.rs (params_compiled refuses an override file on mainnet and testnet); no signal path reads or writes the emission schedule", + "value": "tail = cap; the schedule is a compiled genesis parameter; no vote, no revenue trigger, no tail" + }, + "spec_takes": "the cap as the invariant; the tail-vote sentence is SUPERSEDED", + "why": "D01 (capped issuance, subject to TV-04), ratified by the founder 9 October 2026 09:2x UK; VR-01 (no unexplained tail escape, no price- or revenue-triggered issuance); the code already enforces only the capped schedule. If TV-04 shows capped security cannot pass, the volume's rule applies: delay launch or openly choose another design, never an undisclosed tail.", + "status": "RESOLVED (by D01, subject to TV-04)", + "follow_up": "the litepaper sentence is removed or replaced by the site lane; this landing does not edit site/" + }, + { + "id": "C02", + "topic": "year-one emission and the twelve-year figure", + "litepaper": { + "line": 578, + "words": "emission starts at 1 billion a year", + "line_2": 602, + "words_2": "3,938M IGN in the first 12 years of a 4,000M cap." + }, + "code": { + "where": "consensus/core/src/emission.rs:104 to 106 (launch rate floored, the 30-day ramp from 10%)", + "value": "year 1 issues 963,038,999.99163248548848 IGN at 10 blocks/s (963,038,999.991632485498848 at 1 block/s); the first 12 years issue 3,900,538,999.61814698548848 IGN" + }, + "spec_takes": "the code's figures", + "why": "the litepaper chart and caption ignore the launch ramp's withheld 36,961,000 IGN and the floor of the per-second rate; the spec carries what nodes pay", + "status": "RESOLVED (text correction owed by the site lane)" + }, + { + "id": "C03", + "topic": "terminal behaviour", + "litepaper": { + "line": 578, + "words": "halves every two years for ever" + }, + "code": { + "where": "consensus/core/src/emission.rs:225 (rate[k+1] = rate[k] x 2^31 >> 32, floored), :331 (per block = rate / bps, floored)", + "value": "the per-block subsidy floors to zero at decay step 62 (DAA score 39,131,424,000, the start of year 125) at 10 blocks/s and at step 65 (DAA score 4,102,488,000, the start of year 131) at 1 block/s; zero for ever after" + }, + "spec_takes": "the code: a finite schedule ending in a terminal zero phase", + "why": "integer halving ends; the last subsidy is 1 base unit (10^-18 IGN) per block; after it the security budget is fees alone (TV-04's question)", + "status": "RESOLVED (text correction owed: 'until the subsidy floors to zero')" + }, + { + "id": "C04", + "topic": "block rate at launch and its steps", + "litepaper": { + "line": 542, + "words": "one block a second at launch with scheduled steps to four and ten", + "line_2": 668, + "words_2": "31.688 IGN a block, 86,400 blocks a day" + }, + "code": { + "where": "consensus/core/src/config/params.rs:1789 (mainnet BlockrateParams::new::<10>()); consensus/src/processes/coinbase.rs:31 (the bps_history rescaling is gone) and :265 (subsidy keyed on daa / ONE bps)", + "value": "mainnet as compiled runs 10 blocks/s from genesis, 3.1688087810 IGN a block; the subsidy has no block-rate history, so a step from 1 to 10 blocks/s at DAA score 31,557,600 (one year in) would issue 4,863,038,999.495770867826592 IGN in all, an overshoot of 863,038,999.495770867826592 IGN over the cap" + }, + "spec_takes": "both profiles (10 blocks/s as compiled; 1 block/s as Devnet 4), identical per second; NO live block-rate step is cap-safe under the current code", + "why": "a block-rate step re-keys the schedule clock (seconds = daa / bps) and re-pays elapsed time", + "status": "BLOCKED", + "question": "For the founder: does mainnet launch at the compiled 10 blocks a second (the litepaper's 1-to-4-to-10 step plan removed), or at 1 with steps (then the node lane adds a block-rate-history subsidy rule before genesis, and TV-02 replays a step)? Default if unanswered: the spec freezes the compiled 10 blocks a second and the step plan is treated as text to correct." + }, + { + "id": "C05", + "topic": "unit", + "litepaper": { + "line": 568, + "words": "the base unit is Open" + }, + "code": { + "where": "consensus/core/src/unit.rs:38; consensus/core/src/config/params.rs:1816", + "value": "18 decimals on mainnet, testnet and Devnet 4: 1 IGN = 10^18 base units; one base unit is one EVM wei" + }, + "spec_takes": "18 decimals", + "why": "decided 6 October 2026 (O-2.6) and compiled; the cap is 4 x 10^27 base units", + "status": "RESOLVED (text correction owed)" + }, + { + "id": "C06", + "topic": "where the 20% proving share goes, and which ledger is native supply", + "litepaper": { + "line": 609, + "words": "the coinbase's 20% output goes to an unspendable script tagged igneum-proving-pool-v0 and is burned there. Provers are paid from a separate escrow in the execution state" + }, + "code": { + "where": "consensus/src/processes/coinbase.rs:163 (UTXO pool output to the OP_RETURN script); consensus/src/pipeline/body_processor/body_validation_in_isolation.rs:54 (no UTXO transaction but the coinbase: UTXO outputs can never be spent); igneum/exec/src/executor.rs:181 to 211 (the EVM state credits 80% to the producer and 20% to the escrow 0x...0220 for every blue block)", + "value": "two ledgers record each subsidy: the UTXO coinbase (unspendable by rule) and the EVM state (spendable)" + }, + "spec_takes": "native supply is the EVM state's credit; the UTXO coinbase is a non-spendable shadow record and its OP_RETURN 20% is NOT a burn of native supply; the escrow balance is issued and locked until paid per proof", + "why": "counting both ledgers doubles supply; counting the OP_RETURN as burned and the escrow as issued would understate and overstate at once (VR-02)", + "status": "RESOLVED (for the spec; TV-02 reconciles both ledgers to this rule)" + }, + { + "id": "C07", + "topic": "red blocks", + "litepaper": { + "line": 620, + "words": "80% the block's miner, 20% the proving pool for the provers of that block" + }, + "code": { + "where": "consensus/src/processes/coinbase.rs:152 to 159 (the UTXO coinbase pays a DAA red block's subsidy to the merging miner and the pool); igneum/exec/src/executor.rs:181 (the EVM credits blue blocks only)", + "value": "a red block's subsidy exists on the shadow ledger and not in native supply" + }, + "spec_takes": "native issuance = the blue blocks' subsidies; the per-DAA-score schedule sum is the upper bound", + "why": "the EVM ledger is native supply (C06); the bound keeps the cap invariant whatever the red share", + "status": "RESOLVED (TV-02 measures the red share; no text change needed beyond 'blue block')" + }, + { + "id": "C08", + "topic": "which DAA score a merged block is credited at", + "litepaper": { + "line": null, + "words": "(silent)" + }, + "code": { + "where": "consensus/core/src/config/params.rs:1812 (mainnet subsidy_per_block_activation_daa = never), :2232 (Devnet 4 inherits never), :1960 (testnet-1: 0)", + "value": "on mainnet and Devnet 4 the EVM credits a merged block the merging chain block's subsidy while the UTXO coinbase pays the block's own: one ramp second high per merged block, a whole halving step at a boundary" + }, + "spec_takes": "each block's own DAA score (ledger N8) as the normative rule", + "why": "exact integer agreement between ledgers and replays (TV-02) needs one rule; N8 is the one the testnet object already carries", + "status": "BLOCKED", + "question": "For the founder (the node lane owns the change): set subsidy_per_block_activation_daa = 0 in the mainnet object, as testnet-1 has it? Default if unanswered: the spec keeps N8 as normative and TV-02 reports the chain-block reading as a measured divergence." + }, + { + "id": "C09", + "topic": "the mainnet genesis clock", + "litepaper": { + "line": 775, + "words": "Genesis with no premine, 30-day ramp." + }, + "code": { + "where": "consensus/core/src/config/genesis.rs:92 (mainnet GENESIS daa_score 1312860, Kaspa's 2021 timestamp); the subsidy reads the absolute DAA score (emission.rs:329)", + "value": "as compiled, the first mainnet block would sit 131,286 DAA seconds into the ramp (paying 14.55% of full rate, not 10%) and the whole schedule would run 1.52 days early; issuance would be 510,841.7849105123888436 IGN lower" + }, + "spec_takes": "genesis at DAA score 0 (as Devnet 4 and testnet-1); the activation clocks below are counted from it", + "why": "the mainnet genesis is a Kaspa placeholder not yet cut; every Igneum network so far starts at DAA score 0", + "status": "BLOCKED", + "question": "For the founder: confirm the mainnet genesis is cut at DAA score 0. Default if unanswered: the spec freezes DAA score 0 and the genesis cut is checked against it." + }, + { + "id": "C10", + "topic": "priority fee to provers", + "litepaper": { + "line": 622, + "words": "80% the block's miner and provers; 20% the apps whose code ran, per call frame" + }, + "code": { + "where": "igneum/exec/src/executor.rs:362 to 371 (the tip less the developer share is credited to the block's miner alone); igneum/exec/src/pgas.rs:290 (20% developer share, unregistered parts burned)", + "value": "80% to the block's miner, none to provers; 20% to registered payees or burned" + }, + "spec_takes": "the code", + "why": "fees move existing supply and burn some; they never create supply", + "status": "RESOLVED (text correction owed: drop 'and provers')" + }, + { + "id": "C11", + "topic": "the reference pool's custody and fee", + "litepaper": { + "line": 647, + "words": "The reference pool never holds a member’s balance. Payouts come straight from the coinbase split" + }, + "code": { + "where": "pool/src/payout.rs:1 to 6 (the pool's address receives the 80% and pays members by transfers); pool/src/config.rs:58 (fee_percent 1.0); pool/src/pplns.rs:76; consensus/core/src/config/params.rs:1851 (mainnet pool_split_activation_daa = never: the IGNW coinbase split is off)", + "value": "the reference pool holds members' balances between rounds and keeps a 1% fee; the consensus split that would make the sentence true is off on mainnet and Devnet 4" + }, + "spec_takes": "the code (custodial PPLNS, 1% default fee, no supply effect)", + "why": "the payout route moves issued supply; it creates none", + "status": "BLOCKED", + "question": "For the founder: activate the IGNW coinbase split at mainnet genesis (pool_split_activation_daa = 0) so the litepaper sentence holds, or change the sentence to the custodial PPLNS pool with its 1% fee? Default if unanswered: the sentence is corrected to the code." + }, + { + "id": "C12", + "topic": "a tail schedule compiled into testnet-1", + "litepaper": { + "line": 630, + "words": "The cap stays at 4 billion. There is no tail emission." + }, + "code": { + "where": "consensus/core/src/emission.rs:116 to 122 (TESTNET_1: 100 IGN a block, monthly glide, a 1% a year tail); consensus/core/src/config/params.rs:2014 (testnet-1 carries it)", + "value": "the held testnet-1 object issues without a cap" + }, + "spec_takes": "not the monetary contract: the contract is EmissionSchedule::CURRENT with Tail::Cap", + "why": "D01; the testnet is held and superseded by 2.0; a revived testnet carries CURRENT or is labelled a different supply proposition", + "status": "RESOLVED (by D01)" + }, + { + "id": "C13", + "topic": "dead Kaspa subsidy fields in the mainnet object", + "litepaper": { + "line": null, + "words": "(silent)" + }, + "code": { + "where": "consensus/core/src/config/params.rs:1783 to 1784 (deflationary_phase_daa_score 15,519,600; pre_deflationary_phase_base_subsidy 50,000,000,000)", + "value": "read only into the consensus digest; the subsidy never reads them (coinbase.rs:31)" + }, + "spec_takes": "ignored: they are not part of the monetary contract", + "why": "a reader grepping 'deflationary' would otherwise find a second schedule that does not exist", + "status": "RESOLVED (the node lane may annotate or remove them at the genesis cut)" + } + ], + "sources": { + "volume": { + "path": "docs/plans/igneum-2.0-master/token-value/rules-and-gates.json", + "sha256": "10ce307329e1663dcb6dce849317c9276c19252de5f483e9ee06015fc77cbe3d" + }, + "litepaper": { + "path": "site/litepaper.html", + "igneum_commit": "6824d49cc32def4463b643293a5622545618f7a9", + "sha256": "35ac65e151339089ef6ddeea3842b24d95e00d327a2b12faa9ea190ff85e463f" + }, + "node": { + "repo": "igneum-node (build-1:/srv/igneum-node.git)", + "revisions": { + "release-2.0.2-node": "a284380bdd62d5d0d972cb38f2cbd1daeedda69d", + "release-2.0.3-node-k6": "bf60948a01467bb54eaab9e50d32b91058f11242" + }, + "files": { + "consensus/core/src/config/genesis.rs": { + "release-2.0.2-node": "967618cf3e54987b42993f6ed5c9221bfae6b10db0959c08f8bf24f3aa6eb627", + "release-2.0.3-node-k6": "967618cf3e54987b42993f6ed5c9221bfae6b10db0959c08f8bf24f3aa6eb627" + }, + "consensus/core/src/config/params.rs": { + "release-2.0.2-node": "0c07ddcf0c5383255f1b0cfba54c6f637375b9a5b5514ab4b2affdad717e787f", + "release-2.0.3-node-k6": "0c07ddcf0c5383255f1b0cfba54c6f637375b9a5b5514ab4b2affdad717e787f" + }, + "consensus/core/src/emission.rs": { + "release-2.0.2-node": "07b39c410222a43001c83dddbd85cff4a8a370184588dbc28ab48c8803964fbd", + "release-2.0.3-node-k6": "07b39c410222a43001c83dddbd85cff4a8a370184588dbc28ab48c8803964fbd" + }, + "consensus/core/src/igneum.rs": { + "release-2.0.2-node": "6c859d4268e653978bfa07aaaad2dff304635b892255368cbbadecca3c35705f", + "release-2.0.3-node-k6": "6c859d4268e653978bfa07aaaad2dff304635b892255368cbbadecca3c35705f" + }, + "consensus/core/src/network.rs": { + "release-2.0.2-node": "6b7a7a1148429888650e6b1059262d0dac86017bfe906e95a943201205290c85", + "release-2.0.3-node-k6": "6b7a7a1148429888650e6b1059262d0dac86017bfe906e95a943201205290c85" + }, + "consensus/core/src/unit.rs": { + "release-2.0.2-node": "d64d6d6f973e25b778c1eb558db41fad36a1457871a290cc01df0797a47b4d4f", + "release-2.0.3-node-k6": "d64d6d6f973e25b778c1eb558db41fad36a1457871a290cc01df0797a47b4d4f" + }, + "consensus/src/pipeline/body_processor/body_validation_in_isolation.rs": { + "release-2.0.2-node": "3a639e259840c5238400f4c5ed1df9dcf44368288b501f0a905f63f563678d54", + "release-2.0.3-node-k6": "3a639e259840c5238400f4c5ed1df9dcf44368288b501f0a905f63f563678d54" + }, + "consensus/src/processes/coinbase.rs": { + "release-2.0.2-node": "ef25b2412507d608df08fd22895e74262489f1fa460e6fe26f89877fb5cc6c63", + "release-2.0.3-node-k6": "ef25b2412507d608df08fd22895e74262489f1fa460e6fe26f89877fb5cc6c63" + }, + "igneum/exec/src/config.rs": { + "release-2.0.2-node": "fdc4ba56109ddab4dadfe3d184247cf2cda8774dc5542337acaa38c8da716aaf", + "release-2.0.3-node-k6": "fdc4ba56109ddab4dadfe3d184247cf2cda8774dc5542337acaa38c8da716aaf" + }, + "igneum/exec/src/executor.rs": { + "release-2.0.2-node": "ff12ef5fed88f1cd1d1449c6878a5acc0f7efe098abad7315791d59b5c5cc79c", + "release-2.0.3-node-k6": "ff12ef5fed88f1cd1d1449c6878a5acc0f7efe098abad7315791d59b5c5cc79c" + }, + "igneum/exec/src/pgas.rs": { + "release-2.0.2-node": "0b7dd5080f8a60c77eaab5579797350ac916fc38fa4ce78fcc8618aa7c617c00", + "release-2.0.3-node-k6": "0b7dd5080f8a60c77eaab5579797350ac916fc38fa4ce78fcc8618aa7c617c00" + }, + "kaspad/src/daemon.rs": { + "release-2.0.2-node": "ffa0b97f2ebc9c537380059e7fee511c95406c4333bdf55e80f360241b136ae4", + "release-2.0.3-node-k6": "68c1e5aec8eb7be0fc22da348d1e7ee9dcebb5c4db9ef43434030151fa3e1008" + } + }, + "note": "every cited node file is byte-identical at both revisions except kaspad/src/daemon.rs, whose override refusal is the same rule at both" + }, + "pool": { + "pool/src/config.rs": "0001c219ba629c388eaf916b8d5d4c4da0a854eff6048b27758cab734e797b1d", + "pool/src/payout.rs": "839619378b7e9b0b7eda22ce900aa2ada6410aa90e3d7f1f000a02f0b8449c1f", + "pool/src/pplns.rs": "fa1f6f5627374f1b8ba06238a30e30beacb35bf505a21f2cf7f4bb3539485942" + }, + "citations": [ + { + "id": "year", + "repo": "node", + "path": "consensus/core/src/emission.rs", + "line": 32, + "anchor": "pub const YEAR_SECONDS: u64 = 31_557_600;" + }, + { + "id": "current", + "repo": "node", + "path": "consensus/core/src/emission.rs", + "line": 103, + "anchor": "pub const CURRENT: EmissionSchedule" + }, + { + "id": "launch_rate", + "repo": "node", + "path": "consensus/core/src/emission.rs", + "line": 104, + "anchor": "launch_rate: 3_168_808_781" + }, + { + "id": "ramp_seconds", + "repo": "node", + "path": "consensus/core/src/emission.rs", + "line": 105, + "anchor": "ramp_seconds: 2_592_000" + }, + { + "id": "ramp_start", + "repo": "node", + "path": "consensus/core/src/emission.rs", + "line": 106, + "anchor": "ramp_start_percent: 10" + }, + { + "id": "step_seconds", + "repo": "node", + "path": "consensus/core/src/emission.rs", + "line": 107, + "anchor": "step_seconds: 2 * YEAR_SECONDS" + }, + { + "id": "decay", + "repo": "node", + "path": "consensus/core/src/emission.rs", + "line": 108, + "anchor": "step_decay_q32: 1 << 31" + }, + { + "id": "tail_cap", + "repo": "node", + "path": "consensus/core/src/emission.rs", + "line": 109, + "anchor": "tail: Tail::Cap" + }, + { + "id": "testnet1", + "repo": "node", + "path": "consensus/core/src/emission.rs", + "line": 116, + "anchor": "pub const TESTNET_1: EmissionSchedule" + }, + { + "id": "testnet1_tail", + "repo": "node", + "path": "consensus/core/src/emission.rs", + "line": 122, + "anchor": "tail: Tail::Percent { bps_per_year: 100 }" + }, + { + "id": "decay_rule", + "repo": "node", + "path": "consensus/core/src/emission.rs", + "line": 225, + "anchor": "rate = rate.saturating_mul(s.step_decay_q32 as u128) >> 32;" + }, + { + "id": "ramp_fn", + "repo": "node", + "path": "consensus/core/src/emission.rs", + "line": 316, + "anchor": "pub fn ramp(&self, full: u128, seconds: u64) -> u128" + }, + { + "id": "block_subsidy", + "repo": "node", + "path": "consensus/core/src/emission.rs", + "line": 329, + "anchor": "pub fn block_subsidy(&self, daa_score: u64, bps: u64) -> u128" + }, + { + "id": "per_block_div", + "repo": "node", + "path": "consensus/core/src/emission.rs", + "line": 331, + "anchor": "let per_block = self.rate_at(seconds) / bps as u128;" + }, + { + "id": "cap_const", + "repo": "node", + "path": "consensus/core/src/igneum.rs", + "line": 37, + "anchor": "pub const SUPPLY_CAP_SOMPI: u64 = 4_000_000_000 * SOMPI_PER_KASPA;" + }, + { + "id": "pool_share", + "repo": "node", + "path": "consensus/core/src/igneum.rs", + "line": 44, + "anchor": "pub const PROVING_POOL_SHARE_PERCENT: u64 = 20;" + }, + { + "id": "silent_split", + "repo": "node", + "path": "consensus/core/src/igneum.rs", + "line": 110, + "anchor": "pub fn silent_split_units(" + }, + { + "id": "cap_units", + "repo": "node", + "path": "consensus/core/src/igneum.rs", + "line": 154, + "anchor": "pub const fn supply_cap_units(decimals: u8) -> u128" + }, + { + "id": "pool_units", + "repo": "node", + "path": "consensus/core/src/igneum.rs", + "line": 201, + "anchor": "pub fn proving_pool_share_units(" + }, + { + "id": "producer_units", + "repo": "node", + "path": "consensus/core/src/igneum.rs", + "line": 206, + "anchor": "pub fn producer_share_units(" + }, + { + "id": "pool_script", + "repo": "node", + "path": "consensus/core/src/igneum.rs", + "line": 213, + "anchor": "pub fn proving_pool_script_public_key()" + }, + { + "id": "evm_decimals", + "repo": "node", + "path": "consensus/core/src/unit.rs", + "line": 38, + "anchor": "pub const EVM_DECIMALS: u8 = 18;" + }, + { + "id": "mainnet_deflationary", + "repo": "node", + "path": "consensus/core/src/config/params.rs", + "line": 1783, + "anchor": "deflationary_phase_daa_score: 15778800 - 259200," + }, + { + "id": "mainnet_pre_deflationary", + "repo": "node", + "path": "consensus/core/src/config/params.rs", + "line": 1784, + "anchor": "pre_deflationary_phase_base_subsidy: 50000000000," + }, + { + "id": "mainnet_bps", + "repo": "node", + "path": "consensus/core/src/config/params.rs", + "line": 1789, + "anchor": "blockrate: BlockrateParams::new::<10>()," + }, + { + "id": "mainnet_bonus_off", + "repo": "node", + "path": "consensus/core/src/config/params.rs", + "line": 1809, + "anchor": "signing_bonus_activation_daa: u64::MAX," + }, + { + "id": "mainnet_bonus_bps", + "repo": "node", + "path": "consensus/core/src/config/params.rs", + "line": 1810, + "anchor": "signing_bonus_bps: 1_000," + }, + { + "id": "mainnet_n8_off", + "repo": "node", + "path": "consensus/core/src/config/params.rs", + "line": 1812, + "anchor": "subsidy_per_block_activation_daa: u64::MAX," + }, + { + "id": "mainnet_decimals", + "repo": "node", + "path": "consensus/core/src/config/params.rs", + "line": 1816, + "anchor": "base_unit_decimals: crate::unit::EVM_DECIMALS" + }, + { + "id": "mainnet_pool_split_off", + "repo": "node", + "path": "consensus/core/src/config/params.rs", + "line": 1851, + "anchor": "pool_split_activation_daa: u64::MAX," + }, + { + "id": "mainnet_emission", + "repo": "node", + "path": "consensus/core/src/config/params.rs", + "line": 1858, + "anchor": "emission: EmissionSchedule::CURRENT.rescaled(crate::unit::DEVNET_DECIMALS, crate::unit::EVM_DECIMALS)," + }, + { + "id": "testnet_bonus_on", + "repo": "node", + "path": "consensus/core/src/config/params.rs", + "line": 1955, + "anchor": "signing_bonus_activation_daa: 0," + }, + { + "id": "testnet_n8_on", + "repo": "node", + "path": "consensus/core/src/config/params.rs", + "line": 1960, + "anchor": "subsidy_per_block_activation_daa: 0," + }, + { + "id": "testnet_emission", + "repo": "node", + "path": "consensus/core/src/config/params.rs", + "line": 2014, + "anchor": "emission: EmissionSchedule::TESTNET_1.rescaled(" + }, + { + "id": "devnet_bps", + "repo": "node", + "path": "consensus/core/src/config/params.rs", + "line": 2208, + "anchor": "blockrate: BlockrateParams::new::<1>()," + }, + { + "id": "devnet_n8_off", + "repo": "node", + "path": "consensus/core/src/config/params.rs", + "line": 2232, + "anchor": "subsidy_per_block_activation_daa: u64::MAX," + }, + { + "id": "devnet_pool_split_off", + "repo": "node", + "path": "consensus/core/src/config/params.rs", + "line": 2270, + "anchor": "pool_split_activation_daa: u64::MAX," + }, + { + "id": "devnet4_fn", + "repo": "node", + "path": "consensus/core/src/config/params.rs", + "line": 2342, + "anchor": "pub fn devnet4_params() -> Params {" + }, + { + "id": "devnet4_emission", + "repo": "node", + "path": "consensus/core/src/config/params.rs", + "line": 2372, + "anchor": "emission: EmissionSchedule::CURRENT.rescaled(crate::unit::DEVNET_DECIMALS, crate::unit::EVM_DECIMALS)," + }, + { + "id": "mainnet_genesis_daa", + "repo": "node", + "path": "consensus/core/src/config/genesis.rs", + "line": 92, + "anchor": "daa_score: 1312860, // Checkpoint DAA score" + }, + { + "id": "genesis_no_outputs", + "repo": "node", + "path": "consensus/core/src/config/genesis.rs", + "line": 26, + "anchor": "Transaction::new(0, Vec::new(), Vec::new(), 0, SUBNETWORK_ID_COINBASE" + }, + { + "id": "cb_header", + "repo": "node", + "path": "consensus/src/processes/coinbase.rs", + "line": 31, + "anchor": "Kaspa's pre-deflationary phase, 426-month table and Crescendo `bps_history` rescaling are gone." + }, + { + "id": "cb_split", + "repo": "node", + "path": "consensus/src/processes/coinbase.rs", + "line": 106, + "anchor": "fn producer_and_pool(&self, daa_score: u64, reward: &BlockRewardData)" + }, + { + "id": "cb_reds", + "repo": "node", + "path": "consensus/src/processes/coinbase.rs", + "line": 152, + "anchor": "for red in ghostdag_data.mergeset_reds.iter()" + }, + { + "id": "cb_pool_output", + "repo": "node", + "path": "consensus/src/processes/coinbase.rs", + "line": 163, + "anchor": "outputs.push(TransactionOutput::new_units(proving_pool_reward, igneum::proving_pool_script_public_key()));" + }, + { + "id": "cb_calc", + "repo": "node", + "path": "consensus/src/processes/coinbase.rs", + "line": 262, + "anchor": "pub fn calc_block_subsidy(&self, daa_score: u64) -> Amount" + }, + { + "id": "cb_calc_body", + "repo": "node", + "path": "consensus/src/processes/coinbase.rs", + "line": 265, + "anchor": "Amount(self.emission.block_subsidy(daa_score, self.bps))" + }, + { + "id": "utxo_retired", + "repo": "node", + "path": "consensus/src/pipeline/body_processor/body_validation_in_isolation.rs", + "line": 54, + "anchor": "RuleError::UtxoTransactionsRetired" + }, + { + "id": "exec_blue_only", + "repo": "node", + "path": "igneum/exec/src/executor.rs", + "line": 181, + "anchor": "for b in blocks.iter().filter(|b| b.is_blue)" + }, + { + "id": "exec_split", + "repo": "node", + "path": "igneum/exec/src/executor.rs", + "line": 189, + "anchor": "silent_split_units(subsidy, b.silent, env.signing_bonus_bps)" + }, + { + "id": "exec_miner_credit", + "repo": "node", + "path": "igneum/exec/src/executor.rs", + "line": 208, + "anchor": "db.add_balance(b.miner, producer_wei);" + }, + { + "id": "exec_pool_credit", + "repo": "node", + "path": "igneum/exec/src/executor.rs", + "line": 211, + "anchor": "db.add_balance(PROVING_POOL_ADDRESS, pool_wei);" + }, + { + "id": "exec_tip_miner", + "repo": "node", + "path": "igneum/exec/src/executor.rs", + "line": 362, + "anchor": "let tip_total = (gas_used as u128) * (price - env.base_fee_exec);" + }, + { + "id": "exec_dev_shares", + "repo": "node", + "path": "igneum/exec/src/pgas.rs", + "line": 290, + "anchor": "pub fn developer_shares(" + }, + { + "id": "pool_address", + "repo": "node", + "path": "igneum/exec/src/config.rs", + "line": 59, + "anchor": "pub const PROVING_POOL_ADDRESS: Address" + }, + { + "id": "override_refused", + "repo": "node", + "path": "kaspad/src/daemon.rs", + "line": { + "release-2.0.2-node": 320, + "release-2.0.3-node-k6": 323 + }, + "anchor": "if network.params_compiled() {" + }, + { + "id": "params_compiled", + "repo": "node", + "path": "consensus/core/src/network.rs", + "line": 266, + "anchor": "NetworkType::Mainnet | NetworkType::Testnet => true," + }, + { + "id": "lp_cap", + "repo": "igneum", + "path": "site/litepaper.html", + "line": 578, + "anchor": "Hard cap of 4 billion IGN, approached and never reached, because emission starts at 1 billion a year and halves every two years for ever." + }, + { + "id": "lp_caption", + "repo": "igneum", + "path": "site/litepaper.html", + "line": 602, + "anchor": "3,938M IGN in the first 12 years of a 4,000M cap." + }, + { + "id": "lp_proving_pool", + "repo": "igneum", + "path": "site/litepaper.html", + "line": 609, + "anchor": "is burned there" + }, + { + "id": "lp_tail", + "repo": "igneum", + "path": "site/litepaper.html", + "line": 630, + "anchor": "One rule sits beside the cap. If external proving revenue is under one fifth of the block subsidy over any 90-day window after year 5, the question of a tail reward goes to the miners' signalling vote. The protocol never changes emission by itself." + }, + { + "id": "lp_no_tail", + "repo": "igneum", + "path": "site/litepaper.html", + "line": 630, + "anchor": "The cap stays at 4 billion. There is no tail emission." + }, + { + "id": "lp_block_rate", + "repo": "igneum", + "path": "site/litepaper.html", + "line": 542, + "anchor": "one block a second at launch with scheduled steps to four and ten" + }, + { + "id": "lp_unit", + "repo": "igneum", + "path": "site/litepaper.html", + "line": 568, + "anchor": "the base unit is Open" + }, + { + "id": "lp_emission_route", + "repo": "igneum", + "path": "site/litepaper.html", + "line": 620, + "anchor": "80% the block's miner, 20% the proving pool for the provers of that block" + }, + { + "id": "lp_tip_route", + "repo": "igneum", + "path": "site/litepaper.html", + "line": 622, + "anchor": "80% the block's miner and provers; 20% the apps whose code ran, per call frame" + }, + { + "id": "lp_external_job", + "repo": "igneum", + "path": "site/litepaper.html", + "line": 624, + "anchor": "90% the provers who delivered" + }, + { + "id": "lp_dev_fee", + "repo": "igneum", + "path": "site/litepaper.html", + "line": 625, + "anchor": "1 block template in 100 requested with the dev address" + }, + { + "id": "lp_pool_custody", + "repo": "igneum", + "path": "site/litepaper.html", + "line": 647, + "anchor": "The reference pool never holds a member" + }, + { + "id": "lp_per_block_figure", + "repo": "igneum", + "path": "site/litepaper.html", + "line": 668, + "anchor": "31.688 IGN a block, 86,400 blocks a day" + }, + { + "id": "lp_mainnet_launch", + "repo": "igneum", + "path": "site/litepaper.html", + "line": 775, + "anchor": "Genesis with no premine, 30-day ramp." + }, + { + "id": "pool_payout_doc", + "repo": "igneum", + "path": "pool/src/payout.rs", + "line": 3, + "anchor": "so the pool receives" + }, + { + "id": "pool_fee_default", + "repo": "igneum", + "path": "pool/src/config.rs", + "line": 58, + "anchor": "fee_percent: 1.0," + }, + { + "id": "pool_distribute", + "repo": "igneum", + "path": "pool/src/pplns.rs", + "line": 76, + "anchor": "pub fn distribute(reward_wei: u128, fee_percent: f64, payees: &[Payee])" + } + ], + "code_dump": { + "path": "tools/token-value/tv-01/code-dump/schedule-bf60948a.jsonl", + "sha256": "3e4b5ac3c2f43057a13ace7d781ad714e385a94105623c0e0dac4adc417d8056", + "program": "tools/token-value/tv-01/code-dump/tv01_schedule.rs", + "run": "build-9, release-2.0.3-node-k6 bf60948a: cargo run --release -p kaspa-consensus-core --example tv01_schedule (the program copied into consensus/core/examples of a scratch tree; the node fork is unchanged)", + "agreement": "every field of 129 decay phases, both ramps and both totals equal to this generator's integers" + } + }, + "generator": { + "path": "tools/token-value/tv-01/gen-spec.py", + "command": "python3 tools/token-value/tv-01/gen-spec.py --node-git --igneum-root . --igneum-rev 6824d49cc32def4463b643293a5622545618f7a9 --code-dump tools/token-value/tv-01/code-dump/schedule-bf60948a.jsonl --out docs/plans/igneum-2.0-master/token-value/phase0/tv-01/supply-spec.json --md docs/plans/igneum-2.0-master/token-value/phase0/tv-01/supply-spec.md" + } +} diff --git a/docs/plans/igneum-2.0-master/token-value/phase0/tv-01/supply-spec.md b/docs/plans/igneum-2.0-master/token-value/phase0/tv-01/supply-spec.md new file mode 100644 index 000000000..bc691b8cb --- /dev/null +++ b/docs/plans/igneum-2.0-master/token-value/phase0/tv-01/supply-spec.md @@ -0,0 +1,170 @@ +# TV-01: the monetary contract as one supply spec + +Igneum 2.0, Token Value Phase 0, item TV-01. 9 October 2026. + +Gate TV-01: **NOT RUN**. This is a Phase 0 document. It activates nothing and changes no node, chain or served page. The verdict stays NOT RUN until the independent panel reads it. Four rows are BLOCKED on questions for the founder (C04, C08, C09, C11), each with a default. + +The machine-readable spec is `supply-spec.json` in this directory. This page says the same in words. Every figure on it comes from `tools/token-value/tv-01/gen-spec.py`, and the consensus code's own functions agree with every one (the code dump below). `tools/token-value/tv-01/check-spec.py` checks the json and sums it to the cap in exact integers. + +## The D01 resolution + +The founder ratified D01 on 9 October 2026, 09:2x UK: capped issuance, subject to TV-04. + +The spec holds the cap as the invariant: **4,000,000,000 IGN, which is 4 x 10^27 base units**. There is no tail. There is no vote on emission, and no price or revenue trigger. There is no emergency mint. + +D01 supersedes this sentence of the litepaper (site/litepaper.html line 630, igneum master 6824d49c): + +> "One rule sits beside the cap. If external proving revenue is under one fifth of the block subsidy over any 90-day window after year 5, the question of a tail reward goes to the miners' signalling vote. The protocol never changes emission by itself." + +The code already matches D01: + +- Mainnet carries `EmissionSchedule::CURRENT` (params.rs:1858), and that schedule's tail is `Tail::Cap` (emission.rs:109). +- The schedule is a compiled genesis parameter. The daemon refuses an override file on mainnet and the testnet (daemon.rs, `params_compiled`, network.rs:266). +- No signal path reads or writes the emission schedule. + +"Subject to TV-04" means one thing. If TV-04's security-budget analysis shows capped security cannot pass, the volume's rule applies: delay the launch, or openly choose another monetary design. An undisclosed tail is never the answer. The site lane owns the change to the litepaper sentence. This landing does not edit `site/`. + +## The contract + +| Item | Value | Source (igneum-node, identical at release-2.0.2-node a284380b and release-2.0.3-node-k6 bf60948a) | +|---|---|---| +| Coin | IGN | | +| Base unit | 10^-18 IGN; one consensus base unit is one EVM wei | unit.rs:38; params.rs:1816 | +| Cap | 4,000,000,000 IGN = 4,000,000,000,000,000,000,000,000,000 base units | igneum.rs:37, :154 | +| Time key | seconds = floor(DAA score / blocks per second) | emission.rs:329 to 331; coinbase.rs:265 | +| Launch rate | 31,688,087,810,000,000,000 base units a DAA second (floor(10^17 / 31,557,600) at 8 decimals, times 10^10) | emission.rs:104; params.rs:1858 | +| Launch ramp | linear from 10% at genesis to 100% at 2,592,000 DAA seconds (30 days) | emission.rs:105 to 106, :316 | +| Decay | every 63,115,200 DAA seconds (two years of 365.25 days): rate[k+1] = floor(rate[k] x 2^31 / 2^32), a halving | emission.rs:107 to 108, :225 | +| Per-block subsidy | per_block(d) = ramp(floor(rate[floor(s / 63,115,200)] / bps), s), s = floor(d / bps) | emission.rs:329 to 333 | +| Tail | cap: the curve runs to zero and stays there | emission.rs:109 | +| Block rate | mainnet as compiled: 10 blocks a second from genesis; Devnet 4: 1 (C04 BLOCKED) | params.rs:1789, :2208 | +| Genesis | DAA score 0 (C09 BLOCKED: the compiled mainnet genesis still carries Kaspa's 1,312,860) | genesis.rs:92 | + +### How the cap is enforced + +No running counter enforces the cap. The schedule does: + +- Every block's coinbase must carry exactly the scheduled subsidy (coinbase.rs:262). +- The EVM state credits by the same rule (executor.rs:181 to 211). +- The cap constant itself is only compared in tests (igneum.rs:154). + +The schedule sums to the cap minus an exact shortfall, so issuance never reaches the cap. + +## The schedule + +`supply-spec.json` lists every phase with: + +- its start and end DAA score +- its per-block subsidy as an integer +- its rule name +- its source line + +There are two profiles, and their per-second curves are identical: + +- **mainnet as compiled**: 10 blocks a second, 64 phases. +- **Devnet 4**: 1 block a second, the litepaper's launch rate, 67 phases. + +The phases in order: + +1. **Ramp** (DAA 0 to 25,920,000 at 10 blocks a second). The per-block subsidy is the ramp formula, and the phase sum is exact. +2. **Full rate after the ramp**, to the first halving. +3. **One constant phase per halving**, until the last one-base-unit subsidy. +4. **Terminal**: zero from that point on, for ever. + + + +| Figure | Mainnet as compiled (10 blocks/s) | Devnet 4 (1 block/s) | +|---|---|---| +| Cap | 4,000,000,000 IGN (4000000000000000000000000000 base units) | the same | +| Total scheduled issuance | 3,963,038,999.610200467816224 IGN | 3,963,038,999.610200483289816 IGN | +| Shortfall under the cap (exact) | 36961000389799532183776000 base units (36,961,000.389799532183776 IGN) | 36961000389799516710184000 base units (36,961,000.389799516710184 IGN) | +| Ramp phase | DAA 0 to 25,920,000, 45,174,523.72229648548848 IGN | DAA 0 to 2,592,000, 45,174,523.722296485498848 IGN | +| First block | 0.3168808781 IGN | 3.168808781 IGN | +| Full-rate block (after the ramp) | 3.168808781 IGN | 31.68808781 IGN | +| Phases (ramp, constant, terminal) | 64 | 67 | +| Last non-zero subsidy | 1 base unit a block, DAA 38,500,272,000 to 39,131,424,000 | 1 base unit a block, DAA 4,039,372,800 to 4,102,488,000 | +| Terminal (zero for ever) from | DAA 39,131,424,000 (decay step 62, year 125) | DAA 4,102,488,000 (decay step 65, year 131) | +| Scheduled supply at the end of year 1 | 963,038,999.99163248548848 IGN | 963,038,999.991632485498848 IGN | +| Scheduled supply at the end of year 2 | 1,963,038,999.86448848548848 IGN | 1,963,038,999.864488485498848 IGN | +| Scheduled supply at the end of year 5 | 3,213,038,999.70555848548848 IGN | 3,213,038,999.705558485498848 IGN | +| Scheduled supply at the end of year 10 | 3,838,038,999.62609348548848 IGN | 3,838,038,999.626093485498848 IGN | +| Scheduled supply at the end of year 12 | 3,900,538,999.61814698548848 IGN | 3,900,538,999.618146985498848 IGN | +| Scheduled supply at the end of year 20 | 3,959,132,749.61069714173848 IGN | 3,959,132,749.610697141748848 IGN | +| Scheduled supply at the end of year 50 | 3,963,038,880.400910946483264 IGN | 3,963,038,880.400910949333816 IGN | +| Scheduled supply at the end of year 100 | 3,963,038,999.610196921373136 IGN | 3,963,038,999.6101969312294752 IGN | +| A 1-to-10 blocks/s step at DAA 31,557,600 under the current code | total 4,863,038,999.495770867826592 IGN, 863,038,999.495770867826592 IGN over the cap | | +| The compiled mainnet genesis (DAA 1,312,860) | first ramp block at 14.55%; 510,841.7849105123888436 IGN never scheduled | | + +Code agreement: every field of 129 decay phases, both ramps and both totals equal to this generator's integers (dump sha256 `3e4b5ac3c2f43057a13ace7d781ad714e385a94105623c0e0dac4adc417d8056`). + + + +What the figures mean: + +- **For a miner**: a full-rate block pays 3.168808781 IGN at 10 blocks a second, or 31.68808781 IGN at 1. The emission per second is the same either way, so a card's expected income does not depend on the block rate. In the first two years, 80% of each block goes to the block's producer and 20% to the proving escrow. +- **For a holder**: 963.04 million IGN are issued in year 1 and 1,963.04 million by the end of year 2. The total approaches 3,963,038,999.61 IGN and never reaches the cap. The 36,961,000.39 IGN shortfall is the launch ramp's withheld coins plus the floor of the per-second rate. Nobody holds them. +- **For security**: the subsidy halves every two years. It is one base unit a block by year 123 (10 blocks a second) and zero from the start of year 125. From then on, blocks are paid by fees alone. That is TV-04's question, and nothing in this spec answers it. + +## The coinbase split the node enforces + +| Rule | Effect | Source | +|---|---|---| +| Producer and proving pool | producer = subsidy - floor(subsidy x 20 / 100), pool = floor(subsidy x 20 / 100); fees go to the producer | igneum.rs:44, :201 to 208; coinbase.rs:106 | +| Signing bonus | a silent producer's share loses 10% (1,000 bps) to the pool; nothing destroyed; mainnet: off | igneum.rs:110; params.rs:1809 to 1810 | +| Native ledger (EVM state) | 80% to the block's `IGNA` address (or its `IGNW` split once the pool switch is on), 20% to the escrow 0x0000000000000000000000000000000000000220; blue blocks only | executor.rs:181 to 211; config.rs:59 | +| Shadow ledger (UTXO coinbase) | producer outputs plus one OP_RETURN output tagged `igneum-proving-pool-v0`; no UTXO transaction but the coinbase is valid, so these outputs are never spent | coinbase.rs:126 to 168; body_validation_in_isolation.rs:54 | +| Pool | none in consensus; the reference pool keeps `fee_percent` (default 1.0) of the 80% it receives and pays members PPLNS from its address | pool/src/payout.rs:1 to 6; pool/src/config.rs:58; pool/src/pplns.rs:76 | +| Dev fee | none in consensus; the miner software requests 1 template in 100 with the dev address (off with `--dev-fee 0`); it moves those blocks' producer share and creates nothing | litepaper line 625 | +| Treasury, foundation, team, stake | none | coinbase.rs:126 to 168; executor.rs:181 to 211 | +| Genesis | the genesis coinbase has no outputs; no premine | genesis.rs:26 | +| Burns | execution base fee and proving charge burned; 20% of the tip goes to registered payees, and unregistered parts are burned | executor.rs:319 to 371; pgas.rs:290 | + +## Supply accounting (VR-02, for TV-02) + +- **Issued**: the EVM state's subsidy credits (producer plus escrow), for blue blocks only. The schedule's sum, at one subsidy per DAA score, is the upper bound. +- **Burned**: base fees, proving charges and unregistered developer shares. The UTXO OP_RETURN output is **not** a burn (C06). +- **Locked**: the proving escrow's balance, meaning credited but not yet paid against a valid proof. Unclaimed credit is stranded today, as the litepaper says at line 609. +- **Not supply**: the UTXO coinbase outputs, which are an unspendable shadow record, and any bridged or wrapped IGN on another chain. +- **Replay model**: one scheduled subsidy per DAA score. A block is paid at its own DAA score. Parallel blocks can share a score, and a score can have no block. So measured issuance differs from the model only at phase boundaries, and only by the blocks merged across them. TV-02 reconciles the measured ledgers to this model in exact integers. + +## Conflicts between the litepaper and the code + +The litepaper is site/litepaper.html at igneum master 6824d49c (sha256 `35ac65e1...e85a94`). The code is igneum-node at both releases. Every quote below is checked exact by the generator. + +| # | The litepaper's words | The code's line and value | The spec takes, and why | Status | +|---|---|---|---|---| +| C01 | line 630, the tail-vote sentence quoted above | emission.rs:109 `Tail::Cap`; params.rs:1858; the override refused on mainnet; no vote path | The cap; the sentence is SUPERSEDED. D01, VR-01. | RESOLVED by D01, subject to TV-04 | +| C02 | line 578 "emission starts at 1 billion a year"; line 602 "3,938M IGN in the first 12 years of a 4,000M cap." | emission.rs:104 to 106: year 1 issues 963,038,999.99 IGN; years 1 to 12 issue 3,900,538,999.62 IGN | The code. The chart ignores the ramp's withheld 36.96M IGN. | RESOLVED; text correction owed (site lane) | +| C03 | line 578 "halves every two years for ever" | emission.rs:225, :331: the per-block subsidy floors to 0 at DAA 39,131,424,000 (start of year 125, 10 blocks/s) or DAA 4,102,488,000 (start of year 131, 1 block/s) | The code: a finite schedule ending in a terminal zero phase | RESOLVED; text correction owed | +| C04 | line 542 "one block a second at launch with scheduled steps to four and ten"; line 668 "31.688 IGN a block, 86,400 blocks a day" | params.rs:1789: mainnet runs 10 blocks/s from genesis. coinbase.rs:31, :265: the subsidy keys time on one block rate with no history, so a 1-to-10 step one year in would issue 4,863,038,999.50 IGN, which is 863,038,999.50 over the cap (check-spec KF4) | Both profiles, identical per second. No live block-rate step is cap-safe under today's code. | **BLOCKED** | +| C05 | line 568 "the base unit is Open" | unit.rs:38; params.rs:1816: 18 decimals | 18 decimals (O-2.6, decided 6 October 2026) | RESOLVED; text correction owed | +| C06 | line 609: the 20% "goes to an unspendable script ... and is burned there. Provers are paid from a separate escrow in the execution state" | coinbase.rs:163 (OP_RETURN on the UTXO side); body_validation_in_isolation.rs:54 (UTXO never spent); executor.rs:181 to 211 (the EVM state credits 80% and 20%) | Native supply is the EVM state. The UTXO 20% is not a burn, and the escrow balance is issued and locked. | RESOLVED for the spec; TV-02 reconciles both ledgers | +| C07 | line 620 "80% the block's miner, 20% the proving pool for the provers of that block" | coinbase.rs:152 to 159 (the UTXO side pays DAA red blocks); executor.rs:181 (the EVM credits blue only) | Native issuance is the blue blocks' subsidies; the schedule sum is the upper bound | RESOLVED; TV-02 measures the red share | +| C08 | silent | params.rs:1812 and :2232: `subsidy_per_block_activation_daa` is never on mainnet and Devnet 4 (testnet-1: 0). The EVM credits a merged block the merging chain block's subsidy, while the UTXO side pays the block's own. | Each block's own DAA score (ledger N8) is normative | **BLOCKED** | +| C09 | line 775 "Genesis with no premine, 30-day ramp." | genesis.rs:92: the mainnet GENESIS carries DAA 1,312,860 and Kaspa's 2021 timestamp. The first block would pay 14.55% of full rate, not 10%. 510,841.78 IGN would never be scheduled, and the schedule would run 1.52 days early. | Genesis at DAA score 0, as Devnet 4 and testnet-1 have it | **BLOCKED** | +| C10 | line 622 "80% the block's miner and provers; 20% the apps whose code ran, per call frame" | executor.rs:362 to 371: the tip less the developer share goes to the miner alone | The code. Fees move supply and never create it. | RESOLVED; text correction owed (drop "and provers") | +| C11 | line 647 "The reference pool never holds a member’s balance. Payouts come straight from the coinbase split" | pool/src/payout.rs:1 to 6 (the pool's address receives and pays); config.rs:58 (1% fee); params.rs:1851 (`pool_split_activation_daa` never) | The code: a custodial PPLNS pool with no supply effect | **BLOCKED** | +| C12 | line 630 "The cap stays at 4 billion. There is no tail emission." | emission.rs:116 to 122; params.rs:2014: the held testnet-1 object carries a 1% a year tail | Not the contract. The contract is `CURRENT` with `Tail::Cap`. | RESOLVED by D01 | +| C13 | silent | params.rs:1783 to 1784: Kaspa's `deflationary_phase_daa_score` and `pre_deflationary_phase_base_subsidy` sit in the mainnet object. Only the digest reads them (coinbase.rs:31). | Ignored: not part of the contract | RESOLVED; the node lane may annotate or remove them at the genesis cut | + +### The four BLOCKED rows: the founder's questions + +| Row | Question for the founder | Default if unanswered | Earliest clock | +|---|---|---|---| +| C04 | Does mainnet launch at the compiled 10 blocks a second, with the litepaper's 1-to-4-to-10 step plan removed? Or at 1 with steps? If steps, the node lane adds a block-rate-history subsidy rule before genesis, and TV-02 replays a step. | The spec freezes the compiled 10 blocks a second, and the step plan is treated as text to correct | the founder's answer | +| C08 | Should `subsidy_per_block_activation_daa` be 0 in the mainnet object, as testnet-1 has it, so both ledgers credit each block its own subsidy? (The node lane owns the change.) | N8 stays normative, and TV-02 reports the chain-block reading as a measured divergence | the founder's answer | +| C09 | Is the mainnet genesis cut at DAA score 0? | The spec freezes DAA score 0, and the genesis cut is checked against it | the founder's answer | +| C11 | Should the `IGNW` coinbase split be active at mainnet genesis (`pool_split_activation_daa` = 0), so the litepaper's custody sentence holds? Or should the sentence change to describe the custodial PPLNS pool and its 1% fee? | The sentence is corrected to match the code | the founder's answer | + +## Reproduce + +``` +python3 tools/token-value/tv-01/gen-spec.py --node-git \ + --igneum-root . --igneum-rev 6824d49cc32def4463b643293a5622545618f7a9 \ + --code-dump tools/token-value/tv-01/code-dump/schedule-bf60948a.jsonl \ + --out docs/plans/igneum-2.0-master/token-value/phase0/tv-01/supply-spec.json \ + --md docs/plans/igneum-2.0-master/token-value/phase0/tv-01/supply-spec.md +python3 tools/token-value/tv-01/check-spec.py +``` + +The generator refuses to write if any cited line has lost its anchor text at either node revision, or if any litepaper quote is not exact. The code dump comes from `tools/token-value/tv-01/code-dump/tv01_schedule.rs`. That program was copied into `consensus/core/examples/` of a scratch tree of bf60948a on build-9 and run there with `cargo run --release -p kaspa-consensus-core --example tv01_schedule`. It calls `Params::emission`, `EmissionTable::block_subsidy` and `Params::bps` for mainnet, Devnet 4 and testnet-1. The node fork itself is unchanged. diff --git a/tools/ci/batches/tv-01-20261009-01.json b/tools/ci/batches/tv-01-20261009-01.json new file mode 100644 index 000000000..b925f42c3 --- /dev/null +++ b/tools/ci/batches/tv-01-20261009-01.json @@ -0,0 +1,19 @@ +{ + "run_id": "tv-01-20261009-01", + "manifest_sha": "6824d49cc", + "evidence_dir": "docs/plans/igneum-2.0-master/token-value/phase0/tv-01", + "cells": [ + { + "cell": "token-value:tv-01", + "cases": [ + "TV-01" + ], + "status": "NOT RUN", + "in_progress": true, + "method": "static", + "evidence": "docs/plans/igneum-2.0-master/token-value/phase0/tv-01/supply-spec.json; docs/plans/igneum-2.0-master/token-value/phase0/tv-01/supply-spec.md; tools/token-value/tv-01/check-spec.py; tools/token-value/tv-01/code-dump/schedule-bf60948a.jsonl", + "note": "Phase 0 supply spec (TV-01): the cap 4,000,000,000 IGN held as the invariant under D01 (capped issuance, subject to TV-04), the litepaper's year-five tail-vote sentence superseded; two schedule profiles generated in exact integers and equal on every field to the consensus code's own dump on bf60948a (release-2.0.2-node a284380b byte-identical for every cited file); total + shortfall = cap exactly; 13 litepaper-versus-code rows, 4 BLOCKED on the founder's questions (C04 block rate, C08 per-block crediting, C09 mainnet genesis clock, C11 pool custody). A document and its checks, not a verdict; the panel reads it.", + "claim_impact": "none: nothing activates; the litepaper sentences named in the conflicts table are the site lane's to correct" + } + ] +} diff --git a/tools/token-value/tv-01/check-spec.py b/tools/token-value/tv-01/check-spec.py new file mode 100644 index 000000000..ef2839612 --- /dev/null +++ b/tools/token-value/tv-01/check-spec.py @@ -0,0 +1,250 @@ +#!/usr/bin/env python3 +"""TV-01 checker: reads supply-spec.json, checks it is well-formed, and sums every schedule to the cap in exact integers. + + python3 tools/token-value/tv-01/check-spec.py [docs/plans/igneum-2.0-master/token-value/phase0/tv-01/supply-spec.json] + +Order of work (the known-failed cases first, the standing rule that a check is trusted only after it has fired): + 1. four known-failed specs, built in memory from the real one, must each be REFUSED for the stated reason: + KF1 a tail (the terminal phase pays 1 base unit a block for ever): unbounded, the overshoot is infinite; + KF2 an emergency mint (the first full-rate phase doubled, every sum made self-consistent): overshoot over the cap; + KF3 the declared shortfall one base unit off: the exact reconciliation fails; + KF4 a block-rate step from 1 to 10 blocks a second one year in, keyed as the code keys time today: overshoot; + 2. the real spec must be well-formed and reconcile exactly: total + shortfall = cap, total <= cap, the phases + regenerated from the spec's own rules equal the listed phases, tail = cap, the tail-vote text SUPERSEDED. +Exit 0 only when every known-failed case was refused and the real spec checked clean. The output never says PASS: the +gate TV-01 reads NOT RUN until the independent panel reads the evidence. Standalone Python 3, deterministic. +""" +import copy +import json +import sys + +DEFAULT = "docs/plans/igneum-2.0-master/token-value/phase0/tv-01/supply-spec.json" +TOP = ["schema", "gate", "verdict", "decision", "invariant", "units", "cap", "rules", "activation_clocks", "schedules", + "coinbase_split", "fees", "supply_accounting", "superseded", "conflicts", "sources", "generator"] +CONFLICT_KEYS = ["id", "topic", "litepaper", "code", "spec_takes", "why", "status"] + + +class Refused(Exception): + pass + + +def need(cond, why): + if not cond: + raise Refused(why) + + +def amount(x, where): + need(isinstance(x, str) and x.isdigit() and (x == "0" or not x.startswith("0")), f"{where}: amount {x!r} is not a decimal string of base units") + return int(x) + + +# ---- the schedule regenerated from the spec's own rules (a third implementation beside the code and the generator) -- +def rules_of(spec): + r = spec["rules"] + return {"L": amount(r["launch_rate_per_second"], "rules.launch_rate_per_second"), "R": r["ramp_seconds"], + "P": r["ramp_start_percent"], "S": r["step_seconds"], "Q": r["step_decay_q32"]} + + +def rate(rr, k, cache={}): + key = (rr["L"], rr["Q"], k) + if key not in cache: + x = rr["L"] + for _ in range(k): + x = (x * rr["Q"]) >> 32 + cache[key] = x + return cache[key] + + +def per_block(rr, daa, bps): + s = daa // bps + full = rate(rr, s // rr["S"]) // bps + if s >= rr["R"]: + return full + return full * (rr["P"] * rr["R"] + (100 - rr["P"]) * s) // (100 * rr["R"]) + + +def ramp_sum(rr, bps): + full = rr["L"] // bps + R, P = rr["R"], rr["P"] + return sum(full * (P * R + (100 - P) * s) // (100 * R) for s in range(R)) * bps + + +def supply_to(rr, bps, daa): + """Scheduled issuance over DAA scores [0, daa) at one subsidy per DAA score.""" + total, R = 0, rr["R"] * bps + full = rr["L"] // bps + secs = min(daa, R) // bps + total += sum(full * (rr["P"] * rr["R"] + (100 - rr["P"]) * s) // (100 * rr["R"]) for s in range(secs)) * bps + total += (min(daa, R) - secs * bps) * per_block(rr, secs * bps, bps) + d = R + while d < daa: + k = (d // bps) // rr["S"] + end = min((k + 1) * rr["S"] * bps, daa) + pb = per_block(rr, d, bps) + if pb == 0: + break + total += pb * (end - d) + d = end + return total + + +# ---- the checks ---------------------------------------------------------------------------------------------- +def check(spec, regen=True): + """Returns a list of report lines; raises Refused on the first fault.""" + out = [] + for k in TOP: + need(k in spec, f"top-level field {k!r} missing") + need(spec["gate"] == "TV-01", "gate is not TV-01") + need(spec["verdict"] in ("NOT RUN", "BLOCKED", "FAIL"), f"verdict {spec['verdict']!r}: a lane never writes PASS on its own result") + need(spec["decision"].get("id") == "D01", "decision is not D01") + need(spec["rules"].get("tail") == "cap", f"tail is {spec['rules'].get('tail')!r}: under D01 the only tail is the cap") + cap = amount(spec["cap"]["base_units"], "cap.base_units") + unit = amount(spec["units"]["base_units_per_coin"], "units.base_units_per_coin") + need(unit == 10 ** spec["units"]["decimals"], "base_units_per_coin is not 10^decimals") + need(cap == int(spec["cap"]["coins"]) * unit, "cap.base_units is not cap.coins x base_units_per_coin") + sup = spec["superseded"] + need(any(s.get("status") == "SUPERSEDED" and "tail reward" in s.get("text", "") and s.get("by", "").startswith("D01") for s in sup), + "the litepaper's tail-vote sentence is not named SUPERSEDED by D01") + ids = set() + for c in spec["conflicts"]: + for k in CONFLICT_KEYS: + need(k in c, f"conflict {c.get('id')}: field {k!r} missing") + need(c["id"] not in ids, f"conflict id {c['id']} repeated") + ids.add(c["id"]) + need(c["status"].startswith("RESOLVED") or c["status"] == "BLOCKED", f"conflict {c['id']}: status {c['status']!r}") + if c["status"] == "BLOCKED": + need(c.get("question", "").startswith("For the founder"), f"conflict {c['id']}: BLOCKED without the founder's question") + rr = rules_of(spec) + need(rr["Q"] < 1 << 32 and rr["Q"] > 0, "step_decay_q32 outside 1..2^32: the curve would never fall") + for sc in spec["schedules"]: + name, bps, ph = sc["profile"], sc["bps"], sc["phases"] + need(isinstance(bps, int) and bps > 0, f"{name}: bps {bps!r}") + need(sc["genesis_daa_score"] == 0, f"{name}: genesis DAA score is not 0") + need(len(ph) == sc["phase_count"] and len(ph) >= 2, f"{name}: phase_count disagrees with the list") + need(ph[0]["start_daa_score"] == 0, f"{name}: the first phase does not start at DAA 0") + total, prev_pb = 0, None + for i, p in enumerate(ph): + need(p["index"] == i, f"{name}: phase {i} carries index {p['index']}") + need(p["source"], f"{name} phase {i}: no source line") + if i: + need(p["start_daa_score"] == ph[i - 1]["end_daa_score"], f"{name}: phase {i} does not start where phase {i - 1} ends (a gap or an overlap)") + s = amount(p["phase_sum"], f"{name} phase {i}.phase_sum") + if p["kind"] == "ramp": + need(i == 0, f"{name}: a ramp phase at index {i}") + rs = ramp_sum(rr, bps) + need(s == rs, f"{name}: the ramp's declared sum {s} is not its formula's {rs} (off by {s - rs})") + need(amount(p["ramp"]["full_per_block"], "ramp.full_per_block") == rr["L"] // bps, f"{name}: ramp full_per_block is not launch_rate / bps") + elif p["kind"] == "constant": + pb = amount(p["per_block_subsidy"], f"{name} phase {i}.per_block_subsidy") + need(pb > 0, f"{name}: constant phase {i} pays 0 (that is the terminal)") + need(p["end_daa_score"] > p["start_daa_score"], f"{name}: phase {i} is empty") + need(s == pb * (p["end_daa_score"] - p["start_daa_score"]), f"{name}: phase {i} sum is not per_block x length") + need(prev_pb is None or pb <= prev_pb, f"{name}: phase {i} pays more than phase {i - 1} (issuance rises)") + prev_pb = pb + elif p["kind"] == "terminal": + need(i == len(ph) - 1, f"{name}: a terminal phase before the end") + need(p["end_daa_score"] is None, f"{name}: the terminal phase has an end") + tb = amount(p["per_block_subsidy"], f"{name} terminal per_block_subsidy") + need(tb == 0, f"{name}: the terminal phase pays {tb} base units a block for ever: issuance is unbounded, the overshoot over the cap is infinite") + else: + raise Refused(f"{name}: phase {i} kind {p['kind']!r}") + total += s + need(ph[-1]["kind"] == "terminal", f"{name}: the schedule has no terminal phase (issuance is not shown to end)") + need(total == amount(sc["total_issuance"], f"{name}.total_issuance"), f"{name}: the phases sum to {total}, the spec says {sc['total_issuance']}") + if total > cap: + raise Refused(f"{name}: overshoot {total - cap} base units ({(total - cap) / unit:,.6f} IGN) over the cap") + short = cap - total + declared = amount(sc["cap_shortfall"], f"{name}.cap_shortfall") + need(short == declared, f"{name}: total + declared shortfall = {total + declared}, not the cap (off by {declared - short} base units)") + if regen: + for p in ph: + if p["kind"] == "ramp": + continue + a = p["start_daa_score"] + pb = per_block(rr, a, bps) + need(str(pb) == p["per_block_subsidy"], f"{name}: phase {p['index']} lists {p['per_block_subsidy']}, the rules give {pb}") + if p["end_daa_score"] is not None: + need(per_block(rr, p["end_daa_score"] - 1, bps) == pb, f"{name}: phase {p['index']} is not constant under the rules") + nb = per_block(rr, p["end_daa_score"], bps) + need(nb != pb, f"{name}: phase {p['index']} ends where the rules do not change") + out.append(f"{name}: {len(ph)} phases, contiguous from DAA 0, terminal zero from DAA {ph[-1]['start_daa_score']:,}; " + f"total {total} + shortfall {short} = cap {cap} exactly (shortfall {short / unit:,.6f} IGN)") + return out + + +def bps_step_case(spec): + """KF4: the schedule as the code would pay it if the block rate stepped from 1 to 10 a second at DAA one year in.""" + rr = rules_of(spec) + cap = int(spec["cap"]["base_units"]) + y = spec["rules"]["year_seconds"] + step = y * 1 + s10 = int(next(s for s in spec["schedules"] if s["bps"] == 10)["total_issuance"]) + issued = supply_to(rr, 1, step) + (s10 - supply_to(rr, 10, step)) + need(issued <= cap, f"a 1-to-10 block-rate step at DAA {step:,} keyed as daa / bps: issuance {issued}, overshoot {issued - cap} base units over the cap") + return issued + + +def main(): + path = sys.argv[1] if len(sys.argv) > 1 else DEFAULT + spec = json.load(open(path)) + fails = 0 + + def known_failed(label, mutate, run=None): + nonlocal fails + s = copy.deepcopy(spec) + mutate(s) + try: + (run or (lambda x: check(x, regen=False)))(s) + except Refused as e: + print(f"known-failed {label}: refused as expected: {e}") + return + print(f"known-failed {label}: NOT refused (the checker is broken)") + fails += 1 + + def kf1(s): + sc = s["schedules"][0] + sc["phases"][-1]["per_block_subsidy"] = "1" + + def kf2(s): + sc = s["schedules"][0] + p = sc["phases"][1] + old = int(p["phase_sum"]) + pb = int(p["per_block_subsidy"]) * 2 + p["per_block_subsidy"] = str(pb) + p["phase_sum"] = str(pb * (p["end_daa_score"] - p["start_daa_score"])) + sc["total_issuance"] = str(int(sc["total_issuance"]) - old + int(p["phase_sum"])) + sc["cap_shortfall"] = str(int(s["cap"]["base_units"]) - int(sc["total_issuance"])) # may go negative: str(-x) fails too + + def kf2_run(s): + sc = s["schedules"][0] + if sc["cap_shortfall"].startswith("-"): + sc["cap_shortfall"] = "0" # make the field well-formed so the overshoot itself is what refuses it + return check(s, regen=False) + + def kf3(s): + sc = s["schedules"][0] + sc["cap_shortfall"] = str(int(sc["cap_shortfall"]) + 1) + + known_failed("KF1 (a tail: the terminal pays 1 base unit a block for ever)", kf1) + known_failed("KF2 (an emergency mint: the first full-rate phase doubled, sums self-consistent)", kf2, kf2_run) + known_failed("KF3 (the declared shortfall one base unit off)", kf3) + known_failed("KF4 (a 1-to-10 block-rate step one year in, time keyed as daa / bps)", lambda s: None, bps_step_case) + + try: + lines = check(spec) + except Refused as e: + print(f"spec {path}: REFUSED: {e}") + return 1 + for l in lines: + print(l) + blocked = [c["id"] for c in spec["conflicts"] if c["status"] == "BLOCKED"] + print(f"conflicts: {len(spec['conflicts'])} rows, BLOCKED: {', '.join(blocked) or 'none'}; gate TV-01 verdict as written: {spec['verdict']}") + if fails: + print(f"checker: {fails} known-failed case(s) were not refused; the result above is not trusted") + return 2 + print("check: well-formed and exact (a check result, not a gate verdict)") + return 0 + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/tools/token-value/tv-01/code-dump/schedule-bf60948a.jsonl b/tools/token-value/tv-01/code-dump/schedule-bf60948a.jsonl new file mode 100644 index 000000000..05d2b9638 --- /dev/null +++ b/tools/token-value/tv-01/code-dump/schedule-bf60948a.jsonl @@ -0,0 +1,139 @@ +{"network":"mainnet","bps":10,"decimals":18,"launch_rate":"31688087810000000000","ramp_seconds":2592000,"ramp_start_percent":10,"step_seconds":63115200,"step_decay_q32":2147483648,"tail":"cap","steps":66,"genesis_daa_score":1312860} +{"network":"mainnet","phase":"ramp","start_daa":0,"end_daa":25920000,"first_block":"316880878100000000","last_block":"3168807680719173263","sum":"45174523722296485488480000"} +{"network":"mainnet","phase":"step","k":0,"start_daa":25920000,"end_daa":631152000,"per_block":"3168808781000000000","rate_per_second":"31688087810000000000","sum":"1917864476142192000000000000"} +{"network":"mainnet","phase":"step","k":1,"start_daa":631152000,"end_daa":1262304000,"per_block":"1584404390500000000","rate_per_second":"15844043905000000000","sum":"999999999872856000000000000"} +{"network":"mainnet","phase":"step","k":2,"start_daa":1262304000,"end_daa":1893456000,"per_block":"792202195250000000","rate_per_second":"7922021952500000000","sum":"499999999936428000000000000"} +{"network":"mainnet","phase":"step","k":3,"start_daa":1893456000,"end_daa":2524608000,"per_block":"396101097625000000","rate_per_second":"3961010976250000000","sum":"249999999968214000000000000"} +{"network":"mainnet","phase":"step","k":4,"start_daa":2524608000,"end_daa":3155760000,"per_block":"198050548812500000","rate_per_second":"1980505488125000000","sum":"124999999984107000000000000"} +{"network":"mainnet","phase":"step","k":5,"start_daa":3155760000,"end_daa":3786912000,"per_block":"99025274406250000","rate_per_second":"990252744062500000","sum":"62499999992053500000000000"} +{"network":"mainnet","phase":"step","k":6,"start_daa":3786912000,"end_daa":4418064000,"per_block":"49512637203125000","rate_per_second":"495126372031250000","sum":"31249999996026750000000000"} +{"network":"mainnet","phase":"step","k":7,"start_daa":4418064000,"end_daa":5049216000,"per_block":"24756318601562500","rate_per_second":"247563186015625000","sum":"15624999998013375000000000"} +{"network":"mainnet","phase":"step","k":8,"start_daa":5049216000,"end_daa":5680368000,"per_block":"12378159300781250","rate_per_second":"123781593007812500","sum":"7812499999006687500000000"} +{"network":"mainnet","phase":"step","k":9,"start_daa":5680368000,"end_daa":6311520000,"per_block":"6189079650390625","rate_per_second":"61890796503906250","sum":"3906249999503343750000000"} +{"network":"mainnet","phase":"step","k":10,"start_daa":6311520000,"end_daa":6942672000,"per_block":"3094539825195312","rate_per_second":"30945398251953125","sum":"1953124999751671559424000"} +{"network":"mainnet","phase":"step","k":11,"start_daa":6942672000,"end_daa":7573824000,"per_block":"1547269912597656","rate_per_second":"15472699125976562","sum":"976562499875835779712000"} +{"network":"mainnet","phase":"step","k":12,"start_daa":7573824000,"end_daa":8204976000,"per_block":"773634956298828","rate_per_second":"7736349562988281","sum":"488281249937917889856000"} +{"network":"mainnet","phase":"step","k":13,"start_daa":8204976000,"end_daa":8836128000,"per_block":"386817478149414","rate_per_second":"3868174781494140","sum":"244140624968958944928000"} +{"network":"mainnet","phase":"step","k":14,"start_daa":8836128000,"end_daa":9467280000,"per_block":"193408739074707","rate_per_second":"1934087390747070","sum":"122070312484479472464000"} +{"network":"mainnet","phase":"step","k":15,"start_daa":9467280000,"end_daa":10098432000,"per_block":"96704369537353","rate_per_second":"967043695373535","sum":"61035156242239420656000"} +{"network":"mainnet","phase":"step","k":16,"start_daa":10098432000,"end_daa":10729584000,"per_block":"48352184768676","rate_per_second":"483521847686767","sum":"30517578121119394752000"} +{"network":"mainnet","phase":"step","k":17,"start_daa":10729584000,"end_daa":11360736000,"per_block":"24176092384338","rate_per_second":"241760923843383","sum":"15258789060559697376000"} +{"network":"mainnet","phase":"step","k":18,"start_daa":11360736000,"end_daa":11991888000,"per_block":"12088046192169","rate_per_second":"120880461921691","sum":"7629394530279848688000"} +{"network":"mainnet","phase":"step","k":19,"start_daa":11991888000,"end_daa":12623040000,"per_block":"6044023096084","rate_per_second":"60440230960845","sum":"3814697265139608768000"} +{"network":"mainnet","phase":"step","k":20,"start_daa":12623040000,"end_daa":13254192000,"per_block":"3022011548042","rate_per_second":"30220115480422","sum":"1907348632569804384000"} +{"network":"mainnet","phase":"step","k":21,"start_daa":13254192000,"end_daa":13885344000,"per_block":"1511005774021","rate_per_second":"15110057740211","sum":"953674316284902192000"} +{"network":"mainnet","phase":"step","k":22,"start_daa":13885344000,"end_daa":14516496000,"per_block":"755502887010","rate_per_second":"7555028870105","sum":"476837158142135520000"} +{"network":"mainnet","phase":"step","k":23,"start_daa":14516496000,"end_daa":15147648000,"per_block":"377751443505","rate_per_second":"3777514435052","sum":"238418579071067760000"} +{"network":"mainnet","phase":"step","k":24,"start_daa":15147648000,"end_daa":15778800000,"per_block":"188875721752","rate_per_second":"1888757217526","sum":"119209289535218304000"} +{"network":"mainnet","phase":"step","k":25,"start_daa":15778800000,"end_daa":16409952000,"per_block":"94437860876","rate_per_second":"944378608763","sum":"59604644767609152000"} +{"network":"mainnet","phase":"step","k":26,"start_daa":16409952000,"end_daa":17041104000,"per_block":"47218930438","rate_per_second":"472189304381","sum":"29802322383804576000"} +{"network":"mainnet","phase":"step","k":27,"start_daa":17041104000,"end_daa":17672256000,"per_block":"23609465219","rate_per_second":"236094652190","sum":"14901161191902288000"} +{"network":"mainnet","phase":"step","k":28,"start_daa":17672256000,"end_daa":18303408000,"per_block":"11804732609","rate_per_second":"118047326095","sum":"7450580595635568000"} +{"network":"mainnet","phase":"step","k":29,"start_daa":18303408000,"end_daa":18934560000,"per_block":"5902366304","rate_per_second":"59023663047","sum":"3725290297502208000"} +{"network":"mainnet","phase":"step","k":30,"start_daa":18934560000,"end_daa":19565712000,"per_block":"2951183152","rate_per_second":"29511831523","sum":"1862645148751104000"} +{"network":"mainnet","phase":"step","k":31,"start_daa":19565712000,"end_daa":20196864000,"per_block":"1475591576","rate_per_second":"14755915761","sum":"931322574375552000"} +{"network":"mainnet","phase":"step","k":32,"start_daa":20196864000,"end_daa":20828016000,"per_block":"737795788","rate_per_second":"7377957880","sum":"465661287187776000"} +{"network":"mainnet","phase":"step","k":33,"start_daa":20828016000,"end_daa":21459168000,"per_block":"368897894","rate_per_second":"3688978940","sum":"232830643593888000"} +{"network":"mainnet","phase":"step","k":34,"start_daa":21459168000,"end_daa":22090320000,"per_block":"184448947","rate_per_second":"1844489470","sum":"116415321796944000"} +{"network":"mainnet","phase":"step","k":35,"start_daa":22090320000,"end_daa":22721472000,"per_block":"92224473","rate_per_second":"922244735","sum":"58207660582896000"} +{"network":"mainnet","phase":"step","k":36,"start_daa":22721472000,"end_daa":23352624000,"per_block":"46112236","rate_per_second":"461122367","sum":"29103829975872000"} +{"network":"mainnet","phase":"step","k":37,"start_daa":23352624000,"end_daa":23983776000,"per_block":"23056118","rate_per_second":"230561183","sum":"14551914987936000"} +{"network":"mainnet","phase":"step","k":38,"start_daa":23983776000,"end_daa":24614928000,"per_block":"11528059","rate_per_second":"115280591","sum":"7275957493968000"} +{"network":"mainnet","phase":"step","k":39,"start_daa":24614928000,"end_daa":25246080000,"per_block":"5764029","rate_per_second":"57640295","sum":"3637978431408000"} +{"network":"mainnet","phase":"step","k":40,"start_daa":25246080000,"end_daa":25877232000,"per_block":"2882014","rate_per_second":"28820147","sum":"1818988900128000"} +{"network":"mainnet","phase":"step","k":41,"start_daa":25877232000,"end_daa":26508384000,"per_block":"1441007","rate_per_second":"14410073","sum":"909494450064000"} +{"network":"mainnet","phase":"step","k":42,"start_daa":26508384000,"end_daa":27139536000,"per_block":"720503","rate_per_second":"7205036","sum":"454746909456000"} +{"network":"mainnet","phase":"step","k":43,"start_daa":27139536000,"end_daa":27770688000,"per_block":"360251","rate_per_second":"3602518","sum":"227373139152000"} +{"network":"mainnet","phase":"step","k":44,"start_daa":27770688000,"end_daa":28401840000,"per_block":"180125","rate_per_second":"1801259","sum":"113686254000000"} +{"network":"mainnet","phase":"step","k":45,"start_daa":28401840000,"end_daa":29032992000,"per_block":"90062","rate_per_second":"900629","sum":"56842811424000"} +{"network":"mainnet","phase":"step","k":46,"start_daa":29032992000,"end_daa":29664144000,"per_block":"45031","rate_per_second":"450314","sum":"28421405712000"} +{"network":"mainnet","phase":"step","k":47,"start_daa":29664144000,"end_daa":30295296000,"per_block":"22515","rate_per_second":"225157","sum":"14210387280000"} +{"network":"mainnet","phase":"step","k":48,"start_daa":30295296000,"end_daa":30926448000,"per_block":"11257","rate_per_second":"112578","sum":"7104878064000"} +{"network":"mainnet","phase":"step","k":49,"start_daa":30926448000,"end_daa":31557600000,"per_block":"5628","rate_per_second":"56289","sum":"3552123456000"} +{"network":"mainnet","phase":"step","k":50,"start_daa":31557600000,"end_daa":32188752000,"per_block":"2814","rate_per_second":"28144","sum":"1776061728000"} +{"network":"mainnet","phase":"step","k":51,"start_daa":32188752000,"end_daa":32819904000,"per_block":"1407","rate_per_second":"14072","sum":"888030864000"} +{"network":"mainnet","phase":"step","k":52,"start_daa":32819904000,"end_daa":33451056000,"per_block":"703","rate_per_second":"7036","sum":"443699856000"} +{"network":"mainnet","phase":"step","k":53,"start_daa":33451056000,"end_daa":34082208000,"per_block":"351","rate_per_second":"3518","sum":"221534352000"} +{"network":"mainnet","phase":"step","k":54,"start_daa":34082208000,"end_daa":34713360000,"per_block":"175","rate_per_second":"1759","sum":"110451600000"} +{"network":"mainnet","phase":"step","k":55,"start_daa":34713360000,"end_daa":35344512000,"per_block":"87","rate_per_second":"879","sum":"54910224000"} +{"network":"mainnet","phase":"step","k":56,"start_daa":35344512000,"end_daa":35975664000,"per_block":"43","rate_per_second":"439","sum":"27139536000"} +{"network":"mainnet","phase":"step","k":57,"start_daa":35975664000,"end_daa":36606816000,"per_block":"21","rate_per_second":"219","sum":"13254192000"} +{"network":"mainnet","phase":"step","k":58,"start_daa":36606816000,"end_daa":37237968000,"per_block":"10","rate_per_second":"109","sum":"6311520000"} +{"network":"mainnet","phase":"step","k":59,"start_daa":37237968000,"end_daa":37869120000,"per_block":"5","rate_per_second":"54","sum":"3155760000"} +{"network":"mainnet","phase":"step","k":60,"start_daa":37869120000,"end_daa":38500272000,"per_block":"2","rate_per_second":"27","sum":"1262304000"} +{"network":"mainnet","phase":"step","k":61,"start_daa":38500272000,"end_daa":39131424000,"per_block":"1","rate_per_second":"13","sum":"631152000"} +{"network":"mainnet","phase":"step","k":62,"start_daa":39131424000,"end_daa":39762576000,"per_block":"0","rate_per_second":"6","sum":"0"} +{"network":"mainnet","phase":"terminal","start_daa":39131424000,"per_block":"0"} +{"network":"mainnet","total":"3963038999610200467816224000","cap":"4000000000000000000000000000","shortfall":"36961000389799532183776000"} +{"network":"devnet-4","bps":1,"decimals":18,"launch_rate":"31688087810000000000","ramp_seconds":2592000,"ramp_start_percent":10,"step_seconds":63115200,"step_decay_q32":2147483648,"tail":"cap","steps":66,"genesis_daa_score":0} +{"network":"devnet-4","phase":"ramp","start_daa":0,"end_daa":2592000,"first_block":"3168808781000000000","last_block":"31688076807191732638","sum":"45174523722296485498848000"} +{"network":"devnet-4","phase":"step","k":0,"start_daa":2592000,"end_daa":63115200,"per_block":"31688087810000000000","rate_per_second":"31688087810000000000","sum":"1917864476142192000000000000"} +{"network":"devnet-4","phase":"step","k":1,"start_daa":63115200,"end_daa":126230400,"per_block":"15844043905000000000","rate_per_second":"15844043905000000000","sum":"999999999872856000000000000"} +{"network":"devnet-4","phase":"step","k":2,"start_daa":126230400,"end_daa":189345600,"per_block":"7922021952500000000","rate_per_second":"7922021952500000000","sum":"499999999936428000000000000"} +{"network":"devnet-4","phase":"step","k":3,"start_daa":189345600,"end_daa":252460800,"per_block":"3961010976250000000","rate_per_second":"3961010976250000000","sum":"249999999968214000000000000"} +{"network":"devnet-4","phase":"step","k":4,"start_daa":252460800,"end_daa":315576000,"per_block":"1980505488125000000","rate_per_second":"1980505488125000000","sum":"124999999984107000000000000"} +{"network":"devnet-4","phase":"step","k":5,"start_daa":315576000,"end_daa":378691200,"per_block":"990252744062500000","rate_per_second":"990252744062500000","sum":"62499999992053500000000000"} +{"network":"devnet-4","phase":"step","k":6,"start_daa":378691200,"end_daa":441806400,"per_block":"495126372031250000","rate_per_second":"495126372031250000","sum":"31249999996026750000000000"} +{"network":"devnet-4","phase":"step","k":7,"start_daa":441806400,"end_daa":504921600,"per_block":"247563186015625000","rate_per_second":"247563186015625000","sum":"15624999998013375000000000"} +{"network":"devnet-4","phase":"step","k":8,"start_daa":504921600,"end_daa":568036800,"per_block":"123781593007812500","rate_per_second":"123781593007812500","sum":"7812499999006687500000000"} +{"network":"devnet-4","phase":"step","k":9,"start_daa":568036800,"end_daa":631152000,"per_block":"61890796503906250","rate_per_second":"61890796503906250","sum":"3906249999503343750000000"} +{"network":"devnet-4","phase":"step","k":10,"start_daa":631152000,"end_daa":694267200,"per_block":"30945398251953125","rate_per_second":"30945398251953125","sum":"1953124999751671875000000"} +{"network":"devnet-4","phase":"step","k":11,"start_daa":694267200,"end_daa":757382400,"per_block":"15472699125976562","rate_per_second":"15472699125976562","sum":"976562499875835905942400"} +{"network":"devnet-4","phase":"step","k":12,"start_daa":757382400,"end_daa":820497600,"per_block":"7736349562988281","rate_per_second":"7736349562988281","sum":"488281249937917952971200"} +{"network":"devnet-4","phase":"step","k":13,"start_daa":820497600,"end_daa":883612800,"per_block":"3868174781494140","rate_per_second":"3868174781494140","sum":"244140624968958944928000"} +{"network":"devnet-4","phase":"step","k":14,"start_daa":883612800,"end_daa":946728000,"per_block":"1934087390747070","rate_per_second":"1934087390747070","sum":"122070312484479472464000"} +{"network":"devnet-4","phase":"step","k":15,"start_daa":946728000,"end_daa":1009843200,"per_block":"967043695373535","rate_per_second":"967043695373535","sum":"61035156242239736232000"} +{"network":"devnet-4","phase":"step","k":16,"start_daa":1009843200,"end_daa":1072958400,"per_block":"483521847686767","rate_per_second":"483521847686767","sum":"30517578121119836558400"} +{"network":"devnet-4","phase":"step","k":17,"start_daa":1072958400,"end_daa":1136073600,"per_block":"241760923843383","rate_per_second":"241760923843383","sum":"15258789060559886721600"} +{"network":"devnet-4","phase":"step","k":18,"start_daa":1136073600,"end_daa":1199188800,"per_block":"120880461921691","rate_per_second":"120880461921691","sum":"7629394530279911803200"} +{"network":"devnet-4","phase":"step","k":19,"start_daa":1199188800,"end_daa":1262304000,"per_block":"60440230960845","rate_per_second":"60440230960845","sum":"3814697265139924344000"} +{"network":"devnet-4","phase":"step","k":20,"start_daa":1262304000,"end_daa":1325419200,"per_block":"30220115480422","rate_per_second":"30220115480422","sum":"1907348632569930614400"} +{"network":"devnet-4","phase":"step","k":21,"start_daa":1325419200,"end_daa":1388534400,"per_block":"15110057740211","rate_per_second":"15110057740211","sum":"953674316284965307200"} +{"network":"devnet-4","phase":"step","k":22,"start_daa":1388534400,"end_daa":1451649600,"per_block":"7555028870105","rate_per_second":"7555028870105","sum":"476837158142451096000"} +{"network":"devnet-4","phase":"step","k":23,"start_daa":1451649600,"end_daa":1514764800,"per_block":"3777514435052","rate_per_second":"3777514435052","sum":"238418579071193990400"} +{"network":"devnet-4","phase":"step","k":24,"start_daa":1514764800,"end_daa":1577880000,"per_block":"1888757217526","rate_per_second":"1888757217526","sum":"119209289535596995200"} +{"network":"devnet-4","phase":"step","k":25,"start_daa":1577880000,"end_daa":1640995200,"per_block":"944378608763","rate_per_second":"944378608763","sum":"59604644767798497600"} +{"network":"devnet-4","phase":"step","k":26,"start_daa":1640995200,"end_daa":1704110400,"per_block":"472189304381","rate_per_second":"472189304381","sum":"29802322383867691200"} +{"network":"devnet-4","phase":"step","k":27,"start_daa":1704110400,"end_daa":1767225600,"per_block":"236094652190","rate_per_second":"236094652190","sum":"14901161191902288000"} +{"network":"devnet-4","phase":"step","k":28,"start_daa":1767225600,"end_daa":1830340800,"per_block":"118047326095","rate_per_second":"118047326095","sum":"7450580595951144000"} +{"network":"devnet-4","phase":"step","k":29,"start_daa":1830340800,"end_daa":1893456000,"per_block":"59023663047","rate_per_second":"59023663047","sum":"3725290297944014400"} +{"network":"devnet-4","phase":"step","k":30,"start_daa":1893456000,"end_daa":1956571200,"per_block":"29511831523","rate_per_second":"29511831523","sum":"1862645148940449600"} +{"network":"devnet-4","phase":"step","k":31,"start_daa":1956571200,"end_daa":2019686400,"per_block":"14755915761","rate_per_second":"14755915761","sum":"931322574438667200"} +{"network":"devnet-4","phase":"step","k":32,"start_daa":2019686400,"end_daa":2082801600,"per_block":"7377957880","rate_per_second":"7377957880","sum":"465661287187776000"} +{"network":"devnet-4","phase":"step","k":33,"start_daa":2082801600,"end_daa":2145916800,"per_block":"3688978940","rate_per_second":"3688978940","sum":"232830643593888000"} +{"network":"devnet-4","phase":"step","k":34,"start_daa":2145916800,"end_daa":2209032000,"per_block":"1844489470","rate_per_second":"1844489470","sum":"116415321796944000"} +{"network":"devnet-4","phase":"step","k":35,"start_daa":2209032000,"end_daa":2272147200,"per_block":"922244735","rate_per_second":"922244735","sum":"58207660898472000"} +{"network":"devnet-4","phase":"step","k":36,"start_daa":2272147200,"end_daa":2335262400,"per_block":"461122367","rate_per_second":"461122367","sum":"29103830417678400"} +{"network":"devnet-4","phase":"step","k":37,"start_daa":2335262400,"end_daa":2398377600,"per_block":"230561183","rate_per_second":"230561183","sum":"14551915177281600"} +{"network":"devnet-4","phase":"step","k":38,"start_daa":2398377600,"end_daa":2461492800,"per_block":"115280591","rate_per_second":"115280591","sum":"7275957557083200"} +{"network":"devnet-4","phase":"step","k":39,"start_daa":2461492800,"end_daa":2524608000,"per_block":"57640295","rate_per_second":"57640295","sum":"3637978746984000"} +{"network":"devnet-4","phase":"step","k":40,"start_daa":2524608000,"end_daa":2587723200,"per_block":"28820147","rate_per_second":"28820147","sum":"1818989341934400"} +{"network":"devnet-4","phase":"step","k":41,"start_daa":2587723200,"end_daa":2650838400,"per_block":"14410073","rate_per_second":"14410073","sum":"909494639409600"} +{"network":"devnet-4","phase":"step","k":42,"start_daa":2650838400,"end_daa":2713953600,"per_block":"7205036","rate_per_second":"7205036","sum":"454747288147200"} +{"network":"devnet-4","phase":"step","k":43,"start_daa":2713953600,"end_daa":2777068800,"per_block":"3602518","rate_per_second":"3602518","sum":"227373644073600"} +{"network":"devnet-4","phase":"step","k":44,"start_daa":2777068800,"end_daa":2840184000,"per_block":"1801259","rate_per_second":"1801259","sum":"113686822036800"} +{"network":"devnet-4","phase":"step","k":45,"start_daa":2840184000,"end_daa":2903299200,"per_block":"900629","rate_per_second":"900629","sum":"56843379460800"} +{"network":"devnet-4","phase":"step","k":46,"start_daa":2903299200,"end_daa":2966414400,"per_block":"450314","rate_per_second":"450314","sum":"28421658172800"} +{"network":"devnet-4","phase":"step","k":47,"start_daa":2966414400,"end_daa":3029529600,"per_block":"225157","rate_per_second":"225157","sum":"14210829086400"} +{"network":"devnet-4","phase":"step","k":48,"start_daa":3029529600,"end_daa":3092644800,"per_block":"112578","rate_per_second":"112578","sum":"7105382985600"} +{"network":"devnet-4","phase":"step","k":49,"start_daa":3092644800,"end_daa":3155760000,"per_block":"56289","rate_per_second":"56289","sum":"3552691492800"} +{"network":"devnet-4","phase":"step","k":50,"start_daa":3155760000,"end_daa":3218875200,"per_block":"28144","rate_per_second":"28144","sum":"1776314188800"} +{"network":"devnet-4","phase":"step","k":51,"start_daa":3218875200,"end_daa":3281990400,"per_block":"14072","rate_per_second":"14072","sum":"888157094400"} +{"network":"devnet-4","phase":"step","k":52,"start_daa":3281990400,"end_daa":3345105600,"per_block":"7036","rate_per_second":"7036","sum":"444078547200"} +{"network":"devnet-4","phase":"step","k":53,"start_daa":3345105600,"end_daa":3408220800,"per_block":"3518","rate_per_second":"3518","sum":"222039273600"} +{"network":"devnet-4","phase":"step","k":54,"start_daa":3408220800,"end_daa":3471336000,"per_block":"1759","rate_per_second":"1759","sum":"111019636800"} +{"network":"devnet-4","phase":"step","k":55,"start_daa":3471336000,"end_daa":3534451200,"per_block":"879","rate_per_second":"879","sum":"55478260800"} +{"network":"devnet-4","phase":"step","k":56,"start_daa":3534451200,"end_daa":3597566400,"per_block":"439","rate_per_second":"439","sum":"27707572800"} +{"network":"devnet-4","phase":"step","k":57,"start_daa":3597566400,"end_daa":3660681600,"per_block":"219","rate_per_second":"219","sum":"13822228800"} +{"network":"devnet-4","phase":"step","k":58,"start_daa":3660681600,"end_daa":3723796800,"per_block":"109","rate_per_second":"109","sum":"6879556800"} +{"network":"devnet-4","phase":"step","k":59,"start_daa":3723796800,"end_daa":3786912000,"per_block":"54","rate_per_second":"54","sum":"3408220800"} +{"network":"devnet-4","phase":"step","k":60,"start_daa":3786912000,"end_daa":3850027200,"per_block":"27","rate_per_second":"27","sum":"1704110400"} +{"network":"devnet-4","phase":"step","k":61,"start_daa":3850027200,"end_daa":3913142400,"per_block":"13","rate_per_second":"13","sum":"820497600"} +{"network":"devnet-4","phase":"step","k":62,"start_daa":3913142400,"end_daa":3976257600,"per_block":"6","rate_per_second":"6","sum":"378691200"} +{"network":"devnet-4","phase":"step","k":63,"start_daa":3976257600,"end_daa":4039372800,"per_block":"3","rate_per_second":"3","sum":"189345600"} +{"network":"devnet-4","phase":"step","k":64,"start_daa":4039372800,"end_daa":4102488000,"per_block":"1","rate_per_second":"1","sum":"63115200"} +{"network":"devnet-4","phase":"step","k":65,"start_daa":4102488000,"end_daa":4165603200,"per_block":"0","rate_per_second":"0","sum":"0"} +{"network":"devnet-4","phase":"terminal","start_daa":4102488000,"per_block":"0"} +{"network":"devnet-4","total":"3963038999610200483289816000","cap":"4000000000000000000000000000","shortfall":"36961000389799516710184000"} +{"network":"testnet-1","bps":1,"decimals":18,"launch_rate":"100000000000000000000","ramp_seconds":7776000,"ramp_start_percent":10,"step_seconds":2629800,"step_decay_q32":4172697914,"tail":"percent:100","steps":125,"genesis_daa_score":0} +{"network":"testnet-1","note":"not a cap schedule; phases not dumped"} diff --git a/tools/token-value/tv-01/code-dump/tv01_schedule.rs b/tools/token-value/tv-01/code-dump/tv01_schedule.rs new file mode 100644 index 000000000..e4ab77be7 --- /dev/null +++ b/tools/token-value/tv-01/code-dump/tv01_schedule.rs @@ -0,0 +1,60 @@ +//! TV-01 (token value phase 0, 9 October 2026): the per-block subsidy schedule of each compiled network, read from the +//! consensus code's own functions (`Params::emission`, `EmissionTable::block_subsidy`, `Params::bps`), as JSON lines. +//! Lane scratch file on build-9 only; not part of the node fork. +use kaspa_consensus_core::config::params::{devnet4_params, Params, MAINNET_PARAMS, TESTNET_PARAMS}; +use kaspa_consensus_core::emission::Tail; + +fn dump(name: &str, p: &Params) { + let t = p.emission.table(); + let s = p.emission; + let bps = p.bps(); + let tail = match s.tail { Tail::Cap => "cap".to_string(), Tail::Fixed { rate } => format!("fixed:{rate}"), Tail::Percent { bps_per_year } => format!("percent:{bps_per_year}") }; + println!( + "{{\"network\":\"{name}\",\"bps\":{bps},\"decimals\":{},\"launch_rate\":\"{}\",\"ramp_seconds\":{},\"ramp_start_percent\":{},\"step_seconds\":{},\"step_decay_q32\":{},\"tail\":\"{tail}\",\"steps\":{},\"genesis_daa_score\":{}}}", + p.base_unit_decimals, s.launch_rate, s.ramp_seconds, s.ramp_start_percent, s.step_seconds, s.step_decay_q32, t.step_rate.len(), p.genesis.daa_score + ); + if s.tail != Tail::Cap { + println!("{{\"network\":\"{name}\",\"note\":\"not a cap schedule; phases not dumped\"}}"); + return; + } + // the ramp: every block of DAA second sec pays block_subsidy(sec * bps); sum per DAA score + let mut ramp_sum: u128 = 0; + for sec in 0..s.ramp_seconds { + let a = t.block_subsidy(sec * bps, bps); + let b = t.block_subsidy(sec * bps + bps - 1, bps); + assert_eq!(a, b, "constant inside a DAA second"); + ramp_sum += a * bps as u128; + } + let first = t.block_subsidy(0, bps); + let last_ramp = t.block_subsidy(s.ramp_seconds * bps - 1, bps); + println!("{{\"network\":\"{name}\",\"phase\":\"ramp\",\"start_daa\":0,\"end_daa\":{},\"first_block\":\"{first}\",\"last_block\":\"{last_ramp}\",\"sum\":\"{ramp_sum}\"}}", s.ramp_seconds * bps); + let mut total = ramp_sum; + let mut k: u64 = 0; + loop { + let start = if k == 0 { s.ramp_seconds * bps } else { k * s.step_seconds * bps }; + let end = (k + 1) * s.step_seconds * bps; + let per = t.block_subsidy(start, bps); + let per_end = t.block_subsidy(end - 1, bps); + assert_eq!(per, per_end, "constant inside step {k}"); + let n = (end - start) as u128; + total += per * n; + println!("{{\"network\":\"{name}\",\"phase\":\"step\",\"k\":{k},\"start_daa\":{start},\"end_daa\":{end},\"per_block\":\"{per}\",\"rate_per_second\":\"{}\",\"sum\":\"{}\"}}", t.rate_at(start / bps), per * n); + if per == 0 { + // the terminal: zero at every later DAA score the table can reach + for probe in [end, end * 2, u64::MAX / bps * bps - 1, u64::MAX] { + assert_eq!(t.block_subsidy(probe, bps), 0); + } + println!("{{\"network\":\"{name}\",\"phase\":\"terminal\",\"start_daa\":{start},\"per_block\":\"0\"}}"); + break; + } + k += 1; + } + let cap = kaspa_consensus_core::igneum::supply_cap_units(p.base_unit_decimals); + println!("{{\"network\":\"{name}\",\"total\":\"{total}\",\"cap\":\"{cap}\",\"shortfall\":\"{}\"}}", cap - total); +} + +fn main() { + dump("mainnet", &MAINNET_PARAMS); + dump("devnet-4", &devnet4_params()); + dump("testnet-1", &TESTNET_PARAMS); +} diff --git a/tools/token-value/tv-01/gen-spec.py b/tools/token-value/tv-01/gen-spec.py new file mode 100644 index 000000000..c3ec7b7ae --- /dev/null +++ b/tools/token-value/tv-01/gen-spec.py @@ -0,0 +1,573 @@ +#!/usr/bin/env python3 +"""TV-01 (Igneum 2.0 Token Value, Phase 0): generates the machine-readable supply spec. + +Reads nothing it does not cite. The schedule constants are transcribed from the node fork's consensus crate and every +transcription is anchored: for each cited line the generator reads the file at each named revision (git show) and +refuses to write the spec when the line no longer carries its anchor text. The schedule is then computed here in exact +integers (Python ints), and, when --code-dump is given, compared field by field with the dump the consensus code's own +functions printed on the build box (tools/token-value/tv-01/code-dump/tv01_schedule.rs), so every figure in the spec is +one the code agrees with. + + python3 tools/token-value/tv-01/gen-spec.py \ + --node-git \ + --igneum-root . --igneum-rev 6824d49cc32def4463b643293a5622545618f7a9 \ + --code-dump tools/token-value/tv-01/code-dump/schedule-bf60948a.jsonl \ + --out docs/plans/igneum-2.0-master/token-value/phase0/tv-01/supply-spec.json \ + --md docs/plans/igneum-2.0-master/token-value/phase0/tv-01/supply-spec.md + +Deterministic: the same inputs give the same bytes. Nothing here activates anything. +""" +import argparse +import hashlib +import json +import subprocess +import sys + +NODE_REVS = { + "release-2.0.2-node": "a284380bdd62d5d0d972cb38f2cbd1daeedda69d", + "release-2.0.3-node-k6": "bf60948a01467bb54eaab9e50d32b91058f11242", +} + +# ---- The constants, as the code writes them (each one anchored below) ------------------------------------------- +YEAR_SECONDS = 31_557_600 # emission.rs:32 +LAUNCH_RATE_8 = 3_168_808_781 # emission.rs:104 (10^17 / 31,557,600 floored) +RAMP_SECONDS = 2_592_000 # emission.rs:105 +RAMP_START_PERCENT = 10 # emission.rs:106 +STEP_SECONDS = 2 * YEAR_SECONDS # emission.rs:107 +STEP_DECAY_Q32 = 1 << 31 # emission.rs:108 +DECIMALS = 18 # unit.rs:38, params.rs:1816 +UNIT = 10 ** DECIMALS +LAUNCH_RATE = LAUNCH_RATE_8 * 10 ** (DECIMALS - 8) # emission.rs rescaled(8, 18); params.rs:1858 +CAP = 4_000_000_000 * UNIT # igneum.rs:154 supply_cap_units(18) +PROVING_POOL_SHARE_PERCENT = 20 # igneum.rs:44 +SIGNING_BONUS_BPS = 1_000 # params.rs:1810 +DEVELOPER_SHARE_PERCENT = 20 # exec config (pgas.rs:290 reads it) +MAINNET_BPS = 10 # params.rs:1789 BlockrateParams::new::<10>() +DEVNET4_BPS = 1 # params.rs:2208 (DEVNET_PARAMS, inherited by devnet3/devnet4) +MAINNET_GENESIS_DAA_COMPILED = 1_312_860 # genesis.rs:92 + +# (id, repo, path, line, anchor text the line must contain) +CITATIONS = [ + ("year", "node", "consensus/core/src/emission.rs", 32, "pub const YEAR_SECONDS: u64 = 31_557_600;"), + ("current", "node", "consensus/core/src/emission.rs", 103, "pub const CURRENT: EmissionSchedule"), + ("launch_rate", "node", "consensus/core/src/emission.rs", 104, "launch_rate: 3_168_808_781"), + ("ramp_seconds", "node", "consensus/core/src/emission.rs", 105, "ramp_seconds: 2_592_000"), + ("ramp_start", "node", "consensus/core/src/emission.rs", 106, "ramp_start_percent: 10"), + ("step_seconds", "node", "consensus/core/src/emission.rs", 107, "step_seconds: 2 * YEAR_SECONDS"), + ("decay", "node", "consensus/core/src/emission.rs", 108, "step_decay_q32: 1 << 31"), + ("tail_cap", "node", "consensus/core/src/emission.rs", 109, "tail: Tail::Cap"), + ("testnet1", "node", "consensus/core/src/emission.rs", 116, "pub const TESTNET_1: EmissionSchedule"), + ("testnet1_tail", "node", "consensus/core/src/emission.rs", 122, "tail: Tail::Percent { bps_per_year: 100 }"), + ("decay_rule", "node", "consensus/core/src/emission.rs", 225, "rate = rate.saturating_mul(s.step_decay_q32 as u128) >> 32;"), + ("ramp_fn", "node", "consensus/core/src/emission.rs", 316, "pub fn ramp(&self, full: u128, seconds: u64) -> u128"), + ("block_subsidy", "node", "consensus/core/src/emission.rs", 329, "pub fn block_subsidy(&self, daa_score: u64, bps: u64) -> u128"), + ("per_block_div", "node", "consensus/core/src/emission.rs", 331, "let per_block = self.rate_at(seconds) / bps as u128;"), + ("cap_const", "node", "consensus/core/src/igneum.rs", 37, "pub const SUPPLY_CAP_SOMPI: u64 = 4_000_000_000 * SOMPI_PER_KASPA;"), + ("pool_share", "node", "consensus/core/src/igneum.rs", 44, "pub const PROVING_POOL_SHARE_PERCENT: u64 = 20;"), + ("silent_split", "node", "consensus/core/src/igneum.rs", 110, "pub fn silent_split_units("), + ("cap_units", "node", "consensus/core/src/igneum.rs", 154, "pub const fn supply_cap_units(decimals: u8) -> u128"), + ("pool_units", "node", "consensus/core/src/igneum.rs", 201, "pub fn proving_pool_share_units("), + ("producer_units", "node", "consensus/core/src/igneum.rs", 206, "pub fn producer_share_units("), + ("pool_script", "node", "consensus/core/src/igneum.rs", 213, "pub fn proving_pool_script_public_key()"), + ("evm_decimals", "node", "consensus/core/src/unit.rs", 38, "pub const EVM_DECIMALS: u8 = 18;"), + ("mainnet_deflationary", "node", "consensus/core/src/config/params.rs", 1783, "deflationary_phase_daa_score: 15778800 - 259200,"), + ("mainnet_pre_deflationary", "node", "consensus/core/src/config/params.rs", 1784, "pre_deflationary_phase_base_subsidy: 50000000000,"), + ("mainnet_bps", "node", "consensus/core/src/config/params.rs", 1789, "blockrate: BlockrateParams::new::<10>(),"), + ("mainnet_bonus_off", "node", "consensus/core/src/config/params.rs", 1809, "signing_bonus_activation_daa: u64::MAX,"), + ("mainnet_bonus_bps", "node", "consensus/core/src/config/params.rs", 1810, "signing_bonus_bps: 1_000,"), + ("mainnet_n8_off", "node", "consensus/core/src/config/params.rs", 1812, "subsidy_per_block_activation_daa: u64::MAX,"), + ("mainnet_decimals", "node", "consensus/core/src/config/params.rs", 1816, "base_unit_decimals: crate::unit::EVM_DECIMALS"), + ("mainnet_pool_split_off", "node", "consensus/core/src/config/params.rs", 1851, "pool_split_activation_daa: u64::MAX,"), + ("mainnet_emission", "node", "consensus/core/src/config/params.rs", 1858, "emission: EmissionSchedule::CURRENT.rescaled(crate::unit::DEVNET_DECIMALS, crate::unit::EVM_DECIMALS),"), + ("testnet_bonus_on", "node", "consensus/core/src/config/params.rs", 1955, "signing_bonus_activation_daa: 0,"), + ("testnet_n8_on", "node", "consensus/core/src/config/params.rs", 1960, "subsidy_per_block_activation_daa: 0,"), + ("testnet_emission", "node", "consensus/core/src/config/params.rs", 2014, "emission: EmissionSchedule::TESTNET_1.rescaled("), + ("devnet_bps", "node", "consensus/core/src/config/params.rs", 2208, "blockrate: BlockrateParams::new::<1>(),"), + ("devnet_n8_off", "node", "consensus/core/src/config/params.rs", 2232, "subsidy_per_block_activation_daa: u64::MAX,"), + ("devnet_pool_split_off", "node", "consensus/core/src/config/params.rs", 2270, "pool_split_activation_daa: u64::MAX,"), + ("devnet4_fn", "node", "consensus/core/src/config/params.rs", 2342, "pub fn devnet4_params() -> Params {"), + ("devnet4_emission", "node", "consensus/core/src/config/params.rs", 2372, "emission: EmissionSchedule::CURRENT.rescaled(crate::unit::DEVNET_DECIMALS, crate::unit::EVM_DECIMALS),"), + ("mainnet_genesis_daa", "node", "consensus/core/src/config/genesis.rs", 92, "daa_score: 1312860, // Checkpoint DAA score"), + ("genesis_no_outputs", "node", "consensus/core/src/config/genesis.rs", 26, "Transaction::new(0, Vec::new(), Vec::new(), 0, SUBNETWORK_ID_COINBASE"), + ("cb_header", "node", "consensus/src/processes/coinbase.rs", 31, "Kaspa's pre-deflationary phase, 426-month table and Crescendo `bps_history` rescaling are gone."), + ("cb_split", "node", "consensus/src/processes/coinbase.rs", 106, "fn producer_and_pool(&self, daa_score: u64, reward: &BlockRewardData)"), + ("cb_reds", "node", "consensus/src/processes/coinbase.rs", 152, "for red in ghostdag_data.mergeset_reds.iter()"), + ("cb_pool_output", "node", "consensus/src/processes/coinbase.rs", 163, "outputs.push(TransactionOutput::new_units(proving_pool_reward, igneum::proving_pool_script_public_key()));"), + ("cb_calc", "node", "consensus/src/processes/coinbase.rs", 262, "pub fn calc_block_subsidy(&self, daa_score: u64) -> Amount"), + ("cb_calc_body", "node", "consensus/src/processes/coinbase.rs", 265, "Amount(self.emission.block_subsidy(daa_score, self.bps))"), + ("utxo_retired", "node", "consensus/src/pipeline/body_processor/body_validation_in_isolation.rs", 54, "RuleError::UtxoTransactionsRetired"), + ("exec_blue_only", "node", "igneum/exec/src/executor.rs", 181, "for b in blocks.iter().filter(|b| b.is_blue)"), + ("exec_split", "node", "igneum/exec/src/executor.rs", 189, "silent_split_units(subsidy, b.silent, env.signing_bonus_bps)"), + ("exec_miner_credit", "node", "igneum/exec/src/executor.rs", 208, "db.add_balance(b.miner, producer_wei);"), + ("exec_pool_credit", "node", "igneum/exec/src/executor.rs", 211, "db.add_balance(PROVING_POOL_ADDRESS, pool_wei);"), + ("exec_tip_miner", "node", "igneum/exec/src/executor.rs", 362, "let tip_total = (gas_used as u128) * (price - env.base_fee_exec);"), + ("exec_dev_shares", "node", "igneum/exec/src/pgas.rs", 290, "pub fn developer_shares("), + ("pool_address", "node", "igneum/exec/src/config.rs", 59, "pub const PROVING_POOL_ADDRESS: Address"), + ("override_refused", "node", "kaspad/src/daemon.rs", None, "if network.params_compiled() {"), + ("params_compiled", "node", "consensus/core/src/network.rs", 266, "NetworkType::Mainnet | NetworkType::Testnet => true,"), + ("lp_cap", "igneum", "site/litepaper.html", 578, "Hard cap of 4 billion IGN, approached and never reached, because emission starts at 1 billion a year and halves every two years for ever."), + ("lp_caption", "igneum", "site/litepaper.html", 602, "3,938M IGN in the first 12 years of a 4,000M cap."), + ("lp_proving_pool", "igneum", "site/litepaper.html", 609, "is burned there"), + ("lp_tail", "igneum", "site/litepaper.html", 630, "One rule sits beside the cap. If external proving revenue is under one fifth of the block subsidy over any 90-day window after year 5, the question of a tail reward goes to the miners' signalling vote. The protocol never changes emission by itself."), + ("lp_no_tail", "igneum", "site/litepaper.html", 630, "The cap stays at 4 billion. There is no tail emission."), + ("lp_block_rate", "igneum", "site/litepaper.html", 542, "one block a second at launch with scheduled steps to four and ten"), + ("lp_unit", "igneum", "site/litepaper.html", 568, "the base unit is Open"), + ("lp_emission_route", "igneum", "site/litepaper.html", 620, "80% the block's miner, 20% the proving pool for the provers of that block"), + ("lp_tip_route", "igneum", "site/litepaper.html", 622, "80% the block's miner and provers; 20% the apps whose code ran, per call frame"), + ("lp_external_job", "igneum", "site/litepaper.html", 624, "90% the provers who delivered"), + ("lp_dev_fee", "igneum", "site/litepaper.html", 625, "1 block template in 100 requested with the dev address"), + ("lp_pool_custody", "igneum", "site/litepaper.html", 647, "The reference pool never holds a member"), + ("lp_per_block_figure", "igneum", "site/litepaper.html", 668, "31.688 IGN a block, 86,400 blocks a day"), + ("lp_mainnet_launch", "igneum", "site/litepaper.html", 775, "Genesis with no premine, 30-day ramp."), + ("pool_payout_doc", "igneum", "pool/src/payout.rs", 3, "so the pool receives"), + ("pool_fee_default", "igneum", "pool/src/config.rs", 58, "fee_percent: 1.0,"), + ("pool_distribute", "igneum", "pool/src/pplns.rs", 76, "pub fn distribute(reward_wei: u128, fee_percent: f64, payees: &[Payee])"), +] + + +def sh(cmd, cwd): + return subprocess.run(cmd, cwd=cwd, check=True, capture_output=True).stdout + + +def read_node(node_git, rev, path): + return sh(["git", "show", f"{rev}:{path}"], node_git) + + +def read_igneum(root, rev, path): + return sh(["git", "show", f"{rev}:{path}"], root) + + +def anchor(citations, node_git, igneum_root, igneum_rev): + """Every cited line must carry its anchor at every named revision; returns the resolved citation table and the + sha256 of every cited file per revision.""" + out, files = [], {} + for cid, repo, path, line, text in citations: + revs = NODE_REVS.items() if repo == "node" else [("igneum master", igneum_rev)] + lines_at = {} + for name, rev in revs: + blob = read_node(node_git, rev, path) if repo == "node" else read_igneum(igneum_root, rev, path) + files.setdefault(f"{repo}:{path}", {})[name] = hashlib.sha256(blob).hexdigest() + src = blob.decode("utf-8").split("\n") + if line is None: + hits = [i + 1 for i, l in enumerate(src) if text in l] + if len(hits) != 1: + sys.exit(f"anchor {cid}: {path} at {name} has {len(hits)} lines carrying {text!r}") + lines_at[name] = hits[0] + else: + if line > len(src) or text not in src[line - 1]: + sys.exit(f"anchor {cid}: {path}:{line} at {name} no longer carries {text!r}") + lines_at[name] = line + ref_lines = sorted(set(lines_at.values())) + out.append({"id": cid, "repo": repo, "path": path, "line": ref_lines[0] if len(ref_lines) == 1 else lines_at, + "anchor": text}) + return out, files + + +# ---- The schedule, in exact integers --------------------------------------------------------------------------- +def step_rate(k): + r = LAUNCH_RATE + for _ in range(k): + r = (r * STEP_DECAY_Q32) >> 32 + return r + + +def ramp(full, seconds): + if seconds >= RAMP_SECONDS: + return full + num = RAMP_START_PERCENT * RAMP_SECONDS + (100 - RAMP_START_PERCENT) * seconds + return full * num // (100 * RAMP_SECONDS) + + +def block_subsidy(daa, bps): + seconds = daa // bps + return ramp(step_rate(seconds // STEP_SECONDS) // bps, seconds) + + +def ramp_sum(bps, upto_seconds=RAMP_SECONDS): + full = LAUNCH_RATE // bps + return sum(ramp(full, s) for s in range(min(upto_seconds, RAMP_SECONDS))) * bps + + +def schedule(bps): + phases = [] + rs = ramp_sum(bps) + phases.append({ + "index": 0, "kind": "ramp", "rule": "launch-ramp", + "start_daa_score": 0, "end_daa_score": RAMP_SECONDS * bps, + "per_block_subsidy": None, + "ramp": {"full_per_block": str(LAUNCH_RATE // bps), "start_percent": RAMP_START_PERCENT, + "ramp_seconds": RAMP_SECONDS, "first_block": str(block_subsidy(0, bps)), + "last_block": str(block_subsidy(RAMP_SECONDS * bps - 1, bps)), + "formula": "per_block(d) = floor(full_per_block x (start_percent x ramp_seconds + (100 - start_percent) x s) / (100 x ramp_seconds)), s = floor(d / bps)"}, + "phase_sum": str(rs), + "source": ["consensus/core/src/emission.rs:316", "consensus/core/src/emission.rs:329"], + }) + k = 0 + while True: + start = RAMP_SECONDS * bps if k == 0 else k * STEP_SECONDS * bps + end = (k + 1) * STEP_SECONDS * bps + per = block_subsidy(start, bps) + assert per == block_subsidy(end - 1, bps) + if per == 0: + phases.append({ + "index": len(phases), "kind": "terminal", "rule": "terminal-zero", + "start_daa_score": start, "end_daa_score": None, "per_block_subsidy": "0", + "decay_step": k, "rate_per_second": str(step_rate(k)), "phase_sum": "0", + "source": ["consensus/core/src/emission.rs:109", "consensus/core/src/emission.rs:225", "consensus/core/src/emission.rs:331"], + }) + break + phases.append({ + "index": len(phases), "kind": "constant", + "rule": "full-rate-after-ramp" if k == 0 else f"halving-{k}", + "start_daa_score": start, "end_daa_score": end, "per_block_subsidy": str(per), + "decay_step": k, "rate_per_second": str(step_rate(k)), "phase_sum": str(per * (end - start)), + "source": ["consensus/core/src/emission.rs:107", "consensus/core/src/emission.rs:225", "consensus/core/src/emission.rs:331"], + }) + k += 1 + total = sum(int(p["phase_sum"]) for p in phases) + return phases, total + + +def supply_at(phases, daa, bps): + """Scheduled issuance over DAA scores [0, daa): one subsidy per DAA score (the replay model).""" + s = 0 + for p in phases: + a, b = p["start_daa_score"], p["end_daa_score"] + if daa <= a: + break + if p["kind"] == "ramp": + hi = min(daa, b) + full_secs, rem = divmod(hi, bps) + s += ramp_sum(bps, full_secs) + rem * block_subsidy(full_secs * bps, bps) + elif p["kind"] == "constant": + s += int(p["per_block_subsidy"]) * (min(daa, b) - a) + return s + + +def bps_step_overshoot(step_daa, from_bps, to_bps, total_to): + """The code keys time as daa / bps with ONE bps per network (coinbase.rs:31, :265). If the block rate stepped on a + live chain at `step_daa` with no history rule, every block from the step on would be paid as if the clock read + daa / to_bps: issuance = sum_{d < step} sub_from(d) + sum_{d >= step} sub_to(d).""" + ph_from, _ = schedule(from_bps) + ph_to, _ = schedule(to_bps) + issued = supply_at(ph_from, step_daa, from_bps) + (total_to - supply_at(ph_to, step_daa, to_bps)) + return issued + + +def coins(x): + q, r = divmod(x, UNIT) + return f"{q:,}.{r:018d}".rstrip("0").rstrip(".") + + +# ---- The conflicts and the texts ------------------------------------------------------------------------------ +TAIL_SENTENCE = ("One rule sits beside the cap. If external proving revenue is under one fifth of the block subsidy over " + "any 90-day window after year 5, the question of a tail reward goes to the miners' signalling vote. " + "The protocol never changes emission by itself.") + + +def conflicts(fig): + m, d = fig["mainnet"], fig["devnet-4"] + return [ + {"id": "C01", "topic": "cap versus the year-five tail vote", + "litepaper": {"line": 630, "words": TAIL_SENTENCE}, + "code": {"where": "consensus/core/src/emission.rs:109 (Tail::Cap in EmissionSchedule::CURRENT); consensus/core/src/config/params.rs:1858 (mainnet carries CURRENT); kaspad/src/daemon.rs (params_compiled refuses an override file on mainnet and testnet); no signal path reads or writes the emission schedule", + "value": "tail = cap; the schedule is a compiled genesis parameter; no vote, no revenue trigger, no tail"}, + "spec_takes": "the cap as the invariant; the tail-vote sentence is SUPERSEDED", + "why": "D01 (capped issuance, subject to TV-04), ratified by the founder 9 October 2026 09:2x UK; VR-01 (no unexplained tail escape, no price- or revenue-triggered issuance); the code already enforces only the capped schedule. If TV-04 shows capped security cannot pass, the volume's rule applies: delay launch or openly choose another design, never an undisclosed tail.", + "status": "RESOLVED (by D01, subject to TV-04)", + "follow_up": "the litepaper sentence is removed or replaced by the site lane; this landing does not edit site/"}, + {"id": "C02", "topic": "year-one emission and the twelve-year figure", + "litepaper": {"line": 578, "words": "emission starts at 1 billion a year", "line_2": 602, "words_2": "3,938M IGN in the first 12 years of a 4,000M cap."}, + "code": {"where": "consensus/core/src/emission.rs:104 to 106 (launch rate floored, the 30-day ramp from 10%)", + "value": f"year 1 issues {coins(m['year_1'])} IGN at 10 blocks/s ({coins(d['year_1'])} at 1 block/s); the first 12 years issue {coins(m['year_12'])} IGN"}, + "spec_takes": "the code's figures", + "why": "the litepaper chart and caption ignore the launch ramp's withheld 36,961,000 IGN and the floor of the per-second rate; the spec carries what nodes pay", + "status": "RESOLVED (text correction owed by the site lane)"}, + {"id": "C03", "topic": "terminal behaviour", + "litepaper": {"line": 578, "words": "halves every two years for ever"}, + "code": {"where": "consensus/core/src/emission.rs:225 (rate[k+1] = rate[k] x 2^31 >> 32, floored), :331 (per block = rate / bps, floored)", + "value": f"the per-block subsidy floors to zero at decay step {m['terminal_step']} (DAA score {m['terminal_daa']:,}, the start of year {m['terminal_year'] + 1}) at 10 blocks/s and at step {d['terminal_step']} (DAA score {d['terminal_daa']:,}, the start of year {d['terminal_year'] + 1}) at 1 block/s; zero for ever after"}, + "spec_takes": "the code: a finite schedule ending in a terminal zero phase", + "why": "integer halving ends; the last subsidy is 1 base unit (10^-18 IGN) per block; after it the security budget is fees alone (TV-04's question)", + "status": "RESOLVED (text correction owed: 'until the subsidy floors to zero')"}, + {"id": "C04", "topic": "block rate at launch and its steps", + "litepaper": {"line": 542, "words": "one block a second at launch with scheduled steps to four and ten", "line_2": 668, "words_2": "31.688 IGN a block, 86,400 blocks a day"}, + "code": {"where": "consensus/core/src/config/params.rs:1789 (mainnet BlockrateParams::new::<10>()); consensus/src/processes/coinbase.rs:31 (the bps_history rescaling is gone) and :265 (subsidy keyed on daa / ONE bps)", + "value": f"mainnet as compiled runs 10 blocks/s from genesis, 3.1688087810 IGN a block; the subsidy has no block-rate history, so a step from 1 to 10 blocks/s at DAA score {fig['bps_step']['step_daa']:,} (one year in) would issue {coins(fig['bps_step']['issued'])} IGN in all, an overshoot of {coins(fig['bps_step']['issued'] - CAP)} IGN over the cap"}, + "spec_takes": "both profiles (10 blocks/s as compiled; 1 block/s as Devnet 4), identical per second; NO live block-rate step is cap-safe under the current code", + "why": "a block-rate step re-keys the schedule clock (seconds = daa / bps) and re-pays elapsed time", + "status": "BLOCKED", + "question": "For the founder: does mainnet launch at the compiled 10 blocks a second (the litepaper's 1-to-4-to-10 step plan removed), or at 1 with steps (then the node lane adds a block-rate-history subsidy rule before genesis, and TV-02 replays a step)? Default if unanswered: the spec freezes the compiled 10 blocks a second and the step plan is treated as text to correct."}, + {"id": "C05", "topic": "unit", + "litepaper": {"line": 568, "words": "the base unit is Open"}, + "code": {"where": "consensus/core/src/unit.rs:38; consensus/core/src/config/params.rs:1816", + "value": "18 decimals on mainnet, testnet and Devnet 4: 1 IGN = 10^18 base units; one base unit is one EVM wei"}, + "spec_takes": "18 decimals", + "why": "decided 6 October 2026 (O-2.6) and compiled; the cap is 4 x 10^27 base units", + "status": "RESOLVED (text correction owed)"}, + {"id": "C06", "topic": "where the 20% proving share goes, and which ledger is native supply", + "litepaper": {"line": 609, "words": "the coinbase's 20% output goes to an unspendable script tagged igneum-proving-pool-v0 and is burned there. Provers are paid from a separate escrow in the execution state"}, + "code": {"where": "consensus/src/processes/coinbase.rs:163 (UTXO pool output to the OP_RETURN script); consensus/src/pipeline/body_processor/body_validation_in_isolation.rs:54 (no UTXO transaction but the coinbase: UTXO outputs can never be spent); igneum/exec/src/executor.rs:181 to 211 (the EVM state credits 80% to the producer and 20% to the escrow 0x...0220 for every blue block)", + "value": "two ledgers record each subsidy: the UTXO coinbase (unspendable by rule) and the EVM state (spendable)"}, + "spec_takes": "native supply is the EVM state's credit; the UTXO coinbase is a non-spendable shadow record and its OP_RETURN 20% is NOT a burn of native supply; the escrow balance is issued and locked until paid per proof", + "why": "counting both ledgers doubles supply; counting the OP_RETURN as burned and the escrow as issued would understate and overstate at once (VR-02)", + "status": "RESOLVED (for the spec; TV-02 reconciles both ledgers to this rule)"}, + {"id": "C07", "topic": "red blocks", + "litepaper": {"line": 620, "words": "80% the block's miner, 20% the proving pool for the provers of that block"}, + "code": {"where": "consensus/src/processes/coinbase.rs:152 to 159 (the UTXO coinbase pays a DAA red block's subsidy to the merging miner and the pool); igneum/exec/src/executor.rs:181 (the EVM credits blue blocks only)", + "value": "a red block's subsidy exists on the shadow ledger and not in native supply"}, + "spec_takes": "native issuance = the blue blocks' subsidies; the per-DAA-score schedule sum is the upper bound", + "why": "the EVM ledger is native supply (C06); the bound keeps the cap invariant whatever the red share", + "status": "RESOLVED (TV-02 measures the red share; no text change needed beyond 'blue block')"}, + {"id": "C08", "topic": "which DAA score a merged block is credited at", + "litepaper": {"line": None, "words": "(silent)"}, + "code": {"where": "consensus/core/src/config/params.rs:1812 (mainnet subsidy_per_block_activation_daa = never), :2232 (Devnet 4 inherits never), :1960 (testnet-1: 0)", + "value": "on mainnet and Devnet 4 the EVM credits a merged block the merging chain block's subsidy while the UTXO coinbase pays the block's own: one ramp second high per merged block, a whole halving step at a boundary"}, + "spec_takes": "each block's own DAA score (ledger N8) as the normative rule", + "why": "exact integer agreement between ledgers and replays (TV-02) needs one rule; N8 is the one the testnet object already carries", + "status": "BLOCKED", + "question": "For the founder (the node lane owns the change): set subsidy_per_block_activation_daa = 0 in the mainnet object, as testnet-1 has it? Default if unanswered: the spec keeps N8 as normative and TV-02 reports the chain-block reading as a measured divergence."}, + {"id": "C09", "topic": "the mainnet genesis clock", + "litepaper": {"line": 775, "words": "Genesis with no premine, 30-day ramp."}, + "code": {"where": "consensus/core/src/config/genesis.rs:92 (mainnet GENESIS daa_score 1312860, Kaspa's 2021 timestamp); the subsidy reads the absolute DAA score (emission.rs:329)", + "value": f"as compiled, the first mainnet block would sit 131,286 DAA seconds into the ramp (paying {fig['genesis_offset']['first_ramp_percent']} of full rate, not 10%) and the whole schedule would run 1.52 days early; issuance would be {coins(fig['genesis_offset']['issuance_lost'])} IGN lower"}, + "spec_takes": "genesis at DAA score 0 (as Devnet 4 and testnet-1); the activation clocks below are counted from it", + "why": "the mainnet genesis is a Kaspa placeholder not yet cut; every Igneum network so far starts at DAA score 0", + "status": "BLOCKED", + "question": "For the founder: confirm the mainnet genesis is cut at DAA score 0. Default if unanswered: the spec freezes DAA score 0 and the genesis cut is checked against it."}, + {"id": "C10", "topic": "priority fee to provers", + "litepaper": {"line": 622, "words": "80% the block's miner and provers; 20% the apps whose code ran, per call frame"}, + "code": {"where": "igneum/exec/src/executor.rs:362 to 371 (the tip less the developer share is credited to the block's miner alone); igneum/exec/src/pgas.rs:290 (20% developer share, unregistered parts burned)", + "value": "80% to the block's miner, none to provers; 20% to registered payees or burned"}, + "spec_takes": "the code", + "why": "fees move existing supply and burn some; they never create supply", + "status": "RESOLVED (text correction owed: drop 'and provers')"}, + {"id": "C11", "topic": "the reference pool's custody and fee", + "litepaper": {"line": 647, "words": "The reference pool never holds a member’s balance. Payouts come straight from the coinbase split"}, + "code": {"where": "pool/src/payout.rs:1 to 6 (the pool's address receives the 80% and pays members by transfers); pool/src/config.rs:58 (fee_percent 1.0); pool/src/pplns.rs:76; consensus/core/src/config/params.rs:1851 (mainnet pool_split_activation_daa = never: the IGNW coinbase split is off)", + "value": "the reference pool holds members' balances between rounds and keeps a 1% fee; the consensus split that would make the sentence true is off on mainnet and Devnet 4"}, + "spec_takes": "the code (custodial PPLNS, 1% default fee, no supply effect)", + "why": "the payout route moves issued supply; it creates none", + "status": "BLOCKED", + "question": "For the founder: activate the IGNW coinbase split at mainnet genesis (pool_split_activation_daa = 0) so the litepaper sentence holds, or change the sentence to the custodial PPLNS pool with its 1% fee? Default if unanswered: the sentence is corrected to the code."}, + {"id": "C12", "topic": "a tail schedule compiled into testnet-1", + "litepaper": {"line": 630, "words": "The cap stays at 4 billion. There is no tail emission."}, + "code": {"where": "consensus/core/src/emission.rs:116 to 122 (TESTNET_1: 100 IGN a block, monthly glide, a 1% a year tail); consensus/core/src/config/params.rs:2014 (testnet-1 carries it)", + "value": "the held testnet-1 object issues without a cap"}, + "spec_takes": "not the monetary contract: the contract is EmissionSchedule::CURRENT with Tail::Cap", + "why": "D01; the testnet is held and superseded by 2.0; a revived testnet carries CURRENT or is labelled a different supply proposition", + "status": "RESOLVED (by D01)"}, + {"id": "C13", "topic": "dead Kaspa subsidy fields in the mainnet object", + "litepaper": {"line": None, "words": "(silent)"}, + "code": {"where": "consensus/core/src/config/params.rs:1783 to 1784 (deflationary_phase_daa_score 15,519,600; pre_deflationary_phase_base_subsidy 50,000,000,000)", + "value": "read only into the consensus digest; the subsidy never reads them (coinbase.rs:31)"}, + "spec_takes": "ignored: they are not part of the monetary contract", + "why": "a reader grepping 'deflationary' would otherwise find a second schedule that does not exist", + "status": "RESOLVED (the node lane may annotate or remove them at the genesis cut)"}, + ] + + +def main(): + ap = argparse.ArgumentParser() + ap.add_argument("--node-git", required=True) + ap.add_argument("--igneum-root", required=True) + ap.add_argument("--igneum-rev", default="HEAD") + ap.add_argument("--code-dump") + ap.add_argument("--out", required=True) + ap.add_argument("--md") + a = ap.parse_args() + + igneum_rev = sh(["git", "rev-parse", a.igneum_rev], a.igneum_root).decode().strip() + cites, files = anchor(CITATIONS, a.node_git, a.igneum_root, igneum_rev) + + profiles, fig = [], {} + for name, network, bps in [("mainnet", "mainnet (MAINNET_PARAMS as compiled)", MAINNET_BPS), ("devnet-4", "Devnet 4 (devnet4_params, 1 block a second, the litepaper's launch rate)", DEVNET4_BPS)]: + phases, total = schedule(bps) + term = phases[-1] + f = { + "year_1": supply_at(phases, YEAR_SECONDS * bps, bps), + "year_12": supply_at(phases, 12 * YEAR_SECONDS * bps, bps), + "terminal_step": term["decay_step"], "terminal_daa": term["start_daa_score"], + "terminal_year": term["start_daa_score"] // bps // YEAR_SECONDS, + "total": total, + } + fig[name] = f + years = {} + for y in [1, 2, 5, 10, 12, 20, 50, 100]: + years[str(y)] = str(supply_at(phases, y * YEAR_SECONDS * bps, bps)) + last_nonzero = phases[-2] + profiles.append({ + "profile": name, "network": network, "bps": bps, "decimals": DECIMALS, + "genesis_daa_score": 0, + "time_key": "seconds = floor(daa_score / bps); the per-block subsidy is constant inside a DAA second", + "phases": phases, + "phase_count": len(phases), + "last_nonzero_phase": {"index": last_nonzero["index"], "per_block_subsidy": last_nonzero["per_block_subsidy"], + "start_daa_score": last_nonzero["start_daa_score"], "end_daa_score": last_nonzero["end_daa_score"]}, + "terminal": {"start_daa_score": term["start_daa_score"], "decay_step": term["decay_step"], + "start_year": f["terminal_year"], "behaviour": "per-block subsidy 0 at every later DAA score; the cap is never reached; blocks are paid by fees alone"}, + "total_issuance": str(total), + "cap_shortfall": str(CAP - total), + "scheduled_supply_at_year_end": years, + }) + + # the block-rate step demonstration (C04) and the compiled genesis offset (C09) + step_daa = YEAR_SECONDS * DEVNET4_BPS + fig["bps_step"] = {"step_daa": step_daa, "issued": bps_step_overshoot(step_daa, 1, 10, fig["mainnet"]["total"])} + ph10, _ = schedule(MAINNET_BPS) + off = MAINNET_GENESIS_DAA_COMPILED + s0 = off // MAINNET_BPS + num = RAMP_START_PERCENT * RAMP_SECONDS + (100 - RAMP_START_PERCENT) * s0 + fig["genesis_offset"] = {"issuance_lost": supply_at(ph10, off, MAINNET_BPS), + "first_ramp_percent": f"{num * 100 // (100 * RAMP_SECONDS)}.{(num * 10000 // (100 * RAMP_SECONDS)) % 100:02d}%"} + + dump_check = None + if a.code_dump: + raw = open(a.code_dump, "rb").read() + rows = [json.loads(l) for l in raw.decode().splitlines() if l.strip()] + n = 0 + for prof in profiles: + net = prof["profile"] + head = next(r for r in rows if r.get("network") == net and "bps" in r) + assert head["bps"] == prof["bps"] and head["decimals"] == DECIMALS and int(head["launch_rate"]) == LAUNCH_RATE + assert head["ramp_seconds"] == RAMP_SECONDS and head["step_seconds"] == STEP_SECONDS and head["step_decay_q32"] == STEP_DECAY_Q32 and head["tail"] == "cap" + rp = next(r for r in rows if r.get("network") == net and r.get("phase") == "ramp") + p0 = prof["phases"][0] + assert int(rp["sum"]) == int(p0["phase_sum"]) and rp["first_block"] == p0["ramp"]["first_block"] and rp["last_block"] == p0["ramp"]["last_block"] and rp["end_daa"] == p0["end_daa_score"] + steps = [r for r in rows if r.get("network") == net and r.get("phase") == "step"] + for r, p in zip(steps, prof["phases"][1:]): + assert r["start_daa"] == p["start_daa_score"], (net, r, p) + assert r["per_block"] == p["per_block_subsidy"], (net, r, p) + assert int(r["rate_per_second"]) == int(p["rate_per_second"]), (net, r, p) + if p["kind"] == "constant": + assert r["end_daa"] == p["end_daa_score"] and r["sum"] == p["phase_sum"], (net, r, p) + n += 1 + assert len(steps) == len(prof["phases"]) - 1, (net, len(steps), len(prof["phases"])) + tot = next(r for r in rows if r.get("network") == net and "total" in r) + assert int(tot["total"]) == int(prof["total_issuance"]) and int(tot["cap"]) == CAP and int(tot["shortfall"]) == int(prof["cap_shortfall"]) + assert head["genesis_daa_score"] == (MAINNET_GENESIS_DAA_COMPILED if net == "mainnet" else 0) + t1 = next(r for r in rows if r.get("network") == "testnet-1" and "bps" in r) + assert t1["tail"] == "percent:100" + dump_check = {"path": "tools/token-value/tv-01/code-dump/schedule-bf60948a.jsonl", "sha256": hashlib.sha256(raw).hexdigest(), + "program": "tools/token-value/tv-01/code-dump/tv01_schedule.rs", + "run": "build-9, release-2.0.3-node-k6 bf60948a: cargo run --release -p kaspa-consensus-core --example tv01_schedule (the program copied into consensus/core/examples of a scratch tree; the node fork is unchanged)", + "agreement": f"every field of {n} decay phases, both ramps and both totals equal to this generator's integers"} + + spec = { + "schema": { + "name": "igneum-supply-spec", "version": "1.0.0", + "integers": "every amount is a decimal string of base units (amounts reach 4 x 10^27, past JSON's exact range); DAA scores are JSON integers (all under 2^53)", + "phase_fields": {"index": "0-based, contiguous", "kind": "ramp | constant | terminal", "rule": "the rule's name", "start_daa_score": "inclusive", "end_daa_score": "exclusive; null for the terminal phase", "per_block_subsidy": "base units per block at every DAA score of the phase (null for the ramp, whose per-block value is its formula)", "phase_sum": "base units the phase issues at one subsidy per DAA score", "source": "file:line in the node fork at both named revisions"}, + "checker": "tools/token-value/tv-01/check-spec.py", + }, + "gate": "TV-01", "verdict": "NOT RUN", + "status": "Phase 0 document. Activates nothing; changes no node, no chain and no served page. The verdict stays NOT RUN until the independent panel reads it.", + "decision": {"id": "D01", "title": "Cap and tail", "ruling": "capped issuance, subject to TV-04 (the founder's ratification, 9 October 2026, 09:2x UK)", + "effect": "the cap is the invariant; the litepaper's year-five tail-vote sentence is superseded (C01)"}, + "invariant": {"rule": "sum over all blocks of the per-block subsidy <= cap, with no tail, no vote, no price or revenue trigger and no emergency mint", + "how_enforced": "by the schedule, not by a running counter: every block's coinbase must carry exactly the scheduled subsidy (coinbase.rs:262) and the EVM state credits by the same rule (executor.rs:181 to 211); the cap constant itself is only compared in tests (igneum.rs:154). The schedule sums to the cap minus the shortfall below, so the cap is never reached.", + "change_policy": "the schedule is a compiled genesis parameter on mainnet; the daemon refuses an override file there (kaspad/src/daemon.rs, network.rs:266); a change is a new release with a new consensus digest and an explicit incompatible-policy process (VR-06)"}, + "units": {"coin": "IGN", "base_unit": "wei (one consensus base unit is one EVM wei)", "decimals": DECIMALS, "base_units_per_coin": str(UNIT), + "source": ["consensus/core/src/unit.rs:38", "consensus/core/src/config/params.rs:1816"]}, + "cap": {"base_units": str(CAP), "coins": "4000000000", "kind": "invariant", + "source": ["consensus/core/src/igneum.rs:37", "consensus/core/src/igneum.rs:154"]}, + "rules": { + "launch_rate_per_second": str(LAUNCH_RATE), "launch_rate_note": "floor(10^9 x 10^8 / 31,557,600) = 3,168,808,781 at 8 decimals, times 10^10: 31.68808781 IGN a DAA second", + "year_seconds": YEAR_SECONDS, "ramp_seconds": RAMP_SECONDS, "ramp_start_percent": RAMP_START_PERCENT, + "step_seconds": STEP_SECONDS, "step_decay_q32": STEP_DECAY_Q32, "decay_rule": "rate[k+1] = floor(rate[k] x step_decay_q32 / 2^32) (a halving every two years)", + "per_block": "per_block(d) = ramp(floor(rate[floor(s / step_seconds)] / bps), s), s = floor(d / bps)", + "tail": "cap", + "source": ["consensus/core/src/emission.rs:103 to 110", "consensus/core/src/emission.rs:225", "consensus/core/src/emission.rs:316 to 333", "consensus/core/src/config/params.rs:1858"], + }, + "activation_clocks": { + "genesis": "DAA score 0 (C09: the compiled mainnet genesis still carries Kaspa's 1,312,860; BLOCKED)", + "ramp_end": {"mainnet": RAMP_SECONDS * MAINNET_BPS, "devnet-4": RAMP_SECONDS * DEVNET4_BPS, "seconds": RAMP_SECONDS}, + "halvings": "every 63,115,200 DAA seconds (2 years of 365.25 days): DAA score k x 631,152,000 at 10 blocks/s, k x 63,115,200 at 1 block/s", + "terminal": {"mainnet": fig["mainnet"]["terminal_daa"], "devnet-4": fig["devnet-4"]["terminal_daa"]}, + "signing_bonus": "mainnet never (params.rs:1809); testnet-1 from 0", + "pool_split": "mainnet never (params.rs:1851)", + "per_block_rule_N8": "mainnet never (params.rs:1812; C08 BLOCKED); testnet-1 from 0", + }, + "schedules": profiles, + "coinbase_split": [ + {"rule": "producer and proving pool", "producer": "subsidy - floor(subsidy x 20 / 100)", "proving_pool": "floor(subsidy x 20 / 100)", "source": ["consensus/core/src/igneum.rs:44", "consensus/core/src/igneum.rs:201 to 208"]}, + {"rule": "signing bonus", "effect": "a silent producer's share loses floor(share x 1,000 / 10,000) to the proving pool; nothing destroyed; fees untouched", "mainnet": "off (never)", "source": ["consensus/core/src/igneum.rs:110", "consensus/core/src/config/params.rs:1809 to 1810"]}, + {"rule": "native ledger", "effect": "the EVM state credits the producer share to the block's IGNA address (or by its IGNW split once pool_split is active) and the pool share to escrow 0x0000000000000000000000000000000000000220, blue blocks only", "source": ["igneum/exec/src/executor.rs:181 to 211", "igneum/exec/src/config.rs:59"]}, + {"rule": "shadow ledger", "effect": "the UTXO coinbase pays the producer outputs and one OP_RETURN pool output tagged igneum-proving-pool-v0; no UTXO transaction but the coinbase is valid, so none of it is ever spent", "source": ["consensus/src/processes/coinbase.rs:126 to 168", "consensus/src/pipeline/body_processor/body_validation_in_isolation.rs:54"]}, + {"rule": "pool", "effect": "none in consensus; the reference pool keeps fee_percent (default 1.0) of the 80% it receives and pays members PPLNS from its address", "source": ["pool/src/payout.rs:1 to 6", "pool/src/config.rs:58", "pool/src/pplns.rs:76"]}, + {"rule": "dev fee", "effect": "none in consensus; the miner software requests 1 template in 100 with the dev address (off with --dev-fee 0); it moves the producer share of those blocks, creates nothing", "source": ["site/litepaper.html:625"]}, + {"rule": "treasury, foundation, team, stake", "effect": "none: no output, credit or address in consensus", "source": ["consensus/src/processes/coinbase.rs:126 to 168", "igneum/exec/src/executor.rs:181 to 211"]}, + {"rule": "genesis", "effect": "the genesis coinbase has no outputs; its payload subsidy field is data; no premine", "source": ["consensus/core/src/config/genesis.rs:26"]}, + ], + "fees": [ + {"route": "execution base fee", "effect": "burned (not credited)", "source": "igneum/exec/src/executor.rs:319 to 321"}, + {"route": "proving charge", "effect": "burned", "source": "igneum/exec/src/executor.rs:319 to 321"}, + {"route": "priority fee", "effect": "80% to the block's miner; 20% to the payees registered for the frames' code by own gas, unregistered parts burned", "source": "igneum/exec/src/executor.rs:362 to 371; igneum/exec/src/pgas.rs:290"}, + {"route": "external job after the proof bridge", "effect": "not in code (Designed, phase two): 90% provers, 10% burned per the litepaper", "source": "site/litepaper.html:624"}, + ], + "supply_accounting": { + "issued": "the EVM state's subsidy credits (producer plus escrow), blue blocks only; bounded above by the schedule's per-DAA-score sum", + "burned": "execution base fees, proving charges and unregistered developer shares (EVM side); the UTXO OP_RETURN output is NOT counted as a burn (C06)", + "locked": "the proving escrow's balance: credited, not yet paid against a valid proof; unclaimed credit is stranded today (litepaper line 609, no rule returns it)", + "not_supply": "UTXO coinbase outputs (unspendable shadow record); any bridged or wrapped IGN on another chain (VR-02)", + "replay_model": "one scheduled subsidy per DAA score (the schedules above); a block is paid at its own DAA score, parallel blocks may share a score and a score may have no block, so the measured issuance differs from the model only near phase boundaries and only by the blocks merged across them; TV-02 reconciles the measured ledgers to this model in exact integers", + }, + "superseded": [{"text": TAIL_SENTENCE, "where": "site/litepaper.html:630", "by": "D01 (capped issuance, subject to TV-04)", "status": "SUPERSEDED"}], + "conflicts": conflicts(fig), + "sources": { + "volume": {"path": "docs/plans/igneum-2.0-master/token-value/rules-and-gates.json", "sha256": hashlib.sha256(read_igneum(a.igneum_root, igneum_rev, "docs/plans/igneum-2.0-master/token-value/rules-and-gates.json")).hexdigest()}, + "litepaper": {"path": "site/litepaper.html", "igneum_commit": igneum_rev, "sha256": files["igneum:site/litepaper.html"]["igneum master"]}, + "node": {"repo": "igneum-node (build-1:/srv/igneum-node.git)", "revisions": NODE_REVS, + "files": {k.split(":", 1)[1]: v for k, v in sorted(files.items()) if k.startswith("node:")}, + "note": "every cited node file is byte-identical at both revisions except kaspad/src/daemon.rs, whose override refusal is the same rule at both"}, + "pool": {k.split(":", 1)[1]: v["igneum master"] for k, v in sorted(files.items()) if k.startswith("igneum:pool/")}, + "citations": cites, + "code_dump": dump_check, + }, + "generator": {"path": "tools/token-value/tv-01/gen-spec.py", + "command": "python3 tools/token-value/tv-01/gen-spec.py --node-git --igneum-root . --igneum-rev " + igneum_rev + " --code-dump tools/token-value/tv-01/code-dump/schedule-bf60948a.jsonl --out docs/plans/igneum-2.0-master/token-value/phase0/tv-01/supply-spec.json --md docs/plans/igneum-2.0-master/token-value/phase0/tv-01/supply-spec.md"}, + } + # every litepaper quote in the conflicts table is exact (tags stripped, entities decoded) or nothing is written + import html as _html, re as _re + lp = read_igneum(a.igneum_root, igneum_rev, "site/litepaper.html").decode("utf-8").split("\n") + for c in spec["conflicts"]: + for lk, wk in (("line", "words"), ("line_2", "words_2")): + ln = c["litepaper"].get(lk) + if ln and c["litepaper"][wk] not in _html.unescape(_re.sub("<[^>]+>", "", lp[ln - 1])): + sys.exit(f"{c['id']}: the litepaper's line {ln} does not carry the quoted words exactly") + with open(a.out, "w", encoding="utf-8") as fh: + json.dump(spec, fh, indent=1, ensure_ascii=False) + fh.write("\n") + + if a.md: + m, d = profiles[0], profiles[1] + L = ["", ""] + L.append("| Figure | Mainnet as compiled (10 blocks/s) | Devnet 4 (1 block/s) |") + L.append("|---|---|---|") + L.append(f"| Cap | {coins(CAP)} IGN ({CAP} base units) | the same |") + L.append(f"| Total scheduled issuance | {coins(int(m['total_issuance']))} IGN | {coins(int(d['total_issuance']))} IGN |") + L.append(f"| Shortfall under the cap (exact) | {m['cap_shortfall']} base units ({coins(int(m['cap_shortfall']))} IGN) | {d['cap_shortfall']} base units ({coins(int(d['cap_shortfall']))} IGN) |") + L.append(f"| Ramp phase | DAA 0 to {m['phases'][0]['end_daa_score']:,}, {coins(int(m['phases'][0]['phase_sum']))} IGN | DAA 0 to {d['phases'][0]['end_daa_score']:,}, {coins(int(d['phases'][0]['phase_sum']))} IGN |") + L.append(f"| First block | {coins(int(m['phases'][0]['ramp']['first_block']))} IGN | {coins(int(d['phases'][0]['ramp']['first_block']))} IGN |") + L.append(f"| Full-rate block (after the ramp) | {coins(int(m['phases'][1]['per_block_subsidy']))} IGN | {coins(int(d['phases'][1]['per_block_subsidy']))} IGN |") + L.append(f"| Phases (ramp, constant, terminal) | {m['phase_count']} | {d['phase_count']} |") + L.append(f"| Last non-zero subsidy | {m['last_nonzero_phase']['per_block_subsidy']} base unit a block, DAA {m['last_nonzero_phase']['start_daa_score']:,} to {m['last_nonzero_phase']['end_daa_score']:,} | {d['last_nonzero_phase']['per_block_subsidy']} base unit a block, DAA {d['last_nonzero_phase']['start_daa_score']:,} to {d['last_nonzero_phase']['end_daa_score']:,} |") + L.append(f"| Terminal (zero for ever) from | DAA {m['terminal']['start_daa_score']:,} (decay step {m['terminal']['decay_step']}, year {m['terminal']['start_year'] + 1}) | DAA {d['terminal']['start_daa_score']:,} (decay step {d['terminal']['decay_step']}, year {d['terminal']['start_year'] + 1}) |") + for y in ["1", "2", "5", "10", "12", "20", "50", "100"]: + L.append(f"| Scheduled supply at the end of year {y} | {coins(int(m['scheduled_supply_at_year_end'][y]))} IGN | {coins(int(d['scheduled_supply_at_year_end'][y]))} IGN |") + L.append(f"| A 1-to-10 blocks/s step at DAA {fig['bps_step']['step_daa']:,} under the current code | total {coins(fig['bps_step']['issued'])} IGN, {coins(fig['bps_step']['issued'] - CAP)} IGN over the cap | |") + L.append(f"| The compiled mainnet genesis (DAA 1,312,860) | first ramp block at {fig['genesis_offset']['first_ramp_percent']}; {coins(fig['genesis_offset']['issuance_lost'])} IGN never scheduled | |") + L.append("") + if dump_check: + L.append(f"Code agreement: {dump_check['agreement']} (dump sha256 `{dump_check['sha256']}`).") + L.append("") + L.append("") + txt = open(a.md).read() + b, e = txt.index("") + len("") + with open(a.md, "w") as fh: + fh.write(txt[:b] + "\n".join(L) + txt[e:]) + print(f"wrote {a.out}: mainnet total {fig['mainnet']['total']}, shortfall {CAP - fig['mainnet']['total']}; devnet-4 total {fig['devnet-4']['total']}; code dump {'agrees' if dump_check else 'not given'}") + + +if __name__ == "__main__": + main() From 7e7ccc190f0782d74757c8744d876661a1adbd84 Mon Sep 17 00:00:00 2001 From: igneum-labs <337424239+igneum-labs@users.noreply.github.com> Date: Fri, 9 Oct 2026 08:36:38 +0000 Subject: [PATCH 2/9] TV-01: the genesis rule and the terminal fields TV-02 reads; C10 resolved by O-5.7; the registry batch kept beside the spec Genesis is never rewarded (window.rs:177, coinbase.rs:139, genesis.rs:26), so block height h carries DAA score h - 1; each profile now carries transition_count, last_paying_daa_score, last_paying_block_height and terminal_supply (Devnet 4: 66 transitions, last paying block at height 4,102,488,000, terminal supply 3,963,038,999.610200483289816 IGN), and the checker refuses a spec whose terminal fields disagree. C10 (tip to provers) is resolved by spec 05 section 5.2's closed O-5.7. The batch moved out of tools/ci/batches/ because the test map has no token-value cell for the replay; the CI steward records it. Co-Authored-By: Claude Opus 5.5 --- .../token-value/phase0/tv-01/README.md | 1 + .../registry-batch-tv-01-20261009-01.json | 0 .../token-value/phase0/tv-01/supply-spec.json | 58 ++++++++++++++++++- .../token-value/phase0/tv-01/supply-spec.md | 3 +- tools/token-value/tv-01/check-spec.py | 5 ++ tools/token-value/tv-01/gen-spec.py | 20 +++++-- 6 files changed, 79 insertions(+), 8 deletions(-) rename tools/ci/batches/tv-01-20261009-01.json => docs/plans/igneum-2.0-master/token-value/phase0/tv-01/registry-batch-tv-01-20261009-01.json (100%) diff --git a/docs/plans/igneum-2.0-master/token-value/phase0/tv-01/README.md b/docs/plans/igneum-2.0-master/token-value/phase0/tv-01/README.md index 1512dd89e..2fd632b9d 100644 --- a/docs/plans/igneum-2.0-master/token-value/phase0/tv-01/README.md +++ b/docs/plans/igneum-2.0-master/token-value/phase0/tv-01/README.md @@ -10,6 +10,7 @@ Gate TV-01 ("Resolve and freeze the monetary contract", rules-and-gates.json sha | `supply-spec.md` | the same in words, with the conflicts table, the D01 resolution and the founder's four questions | | `../../../../../../tools/token-value/tv-01/gen-spec.py` | the generator; every figure in both files is its output | | `../../../../../../tools/token-value/tv-01/check-spec.py` | the checker: four known-failed cases first, then the spec summed to the cap in exact integers | +| `registry-batch-tv-01-20261009-01.json` | the registry batch for the CI steward (TV-01 NOT RUN with the evidence paths); kept here, not under tools/ci/batches/, because the map has no token-value cell until the steward adds one | | `../../../../../../tools/token-value/tv-01/code-dump/` | the consensus code's own schedule (`tv01_schedule.rs`, run on build-9 against bf60948a) and its output, `schedule-bf60948a.jsonl` (sha256 `3e4b5ac3c2f43057a13ace7d781ad714e385a94105623c0e0dac4adc417d8056`) | ## Sources diff --git a/tools/ci/batches/tv-01-20261009-01.json b/docs/plans/igneum-2.0-master/token-value/phase0/tv-01/registry-batch-tv-01-20261009-01.json similarity index 100% rename from tools/ci/batches/tv-01-20261009-01.json rename to docs/plans/igneum-2.0-master/token-value/phase0/tv-01/registry-batch-tv-01-20261009-01.json diff --git a/docs/plans/igneum-2.0-master/token-value/phase0/tv-01/supply-spec.json b/docs/plans/igneum-2.0-master/token-value/phase0/tv-01/supply-spec.json index 7a4fadbd5..d85ba2831 100644 --- a/docs/plans/igneum-2.0-master/token-value/phase0/tv-01/supply-spec.json +++ b/docs/plans/igneum-2.0-master/token-value/phase0/tv-01/supply-spec.json @@ -59,6 +59,16 @@ "decay_rule": "rate[k+1] = floor(rate[k] x step_decay_q32 / 2^32) (a halving every two years)", "per_block": "per_block(d) = ramp(floor(rate[floor(s / step_seconds)] / bps), s), s = floor(d / bps)", "tail": "cap", + "genesis_rule": { + "rule": "genesis-unrewarded", + "text": "the genesis block is never rewarded: it never enters the DAA window (window.rs:177), the coinbase pays only the mergeset blues inside the DAA window (coinbase.rs:139), and the genesis coinbase has no outputs (genesis.rs:26). A block's DAA score counts its DAA-window mergeset, so on a chain the block at height h >= 1 carries DAA score h - 1: DAA score 0 is the first paid block and every schedule below is indexed by DAA score, not height", + "height_of_daa_score": "height = DAA score + 1 (a chain of blocks; in the DAG several blocks may share a DAA score)", + "source": [ + "consensus/src/processes/window.rs:177", + "consensus/src/processes/coinbase.rs:139", + "consensus/core/src/config/genesis.rs:26" + ] + }, "source": [ "consensus/core/src/emission.rs:103 to 110", "consensus/core/src/emission.rs:225", @@ -1128,8 +1138,13 @@ "start_daa_score": 38500272000, "end_daa_score": 39131424000 }, + "transition_count": 63, + "last_paying_daa_score": 39131423999, + "last_paying_block_height": 39131424000, + "terminal_supply": "3963038999610200467816224000", "terminal": { "start_daa_score": 39131424000, + "first_unpaid_block_height": 39131424001, "decay_step": 62, "start_year": 124, "behaviour": "per-block subsidy 0 at every later DAA score; the cap is never reached; blocks are paid by fees alone" @@ -2240,8 +2255,13 @@ "start_daa_score": 4039372800, "end_daa_score": 4102488000 }, + "transition_count": 66, + "last_paying_daa_score": 4102487999, + "last_paying_block_height": 4102488000, + "terminal_supply": "3963038999610200483289816000", "terminal": { "start_daa_score": 4102488000, + "first_unpaid_block_height": 4102488001, "decay_step": 65, "start_year": 130, "behaviour": "per-block subsidy 0 at every later DAA score; the cap is never reached; blocks are paid by fees alone" @@ -2519,9 +2539,9 @@ "where": "igneum/exec/src/executor.rs:362 to 371 (the tip less the developer share is credited to the block's miner alone); igneum/exec/src/pgas.rs:290 (20% developer share, unregistered parts burned)", "value": "80% to the block's miner, none to provers; 20% to registered payees or burned" }, - "spec_takes": "the code", - "why": "fees move existing supply and burn some; they never create supply", - "status": "RESOLVED (text correction owed: drop 'and provers')" + "spec_takes": "the code, which is the design's own closed decision", + "why": "docs/spec/05-fees-and-economics.md line 24 (section 5.2): 'No part of the tip reaches the provers: O-5.7 is closed at zero (8 October 2026, docs/design/proving-payment.md); the provers' user-funded payment is the proving base fee'. The code (executor.rs:362 to 371, revm's beneficiary credit) matches it. The litepaper line 622 and the spec's own summary rows (05 line 79, line 98) still say 'producer and provers' and are stale. Fees move existing supply and burn some; they never create supply.", + "status": "RESOLVED (by O-5.7, closed at zero 8 October 2026; text corrections owed: litepaper line 622, spec 05 lines 79 and 98)" }, { "id": "C11", @@ -2619,6 +2639,10 @@ "release-2.0.2-node": "ef25b2412507d608df08fd22895e74262489f1fa460e6fe26f89877fb5cc6c63", "release-2.0.3-node-k6": "ef25b2412507d608df08fd22895e74262489f1fa460e6fe26f89877fb5cc6c63" }, + "consensus/src/processes/window.rs": { + "release-2.0.2-node": "fae87c4cd23ede2486650d8b87699e65c274f3b31b469f6c8ac08dc224b0b2d5", + "release-2.0.3-node-k6": "fae87c4cd23ede2486650d8b87699e65c274f3b31b469f6c8ac08dc224b0b2d5" + }, "igneum/exec/src/config.rs": { "release-2.0.2-node": "fdc4ba56109ddab4dadfe3d184247cf2cda8774dc5542337acaa38c8da716aaf", "release-2.0.3-node-k6": "fdc4ba56109ddab4dadfe3d184247cf2cda8774dc5542337acaa38c8da716aaf" @@ -2973,6 +2997,20 @@ "line": 265, "anchor": "Amount(self.emission.block_subsidy(daa_score, self.bps))" }, + { + "id": "genesis_not_in_window", + "repo": "node", + "path": "consensus/src/processes/window.rs", + "line": 177, + "anchor": "Special case: Genesis does not enter the DAA window" + }, + { + "id": "cb_daa_blues_only", + "repo": "node", + "path": "consensus/src/processes/coinbase.rs", + "line": 139, + "anchor": "for blue in ghostdag_data.mergeset_blues.iter().filter(|h| !mergeset_non_daa.contains(h))" + }, { "id": "utxo_retired", "repo": "node", @@ -3144,6 +3182,20 @@ "line": 775, "anchor": "Genesis with no premine, 30-day ramp." }, + { + "id": "spec_tip_no_provers", + "repo": "igneum", + "path": "docs/spec/05-fees-and-economics.md", + "line": 24, + "anchor": "No part of the tip reaches the provers: O-5.7 is closed at zero (8 October 2026" + }, + { + "id": "spec_tip_table_stale", + "repo": "igneum", + "path": "docs/spec/05-fees-and-economics.md", + "line": 79, + "anchor": "80 / 20 (producer and provers / developer)" + }, { "id": "pool_payout_doc", "repo": "igneum", diff --git a/docs/plans/igneum-2.0-master/token-value/phase0/tv-01/supply-spec.md b/docs/plans/igneum-2.0-master/token-value/phase0/tv-01/supply-spec.md index bc691b8cb..89f31c028 100644 --- a/docs/plans/igneum-2.0-master/token-value/phase0/tv-01/supply-spec.md +++ b/docs/plans/igneum-2.0-master/token-value/phase0/tv-01/supply-spec.md @@ -39,6 +39,7 @@ The code already matches D01: | Tail | cap: the curve runs to zero and stays there | emission.rs:109 | | Block rate | mainnet as compiled: 10 blocks a second from genesis; Devnet 4: 1 (C04 BLOCKED) | params.rs:1789, :2208 | | Genesis | DAA score 0 (C09 BLOCKED: the compiled mainnet genesis still carries Kaspa's 1,312,860) | genesis.rs:92 | +| Genesis is never rewarded | genesis never enters the DAA window and the coinbase pays only DAA-window blues; the genesis coinbase has no outputs. On a chain, block height h >= 1 carries DAA score h - 1, so DAA score 0 is the first paid block and the last paying block is at height = terminal DAA score (mainnet 39,131,424,000; Devnet 4 4,102,488,000) | window.rs:177; coinbase.rs:139; genesis.rs:26 | ### How the cap is enforced @@ -142,7 +143,7 @@ The litepaper is site/litepaper.html at igneum master 6824d49c (sha256 `35ac65e1 | C07 | line 620 "80% the block's miner, 20% the proving pool for the provers of that block" | coinbase.rs:152 to 159 (the UTXO side pays DAA red blocks); executor.rs:181 (the EVM credits blue only) | Native issuance is the blue blocks' subsidies; the schedule sum is the upper bound | RESOLVED; TV-02 measures the red share | | C08 | silent | params.rs:1812 and :2232: `subsidy_per_block_activation_daa` is never on mainnet and Devnet 4 (testnet-1: 0). The EVM credits a merged block the merging chain block's subsidy, while the UTXO side pays the block's own. | Each block's own DAA score (ledger N8) is normative | **BLOCKED** | | C09 | line 775 "Genesis with no premine, 30-day ramp." | genesis.rs:92: the mainnet GENESIS carries DAA 1,312,860 and Kaspa's 2021 timestamp. The first block would pay 14.55% of full rate, not 10%. 510,841.78 IGN would never be scheduled, and the schedule would run 1.52 days early. | Genesis at DAA score 0, as Devnet 4 and testnet-1 have it | **BLOCKED** | -| C10 | line 622 "80% the block's miner and provers; 20% the apps whose code ran, per call frame" | executor.rs:362 to 371: the tip less the developer share goes to the miner alone | The code. Fees move supply and never create it. | RESOLVED; text correction owed (drop "and provers") | +| C10 | line 622 "80% the block's miner and provers; 20% the apps whose code ran, per call frame" | executor.rs:362 to 371: the tip less the developer share goes to the miner alone. docs/spec/05-fees-and-economics.md line 24 says the same: "No part of the tip reaches the provers: O-5.7 is closed at zero (8 October 2026 ...)". | The code, which is the design's closed decision O-5.7. Fees move supply and never create it. | RESOLVED by O-5.7; text corrections owed (litepaper line 622; spec 05 lines 79 and 98 still say "producer and provers") | | C11 | line 647 "The reference pool never holds a member’s balance. Payouts come straight from the coinbase split" | pool/src/payout.rs:1 to 6 (the pool's address receives and pays); config.rs:58 (1% fee); params.rs:1851 (`pool_split_activation_daa` never) | The code: a custodial PPLNS pool with no supply effect | **BLOCKED** | | C12 | line 630 "The cap stays at 4 billion. There is no tail emission." | emission.rs:116 to 122; params.rs:2014: the held testnet-1 object carries a 1% a year tail | Not the contract. The contract is `CURRENT` with `Tail::Cap`. | RESOLVED by D01 | | C13 | silent | params.rs:1783 to 1784: Kaspa's `deflationary_phase_daa_score` and `pre_deflationary_phase_base_subsidy` sit in the mainnet object. Only the digest reads them (coinbase.rs:31). | Ignored: not part of the contract | RESOLVED; the node lane may annotate or remove them at the genesis cut | diff --git a/tools/token-value/tv-01/check-spec.py b/tools/token-value/tv-01/check-spec.py index ef2839612..79a31d36f 100644 --- a/tools/token-value/tv-01/check-spec.py +++ b/tools/token-value/tv-01/check-spec.py @@ -97,6 +97,7 @@ def check(spec, regen=True): need(spec["gate"] == "TV-01", "gate is not TV-01") need(spec["verdict"] in ("NOT RUN", "BLOCKED", "FAIL"), f"verdict {spec['verdict']!r}: a lane never writes PASS on its own result") need(spec["decision"].get("id") == "D01", "decision is not D01") + need(spec["rules"].get("genesis_rule", {}).get("rule") == "genesis-unrewarded", "the genesis rule (genesis never rewarded) is missing") need(spec["rules"].get("tail") == "cap", f"tail is {spec['rules'].get('tail')!r}: under D01 the only tail is the cap") cap = amount(spec["cap"]["base_units"], "cap.base_units") unit = amount(spec["units"]["base_units_per_coin"], "units.base_units_per_coin") @@ -150,6 +151,10 @@ def check(spec, regen=True): raise Refused(f"{name}: phase {i} kind {p['kind']!r}") total += s need(ph[-1]["kind"] == "terminal", f"{name}: the schedule has no terminal phase (issuance is not shown to end)") + need(sc["transition_count"] == len(ph) - 1, f"{name}: transition_count is not phases - 1") + need(sc["last_paying_daa_score"] == ph[-1]["start_daa_score"] - 1 and sc["last_paying_block_height"] == ph[-1]["start_daa_score"], + f"{name}: the last paying DAA score or height disagrees with the terminal phase (genesis is unrewarded: height = DAA score + 1)") + need(sc["terminal_supply"] == sc["total_issuance"], f"{name}: terminal_supply is not the total issuance") need(total == amount(sc["total_issuance"], f"{name}.total_issuance"), f"{name}: the phases sum to {total}, the spec says {sc['total_issuance']}") if total > cap: raise Refused(f"{name}: overshoot {total - cap} base units ({(total - cap) / unit:,.6f} IGN) over the cap") diff --git a/tools/token-value/tv-01/gen-spec.py b/tools/token-value/tv-01/gen-spec.py index c3ec7b7ae..610264944 100644 --- a/tools/token-value/tv-01/gen-spec.py +++ b/tools/token-value/tv-01/gen-spec.py @@ -95,6 +95,8 @@ CITATIONS = [ ("cb_pool_output", "node", "consensus/src/processes/coinbase.rs", 163, "outputs.push(TransactionOutput::new_units(proving_pool_reward, igneum::proving_pool_script_public_key()));"), ("cb_calc", "node", "consensus/src/processes/coinbase.rs", 262, "pub fn calc_block_subsidy(&self, daa_score: u64) -> Amount"), ("cb_calc_body", "node", "consensus/src/processes/coinbase.rs", 265, "Amount(self.emission.block_subsidy(daa_score, self.bps))"), + ("genesis_not_in_window", "node", "consensus/src/processes/window.rs", 177, "Special case: Genesis does not enter the DAA window"), + ("cb_daa_blues_only", "node", "consensus/src/processes/coinbase.rs", 139, "for blue in ghostdag_data.mergeset_blues.iter().filter(|h| !mergeset_non_daa.contains(h))"), ("utxo_retired", "node", "consensus/src/pipeline/body_processor/body_validation_in_isolation.rs", 54, "RuleError::UtxoTransactionsRetired"), ("exec_blue_only", "node", "igneum/exec/src/executor.rs", 181, "for b in blocks.iter().filter(|b| b.is_blue)"), ("exec_split", "node", "igneum/exec/src/executor.rs", 189, "silent_split_units(subsidy, b.silent, env.signing_bonus_bps)"), @@ -119,6 +121,8 @@ CITATIONS = [ ("lp_pool_custody", "igneum", "site/litepaper.html", 647, "The reference pool never holds a member"), ("lp_per_block_figure", "igneum", "site/litepaper.html", 668, "31.688 IGN a block, 86,400 blocks a day"), ("lp_mainnet_launch", "igneum", "site/litepaper.html", 775, "Genesis with no premine, 30-day ramp."), + ("spec_tip_no_provers", "igneum", "docs/spec/05-fees-and-economics.md", 24, "No part of the tip reaches the provers: O-5.7 is closed at zero (8 October 2026"), + ("spec_tip_table_stale", "igneum", "docs/spec/05-fees-and-economics.md", 79, "80 / 20 (producer and provers / developer)"), ("pool_payout_doc", "igneum", "pool/src/payout.rs", 3, "so the pool receives"), ("pool_fee_default", "igneum", "pool/src/config.rs", 58, "fee_percent: 1.0,"), ("pool_distribute", "igneum", "pool/src/pplns.rs", 76, "pub fn distribute(reward_wei: u128, fee_percent: f64, payees: &[Payee])"), @@ -339,9 +343,9 @@ def conflicts(fig): "litepaper": {"line": 622, "words": "80% the block's miner and provers; 20% the apps whose code ran, per call frame"}, "code": {"where": "igneum/exec/src/executor.rs:362 to 371 (the tip less the developer share is credited to the block's miner alone); igneum/exec/src/pgas.rs:290 (20% developer share, unregistered parts burned)", "value": "80% to the block's miner, none to provers; 20% to registered payees or burned"}, - "spec_takes": "the code", - "why": "fees move existing supply and burn some; they never create supply", - "status": "RESOLVED (text correction owed: drop 'and provers')"}, + "spec_takes": "the code, which is the design's own closed decision", + "why": "docs/spec/05-fees-and-economics.md line 24 (section 5.2): 'No part of the tip reaches the provers: O-5.7 is closed at zero (8 October 2026, docs/design/proving-payment.md); the provers' user-funded payment is the proving base fee'. The code (executor.rs:362 to 371, revm's beneficiary credit) matches it. The litepaper line 622 and the spec's own summary rows (05 line 79, line 98) still say 'producer and provers' and are stale. Fees move existing supply and burn some; they never create supply.", + "status": "RESOLVED (by O-5.7, closed at zero 8 October 2026; text corrections owed: litepaper line 622, spec 05 lines 79 and 98)"}, {"id": "C11", "topic": "the reference pool's custody and fee", "litepaper": {"line": 647, "words": "The reference pool never holds a member’s balance. Payouts come straight from the coinbase split"}, "code": {"where": "pool/src/payout.rs:1 to 6 (the pool's address receives the 80% and pays members by transfers); pool/src/config.rs:58 (fee_percent 1.0); pool/src/pplns.rs:76; consensus/core/src/config/params.rs:1851 (mainnet pool_split_activation_daa = never: the IGNW coinbase split is off)", @@ -404,7 +408,11 @@ def main(): "phase_count": len(phases), "last_nonzero_phase": {"index": last_nonzero["index"], "per_block_subsidy": last_nonzero["per_block_subsidy"], "start_daa_score": last_nonzero["start_daa_score"], "end_daa_score": last_nonzero["end_daa_score"]}, - "terminal": {"start_daa_score": term["start_daa_score"], "decay_step": term["decay_step"], + "transition_count": len(phases) - 1, + "last_paying_daa_score": term["start_daa_score"] - 1, + "last_paying_block_height": term["start_daa_score"], + "terminal_supply": str(total), + "terminal": {"start_daa_score": term["start_daa_score"], "first_unpaid_block_height": term["start_daa_score"] + 1, "decay_step": term["decay_step"], "start_year": f["terminal_year"], "behaviour": "per-block subsidy 0 at every later DAA score; the cap is never reached; blocks are paid by fees alone"}, "total_issuance": str(total), "cap_shortfall": str(CAP - total), @@ -477,6 +485,10 @@ def main(): "step_seconds": STEP_SECONDS, "step_decay_q32": STEP_DECAY_Q32, "decay_rule": "rate[k+1] = floor(rate[k] x step_decay_q32 / 2^32) (a halving every two years)", "per_block": "per_block(d) = ramp(floor(rate[floor(s / step_seconds)] / bps), s), s = floor(d / bps)", "tail": "cap", + "genesis_rule": {"rule": "genesis-unrewarded", + "text": "the genesis block is never rewarded: it never enters the DAA window (window.rs:177), the coinbase pays only the mergeset blues inside the DAA window (coinbase.rs:139), and the genesis coinbase has no outputs (genesis.rs:26). A block's DAA score counts its DAA-window mergeset, so on a chain the block at height h >= 1 carries DAA score h - 1: DAA score 0 is the first paid block and every schedule below is indexed by DAA score, not height", + "height_of_daa_score": "height = DAA score + 1 (a chain of blocks; in the DAG several blocks may share a DAA score)", + "source": ["consensus/src/processes/window.rs:177", "consensus/src/processes/coinbase.rs:139", "consensus/core/src/config/genesis.rs:26"]}, "source": ["consensus/core/src/emission.rs:103 to 110", "consensus/core/src/emission.rs:225", "consensus/core/src/emission.rs:316 to 333", "consensus/core/src/config/params.rs:1858"], }, "activation_clocks": { From 48fd4e048cf00ebafdcd0e4490628ce41cf273c9 Mon Sep 17 00:00:00 2001 From: igneum-labs <337424239+igneum-labs@users.noreply.github.com> Date: Fri, 9 Oct 2026 08:53:10 +0000 Subject: [PATCH 3/9] workers page and the build queue (the coordinator, 9 October 2026 09:5x UK): a rig card reads "agent not reporting since