Proving v1: the harness passes (21 checks), the bench-log entry with the step 1 GPU memory, RAM and SM-target numbers, the CPU chain of 2 and verify-segment

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
igneum-labs 2026-10-05 19:16:47 +00:00
parent 55ea10cc26
commit 3fcf4f705c
4 changed files with 379 additions and 3 deletions

View file

@ -1586,3 +1586,41 @@ The 3-node run (`tools/txgen/relay-net.mjs`, new; this Mac, load 7 to 8 at the e
Reading. Every transaction given to A was mined by B or C within 6 s, two thirds of them within 3 s, with no skipped copy: the hold on block-added kept B's and C's parallel blocks from carrying the same transfer. The afternoon run on the live devnet, through one node with the cooldown, had p50 40.7 s and p90 110.8 s with 50-s quiet stretches; here the 1.5 s p50 is one fast-time block plus the relay and the executor's lag. The pool depth matching on all three nodes at every sample is the convergence. Not measured here: a transaction flood above the per-peer rate (the bucket is unit-tested only), a 13 peer in the fleet (the digest check and the version gate are the evidence), and the hold's 30-s expiry on a block that never reaches the chain (not seen in 149 chain blocks).
Commands: `IGNEUMD=vendor/igneum-node/target-txgossip/release/igneumd IGNEUM_MINER=vendor/igneum-node/target-txgossip/release/igneum-miner tools/lock/with-lock.sh run node tools/txgen/relay-net.mjs --rate 2 --duration 120 --wallets 16 --fund 2`; the Mac binaries from the fork worktree with `CARGO_TARGET_DIR=vendor/igneum-node/target-txgossip cargo build --release -j 4 -p kaspad -p igneum-miner --features kaspad/igneum-pow` under the build lock (an APFS clone of `target-036`, 2 min 15 s to clone, 5 min 06 s to build); the suites with `node tools/build-job.mjs run --target 1ccfe586 --node vendor/igneum-node-txgossip --targets linux --node-tests "igneum-exec kaspa-p2p-flows" --no-app`.
## 5 October 2026 (evening), proving v1: segment records, the chain rule, the unproven rule; what was measured tonight (proving engineer)
Branches `proving-v1` (main repository, worktree `igneum-wt-proving-v1`; fork `vendor/igneum-node-pv1` from a24ab01a). Rules: spec 7.8; plan `docs/plans/proving-v1.md`. Every row names its command. The live devnet was in a degraded state the whole evening: from 18:35Z the RTX 5090 workers on PC 1 and PC 2 exited at start on a pack seed mismatch (`the epoch seed bytes do not give the pack's IGNEUM_SEEDW_INIT`, restart 60+ on PC 2 by 19:05Z, another agent's branch `pack-loop`), the Mac app node was down from 17:45Z, so PC 2 mined 3.4 MH/s from its iGPU and PC 2's prover was the only prover; the coordinator held every PC 2 measurement at 19:00Z until the fleet mines again.
### Step 1, the prover default and its cost
| What | Measured |
|---|---|
| The default rule (`app/igneum-app/src/provedefault.rs`) | `cargo test --release -p igneum-app provedefault` on this Mac (the app crate, build lock, 19:05Z): 5 passed (a 5090 with WSL2 on Windows is on; Windows without WSL2 off with the Set up hint; Linux needs no WSL2 and the 12 GB gate holds, a 10 GB 3080 and a 16 GB AMD card stay off; Apple silicon off; the biggest qualifying card is named) |
| Mining alone against mining with the prover (PC 2 job `prover-cost-pc2-pv1`, `tools/proving-v1/pc2-prover-cost.ps1`, 5 + 5 min, published 18:40:48Z, ran 18:41:13Z) | VOID: the job waited 20 min for the 5090 worker to hash and it never did (the pack fault above); "mining alone" was 0 MH/s. Re-run after the coordinator's go. The job's `/api/state` read also came back empty on PC 2 (`cards=::0`, every sample) while `igneum_getProvingStatus` on 127.0.0.1:26790 answered; the re-run script prints the URL file and the error |
| GPU memory during proving (the same job, phase B: the prover on for 5 min, 298 one-second `nvidia-smi --query-gpu=memory.used` samples, the 5090 worker dead so the card held nothing else) | memory.used min 1,654 MiB, max 13,816 MiB, utilisation mean 2.7%, power max 190.6 W. The shards were the devnet's empty shards (0 pgas); the peak on a full shard at `S_p` is the chain job's row (held). Read: a 16 GB card clears tonight's peak, a 12 GB card does not, and the 24 GB of a 4090 has 10 GB of headroom |
| Shards per minute with the mining worker dead | the node's `paidShards` 510 -> 518 over the 5-min phase: 1.6 shards a minute from one 5090 through the app's loop (export, cut, prove, sign, submit) |
| Host RAM (Windows `Win32_OperatingSystem` and the `vmmem` working set, sampled every 15 s) | host used 25,550 MB of 63,132 MB at the end; the WSL2 VM's working set 7,915 MB (2,334 MB used of 30,914 MB inside the distribution) |
| The SP1 GPU server's compiled targets (`cuobjdump --list-elf /root/.sp1/bin/sp1-gpu-server` inside PC 2's Ubuntu-24.04, CUDA 12.8, driver 610.47) | `sp1-gpu-server` 6.8.1 (251,306,680 bytes, sha256 c2642ad1c42e85d8525159cf0c7cd5200d8766c9be1283f452a1f9bf9fea725c, the asset `sp1_gpu_server_v6.8.1_x86_64.tar.gz` the SDK downloads, `sp1-cuda-6.8.1/src/server.rs`): one ELF each for sm_80, sm_86, sm_89, sm_90, sm_100 and sm_120; `strings` finds compute_120 PTX as well. So sm_89 (Ada: RTX 4090, 4080) is compiled in natively, no JIT; so are Ampere (3090, 3060), Hopper, Blackwell datacentre (sm_100) and consumer (sm_120, the 5090). Nothing for AMD (no HIP path in SP1) |
### Step 2, aggregated chains
| What | Measured |
|---|---|
| The new host (`--mode chain`, `aggregate`, `verify-segment`) against every fixture natively | `igneum-prove-host <f> --mode native` on the Mac for the 12 fixtures of `proving/fixtures/` (9 block, 3 fee-switch), host built from this branch 19:06Z: every one MATCHES (the package gate's native half); `--mode id`: shard `0x2b1a81cb...`, aggregator `0x474678f3...`, the 0.3.9 pin, unchanged |
| Eight consecutive live fixtures | `igneum_exportSegments 0x0..0x13cb4` on node 1's exec RPC (127.0.0.1:26790, read-only, 20:06 BST, tip 81,076): 71,042,616 bytes, 81,077 segments, 28 accounts, 0.5 s; `igneum-prove-export export.json <n> block-<n>.json` for 81046..81053: replayed 81,077 segments from genesis in 1.8 s each, every state root equal to the node's; one shard a block, 0 pgas (no transactions on the devnet tonight), `proving/fixtures/chain/` |
| Chain of 2 on the Mac CPU (the known-finished case of `--mode chain` before the GPU; M5 Max under the live nodes, the harness and two builds) | `SP1_PROVER=cpu igneum-prove-host --mode chain --chain block-81046.json,block-81047.json --out results.json` under the run lock, 19:07:48Z to 19:11:28Z: setup 12.2 s; block 81046: shard 0 compressed 55.4 s (1,272,897 bytes, verify 0.036 s), aggregate 52.0 s (1,272,909 bytes, verify 0.031 s), chain_len 1, agg_vk zero; block 81047: shard 41.3 s, aggregate WITH the previous block proof 59.1 s, chain_len 2, agg_vk = the pinned aggregator id; end to end 207.9 s; final proof 1,272,909 bytes, statement 0x232276f4... The recursion over the previous proof cost 7 s more than the first aggregation on this CPU |
| `--mode verify-segment` on that proof (the node's path: SP1 light verifier, pinned aggregator key) | VERIFIED in 0.032 s (0.27 s wall, three runs: 0.033, 0.032, 0.032); known-failed: a wrong statement NOT VERIFIED (0.032 s); the shard verifier (`--mode verify`) on the segment proof NOT VERIFIED, "program id 0x474678f3... IS NOT OURS 0x2b1a81cb..." |
| Chain of 8 on the RTX 5090 (N = 2, 4, 8) | HELD with step 1 (`tools/proving-v1/pc2-chain.ps1`, package `igneum-prove-wsl2-pv1.zip` eb6dccf8..., 1.5 MB, built from this branch with the gate's native half run above) |
### Step 3, coverage
| What | Measured |
|---|---|
| A 3-minute window at 18:57Z on node 1 (`node tools/proving-v1/coverage.mjs --minutes 3`, chain blocks 80754..80839, 86 blocks) | 4 blocks with a paid shard (4.7%), 4 fully proven, 4 of 86 shards; on-chain latency (carrier timestamp minus block timestamp) n 4: min 36 s, p50 39 s, max 44 s; 0 content blocks. One prover (PC 2), the Mac verifier node down, PC 2 producing few blocks (3.4 MH/s): the degraded state above, not the fleet's number |
| The 30-minute window | waits for the fleet (the coordinator's go) |
### Step 4, the rule
| What | Measured |
|---|---|
| Unit tests | `cargo test --release -p kaspa-consensus-core -p igneum-exec --lib -- proving config::params::tests::override_params_carry_the_proving_v1 config::params::tests::consensus_digest` on this Mac (target `vendor/igneum-node/target-pv1`, 19:09Z): consensus core 13 passed (the segment record round trip, signature and the three nested sections; the credit split; the params switch and the digest that moves only once the switch is set), exec 8 passed (the segment grid and the split; the record checks: alignment, block, chain length, the veto naming the field, the deadline, the window; the chain rule both ways; the unproven restart; the shard side at 90%; the pool offering the segment section). The six full node suites go to PC 2 as a build job when the fleet is back |
| The fast-time 3-node harness (`tools/proving-v1/net.mjs`, 29950+, suffix 956, every node in trust mode, three vmine voters, v0 at DAA 60, v1 at DAA 120, 4 blocks a segment, unproven after 60 DAA, a tenth to the aggregator; fork b177718e built on this Mac) | run 2, 19:13:01Z to 19:16:19Z, under the run lock: PASSED, 21 checks in 197.3 s (`tools/proving-v1/report-2026-10-05.json`). v1 start = chain block 119 on all three nodes; the native statement identical on all three. Known-finished: segment 119..122's fresh-chain record submitted to n1 at t=131.1 s, relayed, verified (trust) and PAID on n0 1.0 s later at chain block 129, 253,611,648,000,000,000 wei = a tenth of the four credits, the same on every node, the payout address holding it. Chain rule: segment 123..126's fresh-chain record refused ("does not chain to segment 119..122 ... proven (record paid at chain block 129)"), the continuing one (chain_len 8) accepted and paid. Known-failed: segment 127..130 left without a record: a fresh-chain record for 131..134 refused while 127..130 was pending ("pending until DAA 191"); at DAA 192 the status read unproven, a late record for 127..130 refused ("unproven: carried after the deadline"), the fresh-chain record for 131..134 accepted and paid with chain_len 4; `segmentsInWindow` proven 3, unproven 1. The shard side: a v1 shard's `shardWei` = 90% of its block's credit. Run 1 (19:10Z) failed in its own tooling (the signer's argument order), fixed |

View file

@ -122,7 +122,7 @@ async function waitExecuted(n, number) {
// signs a segment record over the given public values with v0's key; the proof bytes are a placeholder (trust mode)
function signSegment(first, last, hash, pv, tag) {
const proof = Buffer.from(`igneum-proving-v1-harness-${tag}-${first}-${last}`);
const sg = run(MINER, ['sign-segment-record', 'v0', CHAIN_NAME, hash, String(first), String(last), PAYOUT, pv, sha256(proof)]);
const sg = run(MINER, ['sign-segment-record', 'v0', CHAIN_NAME, String(first), String(last), hash, PAYOUT, pv, sha256(proof)]);
if (sg.code !== 0) throw new Error(`sign-segment-record failed: ${sg.out}`);
const signed = JSON.parse(sg.out.trim().split('\n').pop());
return { record: signed.record, proof: '0x' + proof.toString('hex'), keyHash: signed.keyHash, statement: signed.statement };

View file

@ -7,9 +7,15 @@
# 5. leaves the prover ON
# Every number is a RESULT line; the per-sample lines are SAMPLE lines. Read with `node tools/jobs.mjs <id>`.
$ErrorActionPreference = 'Continue'
$base = (Get-Content (Join-Path $env:LOCALAPPDATA 'igneum\app\app.url') -Raw).Trim().TrimEnd('/')
$urlFile = if ($env:IGNEUM_APP_DIR) { Join-Path $env:IGNEUM_APP_DIR 'app.url' } else { Join-Path $env:LOCALAPPDATA 'igneum\app\app.url' }
if (-not (Test-Path $urlFile)) { $urlFile = Join-Path $env:LOCALAPPDATA 'igneum\app\app.url' }
$base = (Get-Content $urlFile -Raw).Trim().TrimEnd('/')
function Stamp { (Get-Date).ToUniversalTime().ToString('yyyy-MM-ddTHH:mm:ssZ') }
function State { try { Invoke-RestMethod -Uri "$base/api/state" -TimeoutSec 10 } catch { $null } }
$script:stateErr = ''
function State { try { Invoke-RestMethod -Uri "$base/api/state" -TimeoutSec 20 } catch { $script:stateErr = "$_"; $null } }
"RESULT app_url_file $(Stamp) $urlFile exists=$(Test-Path $urlFile) base_len=$($base.Length)"
$probe = State
"RESULT state_probe $(Stamp) ok=$($null -ne $probe) version=$($probe.version) cards=$(($probe.mining.cards | Measure-Object).Count) err=$script:stateErr"
function Prove($on) { try { (Invoke-RestMethod -Method Post -Uri "$base/api/prove" -ContentType 'application/json' -Body (@{on=$on} | ConvertTo-Json -Compress) -TimeoutSec 10) | ConvertTo-Json -Compress } catch { "error: $_" } }
function Rpc($port, $method, $params) {
try { (Invoke-RestMethod -Method Post -Uri "http://127.0.0.1:$port" -ContentType 'application/json' -Body (@{jsonrpc='2.0'; id=1; method=$method; params=$params} | ConvertTo-Json -Compress -Depth 6) -TimeoutSec 20).result } catch { $null }

View file

@ -0,0 +1,332 @@
{
"v0": 60,
"v1": 120,
"segment": 4,
"unproven": 60,
"share_bps": 1000,
"steps": {
"status": {
"v0": "0x3c",
"v1": {
"activationDaa": "0x78",
"active": false,
"aggregatorId": null,
"aggregatorShareBps": "0x3e8",
"paidSegmentWei": "0x0",
"paidSegments": 0,
"pool": {
"entries": 0,
"failed": 0,
"pending": 0,
"verified": 0
},
"segmentBlocks": "0x4",
"segmentsInWindow": {
"pending": 0,
"proven": 0,
"unproven": 0
},
"shardProgramId": null,
"start": null,
"unprovenDaa": "0x3c"
}
},
"v1_start": {
"start": 119,
"tipDaa": 128
},
"case1": {
"segment": [
119,
122
],
"wei": "253611648000000000",
"paidSecs": 1.008,
"carrier": "0x81"
},
"case2": {
"segment": [
123,
126
],
"refused": "segment 123..126 does not chain to segment 119..122 (chain_len 4), which is proven (record paid at chain block 129)",
"paid": {
"carrierNumber": "0x87",
"chainLen": "0x8",
"keyHash": "0xc379ba2cdb239d2884d6bdb391d243ddfa869ab95ec4e72372e0e31fc9025fa0",
"payout": "0x4343434343434343434343434343434343434343",
"wei": "0x38505a6ce4a8000"
}
},
"case3": {
"unproven": [
127,
130
],
"restarted": [
131,
134
],
"status": {
"activationDaa": "0x78",
"active": true,
"aggregatorId": null,
"aggregatorShareBps": "0x3e8",
"paidSegmentWei": "0xa8f1428e9a42800",
"paidSegments": 3,
"pool": {
"entries": 3,
"failed": 0,
"pending": 0,
"verified": 0
},
"segmentBlocks": "0x4",
"segmentsInWindow": {
"pending": 15,
"proven": 3,
"unproven": 1
},
"shardProgramId": null,
"start": "0x77",
"unprovenDaa": "0x3c"
}
}
},
"checks": [
{
"name": "the node carries the v1 parameters",
"ok": true,
"detail": {
"activationDaa": "0x78",
"active": false,
"aggregatorId": null,
"aggregatorShareBps": "0x3e8",
"paidSegmentWei": "0x0",
"paidSegments": 0,
"pool": {
"entries": 0,
"failed": 0,
"pending": 0,
"verified": 0
},
"segmentBlocks": "0x4",
"segmentsInWindow": {
"pending": 0,
"proven": 0,
"unproven": 0
},
"shardProgramId": null,
"start": null,
"unprovenDaa": "0x3c"
}
},
{
"name": "every node agrees on the v1 start",
"ok": true,
"detail": 119
},
{
"name": "segment 0 is aligned at the start and pending",
"ok": true,
"detail": {
"first": "0x77",
"last": "0x7a",
"status": {
"deadline_daa": 183,
"status": "pending"
}
}
},
{
"name": "the native statement is the same on every node",
"ok": true,
"detail": "0x000000000000116f000000"
},
{
"name": "the aggregator share is a tenth of the segment credits",
"ok": true,
"detail": {
"expectedWei0": "253611648000000000",
"creditSum0": "2536116480000000000"
}
},
{
"name": "known-finished: segment 0 record accepted by n1",
"ok": true,
"detail": {
"accepted": true,
"block": "0xe03d6896eff5476fffb90d066efd77feb0e2eb9c527b967423b74bb5948f36d2",
"first": "0x77",
"keyHash": "0xc379ba2cdb239d2884d6bdb391d243ddfa869ab95ec4e72372e0e31fc9025fa0",
"last": "0x7a",
"new": true,
"reason": "accepted"
}
},
{
"name": "known-finished: segment 0 paid on n0 (relayed over p2p, verified in trust mode, carried)",
"ok": true,
"detail": {
"paid": {
"carrierNumber": "0x81",
"chainLen": "0x4",
"keyHash": "0xc379ba2cdb239d2884d6bdb391d243ddfa869ab95ec4e72372e0e31fc9025fa0",
"payout": "0x4343434343434343434343434343434343434343",
"wei": "0x38502733df10000"
},
"secs": 1.008
}
},
{
"name": "every node paid segment 0 the same",
"ok": true,
"detail": [
"0x38502733df10000",
"0x38502733df10000",
"0x38502733df10000"
]
},
{
"name": "the payout address holds the aggregator share",
"ok": true,
"detail": {
"balance": "253611648000000000"
}
},
{
"name": "segment 1 names segment 0 as its proven previous",
"ok": true,
"detail": {
"carrierNumber": "0x81",
"chainLen": "0x4",
"first": "0x77",
"keyHash": "0xc379ba2cdb239d2884d6bdb391d243ddfa869ab95ec4e72372e0e31fc9025fa0",
"last": "0x7a",
"proofHash": "0xed42fb45a37c81f151b2fde1b2b9b35ce0c76f7b59145eaa428f6760b739cae4",
"proofInPool": true
}
},
{
"name": "chain rule: a fresh-chain record for segment 1 is refused while segment 0 is proven",
"ok": true,
"detail": {
"accepted": false,
"block": "0x43b605649b1d40550fc280a520950a328b25e733b4efe9cc0a204e31e9351022",
"first": "0x7b",
"keyHash": "0xc379ba2cdb239d2884d6bdb391d243ddfa869ab95ec4e72372e0e31fc9025fa0",
"last": "0x7e",
"new": false,
"reason": "segment 123..126 does not chain to segment 119..122 (chain_len 4), which is proven (record paid at chain block 129)"
}
},
{
"name": "chain rule: the continuing record (chain_len 8) is accepted",
"ok": true,
"detail": {
"accepted": true,
"block": "0x43b605649b1d40550fc280a520950a328b25e733b4efe9cc0a204e31e9351022",
"first": "0x7b",
"keyHash": "0xc379ba2cdb239d2884d6bdb391d243ddfa869ab95ec4e72372e0e31fc9025fa0",
"last": "0x7e",
"new": true,
"reason": "accepted"
}
},
{
"name": "segment 1 paid with chain_len 8",
"ok": true,
"detail": {
"carrierNumber": "0x87",
"chainLen": "0x8",
"keyHash": "0xc379ba2cdb239d2884d6bdb391d243ddfa869ab95ec4e72372e0e31fc9025fa0",
"payout": "0x4343434343434343434343434343434343434343",
"wei": "0x38505a6ce4a8000"
}
},
{
"name": "segment 2 is pending with a deadline",
"ok": true,
"detail": {
"deadline_daa": 191,
"status": "pending"
}
},
{
"name": "known-failed: segment 3 cannot start a fresh chain while segment 2 is pending",
"ok": true,
"detail": {
"accepted": false,
"block": "0x4f502ffcbe86530352096707a93074ee8e1d43e3d2e94b06b8c71735c9eb0b46",
"first": "0x83",
"keyHash": "0xc379ba2cdb239d2884d6bdb391d243ddfa869ab95ec4e72372e0e31fc9025fa0",
"last": "0x86",
"new": false,
"reason": "segment 131..134 does not chain to segment 127..130 (chain_len 4), which is pending until DAA 191"
}
},
{
"name": "known-failed: segment 2 is unproven after its deadline",
"ok": true,
"detail": {
"deadline_daa": 191,
"status": "unproven"
}
},
{
"name": "known-failed: a late record for segment 2 pays nothing (refused as unproven)",
"ok": true,
"detail": {
"accepted": false,
"block": "0xb46575c11a6e42efd2cdbc8a450c0f169c069409a1f6e107c7418cea9c594623",
"first": "0x7f",
"keyHash": "0xc379ba2cdb239d2884d6bdb391d243ddfa869ab95ec4e72372e0e31fc9025fa0",
"last": "0x82",
"new": false,
"reason": "unproven: the record is carried at DAA 194, after the segment's deadline DAA 191"
}
},
{
"name": "segment 3 restarts the chain with a fresh-chain record after the unproven segment",
"ok": true,
"detail": {
"accepted": true,
"block": "0x4f502ffcbe86530352096707a93074ee8e1d43e3d2e94b06b8c71735c9eb0b46",
"first": "0x83",
"keyHash": "0xc379ba2cdb239d2884d6bdb391d243ddfa869ab95ec4e72372e0e31fc9025fa0",
"last": "0x86",
"new": true,
"reason": "accepted"
}
},
{
"name": "segment 3 paid with chain_len 4",
"ok": true,
"detail": {
"carrierNumber": "0xc1",
"chainLen": "0x4",
"keyHash": "0xc379ba2cdb239d2884d6bdb391d243ddfa869ab95ec4e72372e0e31fc9025fa0",
"payout": "0x4343434343434343434343434343434343434343",
"wei": "0x3850c0edd68a800"
}
},
{
"name": "the status counts proven and unproven segments",
"ok": true,
"detail": {
"pending": 15,
"proven": 3,
"unproven": 1
}
},
{
"name": "a v1 shard is paid 90% of its block share (one shard a block here)",
"ok": true,
"detail": {
"number": "0xc3",
"shardWei": "0x7ebcd81877b9c00",
"credit": "0x8cd1d3a96895800"
}
}
],
"ok": true
}