The sweep (main's item 1): 199 tracked text files, 783 lines. The founder's full name, first name and possessive become "the founder" (sentence starts capitalised); the lowercase operating-system user name in WSL paths and commands becomes <user>; the second owner login becomes "the second owner login"; the three earlier businesses and the two other brands become "the other business", "the earlier entity", "the earlier business" and "another brand"; the Chrome profile rule names the igneum.network profile, not the profile's label. The standing commit login igneum-labs is not a founder term here: the fresh-repository step renames it in the history (docs/plans/history-rewrite.md, tools/repo/fresh-repo.sh). The patterns never appear in plain text in the tree (a plaintext list would be the hit): tools/ci/founder-strings.b64 (perl regex, tab, a sample per row) is read by tools/ci/founder-strings-check.sh (every tracked text file, perl, known-failed first: the self-test plants each row's sample in a fixture and the hit must name the file), by tools/community/discord-hooks.mjs (the guard's founder and business rows; the test takes its fixtures from the samples) and by tools/repo/fresh-repo.sh (the business names of the rewrite rules). site/forbidden-strings.txt carries the same patterns as b64: lines, decoded case-insensitive by site/scrub.mjs and tools/ci/launch-gates-check.mjs (whose fixture now plants an encoded made-up name). The check runs in the gate's tree checks on every merge. Not in this commit, by main's word: the 105 commit messages and 40 personal-identity commits that need the history rewrite (listed, not run), and the secrets found by gitleaks over the history (reported with owners). Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
34 KiB
Igneum protocol specification, section 7: execution
Spec version 0.1, 3 October 2026. Status of this section: Designed. Nothing here is implemented or measured. This section is the normative extract of docs/design/execution-layer.md (design version 0.1), which holds the reasons, the rejected alternatives and the precedents for every rule below. Where the two disagree, this section is wrong and the design document's decision table is right until the next MAJOR step (section 0.4). The rest of the execution layer (the transaction model, the two gas dimensions and the pgas table, proof records, the proving interface, the native proving precompile, the RPC surface) stays in the design document for 0.1.
Terms. A chain block is a block on the selected chain. The segment of chain block C is C's mergeset in GHOSTDAG order, with C last; the executor runs segments in selected-chain order (design document, section 1.2). A segment is executed natively by every node, proven by miners in shards, and locked by the finality rule of section 3 independently of its proof.
7.1 EVM semantics
Decided 3 October 2026 (ledger P5, closed by this section). Igneum runs Ethereum bytecode. Contracts see the environment of the chain block C whose segment is executing. The table is normative; a conforming executor MUST return these values. Ported contracts get this table as the documented differences; "unchanged" is not claimed.
| Opcode or field | Igneum value | Ethereum value | Note for ported contracts |
|---|---|---|---|
block.number (NUMBER) |
The selected-chain height of C: genesis 0, each chain block +1, contiguous | Block height | About one per second at launch but not fixed; use timestamps for time. Blue score and DAA score are readable from the system contract IgneumInfo |
block.timestamp (TIMESTAMP) |
ts(C) = max(ts(parent chain block), C.timestamp_ms div 1000) |
Header timestamp, strictly increasing | Non-decreasing by rule; equal values happen at one block a second. The header timestamp alone may step backwards within Kaspa's tolerance (above the past median of a 27-sample window, below now plus 132 s), so the executor MUST apply the max rule and MUST NOT use the raw header value |
blockhash(n) (BLOCKHASH) |
The hash of chain block n for number - 256 <= n < number, else 0 |
Same | Hashes of merged non-chain blocks are not reachable from the EVM; IgneumInfo exposes the mergeset of a chain block |
block.prevrandao (PREVRANDAO, and DIFFICULTY) |
keccak256(epoch_seed ‖ number), where epoch_seed is the 10-minute class-group VDF output for the epoch that contains C (section 4) |
RANDAO mix | Unbiasable by the producer. Predictable for the whole epoch (about 1 h) by anyone who has evaluated the VDF, so it is fine for a shuffle revealed later and wrong for a per-block lottery; adversarial randomness goes through the proving precompile with a committed input |
block.coinbase (COINBASE) |
The miner address of the block that first included the executing copy of the transaction (design document, section 1.3) |
Fee recipient | Also the address that receives the producer's part of the 80% tip share, so the correspondence Ethereum contracts assume holds. For a transaction in a red block it is the red block's miner, who is paid that share |
block.gaslimit (GASLIMIT) |
The per-block execution gas limit B_e, a consensus constant |
Header gas limit | A segment can hold up to the mergeset limit of blocks (180 at 1 BPS), so a segment's total can exceed gaslimit |
block.basefee (BASEFEE) |
The execution base fee f_e at this segment |
Same | The proving base fee f_p is readable from IgneumInfo |
block.chainid (CHAINID) |
4461 mainnet, 4462 public testnet, 4463 devnet | 1 | Registered on ethereum-lists/chains before the public testnet |
| BLOBHASH, BLOBBASEFEE | Zero and 1 respectively; no blob transactions | EIP-4844 | As on L2s without blobs |
| Opcode set | Cancun (PUSH0, TSTORE, TLOAD, MCOPY, SELFDESTRUCT per EIP-6780) | Cancun or later | EIP-7702 and the Prague BLS precompiles are deferred to phase two |
| Precompiles | 0x01 to 0x09 (ecrecover, sha256, ripemd160, identity, modexp, ecadd, ecmul, ecpairing, blake2f); 0x0a absent and returns failure | Cancun has 0x0a | Heavy precompiles cost more here because proving gas is charged |
The timestamp rule in words: the EVM clock never runs backwards, and it never runs ahead of the header clock. Under a burst of back-dated headers inside the 132-s tolerance the EVM clock holds still rather than stepping back; its drift from wall-clock under that attack is the devnet measurement R9 of the design document.
Quoted gas price. Every transaction is metered in execution gas and in proving gas and charged gas_used x (f_e + tip) + pgas_used x f_p wei against the signed budget gas_limit x max_fee_per_gas (design document, section 4.1). Wallets sign one gas limit and one price, so the node folds the second dimension into the quote: eth_gasPrice returns f_e + f_p x (pgas_est / gas_est) + tip and eth_estimateGas returns a gas limit that covers both charges at that quote. A transaction heavy in pairing or modexp sees a higher quoted price than on Ethereum. Rationale and the rejected second-limit transaction type: design document, section 4.1.
Rationale for every row, the precedents (Conflux eSpace, Kasplex, Igra) and the rejected blue-score alternative for block.number: design document, section 3.
7.2 Shard assignment
Decided 3 October 2026 (ledger P8 and C9, closed by this section). Every segment is cut into shards by proving gas at transaction boundaries, deterministically from the native trace, so every node computes the same shard list and the same shard ids (segment hash, shard index) (design document, section 5.1). Shards are not claimed first-come. They are assigned by sortition:
- Eligible provers. The vote keys above dust under section 3 (at least 100 blue blocks in the trailing 30-day window at the chain block that heads the segment). The finality-rule population is the proving population; there is no separate registration.
- Sortition, by weight. Rule of 3 October 2026 (ledger F17, round 3); the earlier per-key ranking is withdrawn because keys are free (section 3.1 W6) and a miner who split its blocks over many keys held most of the tickets. The window is the list of blue blocks in the chain block's past that W2 of section 3.1 counts at that chain block, in GHOSTDAG order, restricted to blocks whose key is eligible under step 1; N is its length. For draw n = 1, 2, ...,
r_n = H("igneum-shard/" ‖ epoch_seed ‖ shard_id ‖ n) mod N, H the chain's hash of section 0.6 read as an unsigned integer, and the key named by blockr_nof the window is an assignee. A key drawn again holds one slot and the draw continues; the draw stops at 8 distinct keys, or earlier when every eligible key holds a slot. A key is drawn in proportion to its blocks in the window, which is its weight up to the bucket normalisation of W2, so splitting one key into a thousand changes nothing, as it changes nothing for the vote.epoch_seedis the VDF output of section 4 for the epoch containing the chain block, so the producer cannot bias it, andshard_idcommits to the segment, so the assignment is keyed to the block and known to every node the moment the segment is executed. The function is public and deterministic: it needs no private key and no proof of evaluation. Whether to replace the hash draw with the private VRF of section 3.4 (so assignees are hidden until they prove) is settled together with O-3.5; nothing else in this section depends on the choice. - Exclusive window. From the moment the segment is executed, the 8 assignees hold the shard for 10 s of DAA time. A valid proof of the shard by any of the 8 that is included in a block during the window earns the shard's part of the proving pool (section 5.3); a proof by anyone else is valid but unpaid.
- Open claiming. After the window any prover MAY prove the shard, and the first valid proof included in a block earns the shard's part of the pool. There is no claim and no shard bond: nothing waits on an assigned prover, so there is nothing to bond against (ledger P9). The bond remains in the external job market, where a customer does wait (section 5.4).
- Inclusion. Shard proofs gossip like votes and any block producer MAY include them (design document, section 5.4). A block is invalid if a proof record it carries fails verification, names a chain block that is not on the carrying block's own selected-parent chain, or carries a post-root or receipts that differ from the execution of that segment along that chain (rule of 3 October 2026, ledger P11, round 3). The test is relative to the carrying block's own chain, never to the validating node's current selected chain: that chain is a property of the node's virtual and differs between honest nodes every second on a DAG, so a rule written against it makes two honest nodes disagree on one block. Written this way, validity is a function of the block and its past and every node computes it identically, as for every other rule in the fork. The design document's section 5.5 wording ("the node's selected chain") is superseded by this item.
What the rule gives. A datacentre cannot sweep every shard by latency, because for 10 s only 8 drawn provers are paid, and the draw is proportional to a prover's blocks in the window, which is its 30-day mining however many keys it spreads them over. Income from the pool is bounded by the shards a prover is assigned plus the shards nobody assigned proves in time, not by how many it can grab. A segment producer could grind transaction content to move the assignment; it gains only if it is also one of the many eligible provers, and the draw of 8 out of the whole population makes the gain small. Its size is part of the measurement below.
Parameters 8 and 10 s are Designed. They are set on the phase 4 devnet from the shard-time distribution across three prover speeds, with the acceptance test that the fastest prover wins under 25% of shards (design document, R7; O-5.1), and the test that one key and 1,000 keys of equal weight win the same number of shards (ledger F17).
7.3 Bridges
Decided 3 October 2026 (ledger E7, closed by this section).
- There are no bridged stablecoins at genesis. No USDC, USDT or other bridged asset is a launch feature, and the project does not request, label or seed a canonical bridged version of any asset before a proof bridge exists.
- No bridge is called official. Igneum ships no bridge contract at genesis and endorses none. Anyone MAY deploy a bridge on Igneum, at their own risk and their users', and it is labelled by whoever runs it, never by the protocol or the project.
- The proof bridge arrives with the consensus proof. A bridge contract on another chain that verifies Igneum state without a committee needs to verify a lock certificate, which means knowing the voter set and weights; that is the consensus proof of the design document, section 7, scoped as phase two. When it exists, the segment proof carries a self-verifying certificate and a bridge on Ethereum needs no relayer and no multisig. Until it exists, a light client is given a recent certificate and the key set out of band (ledger P4).
- Settlement of the external job market in IGN, with its 10% burn, starts when the proof bridge lets Igneum see the payment (section 5.4). At launch customers pay on their own chain.
Nothing in consensus changes for any of this: the segment claim already commits to the chain block hash, which is what the consensus proof folds in.
7.4 Parameters in this section
| Parameter | Value | Label |
|---|---|---|
| Chain id | 4461 / 4462 / 4463 (mainnet / testnet / devnet) | Designed |
| BLOCKHASH reach | 256 chain blocks | Designed (Ethereum's) |
| PREVRANDAO source | 10-minute epoch VDF output, keccak256 with the chain height | Designed |
| Opcode set, precompiles | Cancun; 0x01 to 0x09 | Designed |
| Provers assigned per shard | 8 | Designed, set at the phase 4 devnet (O-5.1) |
| Exclusive proving window | 10 DAA s | Designed, set at the phase 4 devnet (O-5.1) |
| Shard claim bond | none | Designed |
| Sortition draw | by weight: blue blocks drawn uniformly from the window, their keys assigned | Decided 3 October 2026 (ledger F17) |
| Proof-record validity | relative to the carrying block's own selected-parent chain | Decided 3 October 2026 (ledger P11) |
| Bridged stablecoins at genesis | none | Decided (3 October 2026) |
| Official bridge | none | Decided (3 October 2026) |
| Per-transaction pgas cap | the including block's remaining B_p, metered incrementally, halt before the crossing opcode or precompile |
Decided 4 October 2026 (ledger P19), 7.5 |
| Over-cap transaction | executed as out of gas: charged for gas and pgas consumed to the abort, status 0, nonce advanced, never skipped | Decided 4 October 2026 (ledger P19), 7.5 |
| Mempool bounds | gas_limit <= B_e; estimated pgas <= B_p; template packs by the estimate |
Designed, node policy (ledger P18, P19), 7.5 |
Shard budget S_p |
7,500,000 pgas (B_p / 4), provisional: the specification carried no number before 4 October 2026; set from the shard-time measurements, never from the fixtures |
Implemented (proving/igneum-prove/core/src/config.rs), value Designed, 7.6 |
| Shard statement carry | a link hash between consecutive shards (transaction index, including block, block gas and pgas, cumulative gas, running transaction commitment) | Implemented, 7.6 |
| Proof record (v0) | per shard, 274 bytes, BLS-signed by the prover's vote key, in the coinbase extra data before the finality section; proof bytes on p2p message 71 | Implemented, 7.7 |
| Record window | 600 chain blocks behind the carrier | Implemented, 7.7 (Designed value) |
| Records per block | 8 | Implemented, 7.7 (Designed value) |
| Payout per shard | the segment's pool credit in equal parts, remainder to shard 0, paid by the carrying segment | Implemented, 7.7 |
| Proving v0 activation | proving_v0_activation_daa, default never |
Implemented, 7.7 |
| Segment record (v1) | per segment of proving_v1_segment_blocks chain blocks, 586 bytes (the aggregator guest's 340-byte statement inline), BLS-signed by the aggregator's vote key, in the coinbase extra data before the shard record section (IGNS); proof bytes on p2p message 75 (protocol 15) |
Implemented, 7.8 (branch proving-v1, 5 October 2026) |
| Segment records per block | 2 | Implemented, 7.8 (Designed value) |
Segment length N |
proving_v1_segment_blocks, 8 |
Implemented, value Decided (5 October 2026, delegated; docs/plans/proving-v1.md) |
Unproven deadline T |
proving_v1_unproven_daa, 600 DAA s after the segment's last chain block |
Implemented, value Decided (5 October 2026, delegated) |
| Aggregator share | proving_v1_aggregator_share_bps, 1,000 (a tenth of every attested block's pool credit; the shards share the rest) |
Implemented, value Decided (5 October 2026, delegated) |
| Proving v1 activation | proving_v1_activation_daa, default never; the segment grid starts at the first chain block at or above it |
Implemented, 7.8 |
| Mandatory proofs | the rule of 7.8 item 9, no switch yet, off | Designed |
7.5 Proving gas per transaction: the cap and the abort
Decided 4 October 2026 (ledger P18 and P19, closed by this section; docs/bench-log.md, "execution layer attack fixes"). Implemented on branch execution-layer and measured there. This section supersedes the execution-time skip of design 4.3 for a transaction's own running pgas: a transaction is never skipped for its proving cost after it has run, because a skip is free and the attack of P19 is exactly a transaction that runs for free. The intrinsic-only skip of design 1.5 (a copy whose intrinsic pgas alone does not fit the block) stays: it costs one comparison and no execution.
- Incremental metering under a cap. The executor meters pgas opcode by opcode and precompile by precompile while the native execution runs. Before an opcode executes, or a precompile is entered, its pgas is added to the transaction's running total. If the total would exceed the cap, the opcode or precompile does not run and the transaction halts there. The cap is the including block's remaining proving budget:
B_pminus the pgas already charged to the block, which includes the intrinsic pgas of every copy included before it and of the transaction itself. A transaction carries no pgas limit field of its own (7.1, design 4.1); its own limit is the signed wei budget, which halts it as out of gas under 7.1 the moment the running charge would cross it, so the binding limit is whichever of the two comes first. A halt propagates: every frame still open halts at its next instruction, so a contract cannot catch the failed call and go on. The native work of one transaction is therefore bounded byB_pof proving gas and its own gas limit of execution gas, whatever its input, and no block ever carries more thanB_p. - An aborted transaction pays, and its nonce advances. It is not skipped. It is an executed transaction with status 0, no logs and its state changes reverted, as a transaction that ran out of gas; its nonce advances. The sender pays
gas_consumed x (f_e + tip) + pgas_consumed x f_p:gas_consumedis the execution gas spent up to the abort, intrinsic included and never the whole limit;pgas_consumedis the pgas metered up to the abort plus the intrinsic pgas. The proving part never takes the charge past the signed budget. Both base fees burn and the tip splits as design 4.4. The receipt carriespgasAborted: true. A later copy of the same transaction is skipped by the nonce rule of design 1.3 at one account read, so it is never executed twice, and the sender's later nonces are not held behind it. - Admission and the template. A node's mempool does not admit a transaction whose
gas_limitexceedsB_e, nor one whose estimated pgas exceedsB_p; the estimate is a simulation at the tip under the cap of item 1, so it costs at mostB_pof pgas, and the rejection names the pgas metered andB_p. The template builder packs by that estimate: it never includes a transaction whose estimated pgas exceeds the block's remainingB_p, and it stops at the first transaction that does not fit a budget, so a sender's later nonces never jump ahead. These are node policy (design 1.4), not consensus; item 1 is the consensus rule and holds whatever a miner includes. - The pgas dimension is visible.
eth_estimateGasfolds the proving charge into the quoted gas limit (7.1) and fails, naming the pgas metered andB_p, for a call that hits the cap;eth_callfails the same way.igneum_estimateGasreturns both dimensions for the same simulation:gasUsed,pgas, the foldedgas,provingGasLimit, both base fees andexceedsProvingLimit, so a wallet or tool can show the proving side.
What the rule gives, measured (bench-log, 4 October 2026, B_p 30 M, modexp loop of 9,000 calls): before, 10.85 ms of native execution per inclusion, nothing charged, the nonce stuck and the sender's later transactions never includable; after, the mempool refuses it, a hostile miner's inclusion is cut at 29,998,593 pgas after 4,680,437 gas in 11.4 ms, the sender pays 0.0394 IGN, the nonce advances, a second inclusion is skipped in 35 us, and the next nonce executes in the following blocks.
7.6 Shard statement and block proof, as implemented
Added 4 October 2026 because the implementation (proving/igneum-prove, devnet v4) needed three definitions the specification did not give. They are Implemented; nothing else in this section changes.
- Carry between shards. Section 7.2 cuts a segment at transaction boundaries, but a transaction's outcome depends on more than the state: the including block's running gas and pgas (the budgets of 7.5), the receipts' cumulative gas, and the position in the segment. Shard i therefore starts from a carry (transaction index, including-block index, block gas, block pgas, cumulative gas, running transaction commitment) and ends with the carry shard i+1 starts from; each shard proof commits the hash of both (
link_in,link_out), and the block proof is invalid unless everylink_inequals the previouslink_outand the first is the empty carry. A shard whose single transaction exceedsS_pis a shard of its own (over_budget); the zkVM's own continuations prove it (approximate). - Transaction commitment. The block's transaction commitment is a running keccak over the transactions in sequence order (
acc = keccak(acc, miner, blue, length, raw)), carried in the link, so it is the same whatever the cut. The block proof'stx_commitmentis the final accumulator. - Receipts. A shard commits the ordered trie root of its own receipts (cumulative gas running across the whole segment); the block proof commits keccak over the shard receipts roots in order. This is what a proof record's
receipts(design 5.4) means under this implementation, and what the native-execution veto of 7.2 item 5 compares. The provers are committed the same way (keccak over the shards' payout addresses, ledger P12), beside the shard program's verifying-key hash and, when the proof chains to the previous segment's proof, the aggregator's own.
7.7 Proof records, assignment and payout, as implemented (proving v0)
Added 4 October 2026 because the implementation (vendor/igneum-node-proving, branch proving; proving/igneum-prove; app/igneum-app/src/prover.rs) needed decisions the specification did not give. Every item is Implemented on the proving branch and behind the height switch of item 7; nothing here changes the devnet until the switch is set. Where this section and the design document's section 5.4 differ, this section is what runs.
- The record is per shard, not per segment. Design 5.4 carried one aggregated record per segment with a prover list. Proving v0 carries one
ProofRecordper shard (kaspa_consensus_core::proving): version, chain block hash and height, shard index, the prover's BLS vote key, the payout address, the statement (keccak256 of the shard program's 328-byte public values, 7.6), the SHA-256 of the proof bytes, and a BLS signature over all of it under the tagIGNEUM_PROOF_RECORD_V1, domain-separated with the network name. 274 bytes. The aggregated segment proof and its chain rule (design 5.3) are not in consensus yet: the per-shard record is what the devnet can produce today, and the aggregated record of design 5.4 is the next step on top of it (an aggregator's record would name the same shards). - Carriage. Records ride in the coinbase extra data as a section
records || len_le32 || "IGNP"placed before the finality section ("IGNF"closes the extra data), at most 8 per block. The proof bytes do not ride in blocks: they travel beside the record on the p2p messageIgneumProofRecordMessage(type 71, protocol version 13; peers at 12 never receive it) and throughigneum_submitProofRecord, committed by the record'sproof_hash. - What every node checks on a carried record (consensus). The record names a chain block on the executor's own chain at most 600 chain blocks behind the carrier; its shard index is in that segment's plan; its signature verifies under its key; its statement equals the node's native statement for that shard and payout address (the veto of 7.2 item 5, computed by every node from its own trace); and, while the carrier's DAA score is within 10 of the segment's, its key is one of the shard's 8 assignees (7.2 items 3 and 4). A record that fails is ignored, not a fault of the block: it pays nothing. The SP1 proof is NOT verified on this path (item 4).
- Verification is off the consensus path. A node keeps a proof pool: records with their proof bytes, accepted after the checks of item 3 against its own execution. A verifier (
igneum-prove-host --mode verify, SP1 compressed proof against the shard program's verifying key, the statement compared) runs one proof at a time outside consensus; a block producer offers only verified records to its templates. A node without a verifier relays and stores records and never includes them. Consequence, stated plainly: a prover who signs a correct statement with a fake proof is paid if a producer includes the record without verifying; honest producers verify, and the native statement bounds the damage to that prover's payout, never to state. The aggregated segment proof verified in consensus (design 5.4) closes this and is the next step. - Assignment, as implemented. The sortition window at chain block C is the vote key hash of every blue block in C's past with DAA score in
(daa(C) - W, daa(C)], in GHOSTDAG order (the executor's segment order), restricted to keys with at leastdustsuch blocks (W and dust are the finality parameters of section 3). The draw isH("igneum-shard/" || epoch_seed || shard_id || n)with H the chain's BLAKE2b under the domainIgneumShardSortition, read as the low 16 bytes little-endian, modulo the window length;shard_id = BLAKE2b_IgneumShardId(block hash || index_le32);epoch_seedis the executor's epoch seed of the segment (the devnet's chain-block seed, not yet the VDF of section 4). The draw stops at 8 distinct keys or when every eligible key holds a slot. The list is in every node'signeum_getShardPlan. - Payout, as implemented. The 20% pool share of a segment (section 5.3) is credited to the pool escrow when the segment executes, as before. At the carrying chain block C, for every record its segment's blocks carry in sequence order, the first valid record per (segment, shard) pays that shard's part of the segment's credit, equal parts with the remainder to shard 0, from the escrow to the record's payout address, as a state transition of C's segment applied after the rewards and before the transactions (design 1.1: rewards by rule). The shard statement commits the post-root after those payouts, so the fixture, the shard input and the guest carry the segment's payouts as data beside the rewards (
payouts), the same class of unverified input as the rewards are in v0. The UTXO-side coinbase is unchanged (its pool output still burns). A reorg unwinds the payouts with the carrier. - Activation.
Params::proving_v0_activation_daa(override file, default never) gates item 6 only: before it, records are relayed, stored, carried and checked, and nothing is paid; from it, carriers pay. Every node must run the proving build before the height (a node on the old build neither carries nor pays, and a block whose coinbase carries a record section is valid to it, since the section is extra data it does not read). - The plan. Every segment has at least one shard; an empty segment is one shard whose statement applies the rewards and payouts only. The node cuts from its own per-transaction boundaries (
TxBoundary: the carry of 7.6, the state root after every transaction) with the cut ofigneum_prove_core::plan;igneum-prove-exportmust reproduce the node's plan on the same export, and the test network checks that it does.
RPCs (the execution layer's JSON-RPC): igneum_getShardPlan(block), igneum_getProofRecords(block), igneum_submitProofRecord({record, proof}), igneum_getAssignedShards([keyHash...], lookback) (the prover's work list), igneum_getProvingStatus(). Signing without the BLS key material in the prover process: igneum-miner sign-record and key-hash.
7.8 Segment records, the chain rule and the unproven rule, as implemented (proving v1)
Added 5 October 2026 (the founder: "open the proving round asap"; branch proving-v1 of the fork and of the main repository, docs/plans/proving-v1.md). Every item is Implemented on the branch and behind proving_v1_activation_daa (default never); nothing here changes the devnet until the 0.3.11 rollout sets the switch. Item 9 is Designed and off. Proving v0 (7.7) keeps running underneath: per-shard records stay valid and paid.
- The aggregated proof. The aggregator guest of 7.6 (pinned,
elf/igneum-prove-aggregator) verifies every shard proof of one chain block and, by recursion, the previous chain block's aggregated proof (AggInput.prev): its public values (BlockOutput, 340 bytes, mirrored in consensus asBlockStatement) carrychain_len, the number of consecutive chain blocks the proof attests, andagg_vk, the aggregator's own id wheneverchain_len > 1. One compressed proof of constant size therefore attests any run of consecutive chain blocks (measured:docs/bench-log.md, "proving v1, aggregated chains on the RTX 5090"). This is design 5.3's "segment N verifies N-1" realised inside the proof rather than beside it. - Segments. From the first chain block
Awhose DAA score reachesproving_v1_activation_daa, chain blocks are grouped in fixed segments ofN = proving_v1_segment_blocks: segmentkisA + kN ..= A + kN + N - 1. The grid is a pure function of the chain, so every node names the same segments. - The record. One
SegmentRecord(kaspa_consensus_core::proving): version 2,first,last, the hash of chain blocklast, the aggregator's BLS vote key, the payout address, the aggregated proof's 340 public values inline, the SHA-256 of the proof bytes, and a BLS signature over all of it underIGNEUM_SEGMENT_RECORD_V1, domain-separated with the network name. 586 bytes. The statement the verifier checks is keccak256 of the public values. - Carriage. Records ride in the coinbase extra data as a section
records || len_le32 || "IGNS"placed before the shard record section (IGNP), which sits before the finality section; at most 2 per block. A node that does not read the section sees miner bytes. The proof bytes travel beside the record on p2p messageIgneumSegmentRecordMessage(type 75, protocol version 15; peers at 14 and below never receive it; 14 is the EVM transaction relay of 0.3.10) and throughigneum_submitSegmentRecord. - What every node checks on a carried record (consensus). The segment is aligned on the grid and its last block is on the executor's own chain, at most 600 chain blocks behind the carrier; the signature verifies; the public values equal the node's native block statement for chain block
lastin every field butproversandchain_len(chain_id,number,block_hash,parent_hash,shard_count,tx_commitment,pre_root,post_root, the keccak of the shard receipts roots, gas, pgas, executed, skipped,shard_vk= the pinned shard program id,agg_vk= the pinned aggregator id whenchain_len > 1and zero otherwise);chain_lenis at leastNand at most the chain height; the chain rule of item 6; and the deadline of item 7. A record that fails is ignored, not a fault of the block: it pays nothing. The SP1 proof is not verified on this path (item 8). - The chain rule. A record whose
chain_len > Nchains to the previous segment's proof by recursion (the proof itself verified it), and is valid whatever the chain says about that segment. A record whosechain_len = Nstarts a fresh chain and is valid only for the first segment of the grid, or when the previous segment is unproven (item 7). So a proven segment is followed only by records that verify it; an unproven one may be skipped. - The unproven rule. A segment whose last chain block is more than
T = proving_v1_unproven_daaDAA seconds old at the carrier, with no paid record, is unproven: the pool pays nothing for it (its aggregator share stays in the escrow), a record for it carried after the deadline is invalid, and the next segment may start a fresh chain. A segment with a paid record is proven; before its deadline it is pending.igneum_getProvingStatusreports the three counts over the record window. - Verification is off the consensus path, as 7.7 item 4: the proof pool verifies segment proofs through
igneum-prove-host --mode verify-segment(SP1's light verifier against the pinned aggregator key; the shard id and the aggregator id inside the statement checked against the pinned ids; keccak of the public values against the statement) and a producer offers only verified records to its templates. The native statement bounds what an unverified record can do to the aggregator's payout, never to state. - Payout. From the activation, a chain block's pool credit (5.3) splits:
proving_v1_aggregator_share_bpsof it to the aggregator of the segment record that attests the block, the rest to its shards in equal parts as 7.7 item 6 (split_pool_credit). At the carrying chain block, for every segment record its blocks carry in sequence order, the first valid record per segment pays the sum of the aggregator shares of the segment's blocks to the record's payout address, from the escrow, after the shard payouts and before the transactions; a reorg unwinds it with the carrier. There is no aggregator sortition yet: the first valid record carried wins (Open, O-7.3: the VRF draw of design 5.3). - Mandatory proofs (Designed, off). The rule that makes a proof a condition of validity: a chain block is invalid if the segment ending
TDAA seconds before it is unproven. It needs an activation height of its own (not yet a parameter) and a consensus-level check in the block validator; it is written here so the devnet measures the coverage the fleet can meet first (docs/plans/proving-v1.md, step 3) and the founder sets the height when the share is one.
RPCs: igneum_submitSegmentRecord({record, proof}), igneum_getSegmentStatement(block) (the segment, its status, the native public values for a fresh and a continuing chain, the shard proofs the pool holds per block, the previous paid record), igneum_getSegmentRecords(block), igneum_getProofBytes(block, shard, keyHash) and igneum_getSegmentProofBytes(first, keyHash) (the aggregator's inputs), the v1 object of igneum_getProvingStatus. Signing: igneum-miner sign-segment-record. Host modes: chain, aggregate, verify-segment.