Merge origin/dev-fee (96270bd) into release-0.3.5
bench-log.md: both appended entries kept; the generated site pages rebuilt with node site/build.mjs.
This commit is contained in:
commit
29e3a0c1d3
5 changed files with 93 additions and 35 deletions
|
|
@ -1222,3 +1222,43 @@ Not measured: any real GPU. The job-time and interval guards, exit 43 and the ap
|
|||
RTX 5090, the gfx1036 or a Metal card; the first real run is owed from the fleet logs. The "no status" rule has not
|
||||
been tried against a hung RPC (only a stopped process). Unit tests: `cargo test -p igneum-miner -- guard` (7) and
|
||||
`cargo test -- watchdog` in `app/igneum-app` (11), both replaying recorded STATUS and WORKER FAULT lines.
|
||||
|
||||
## 4 October 2026 (evening), the software dev fee measured on a test network: 9 fee blocks in 785, the chain and the miners' counters agree
|
||||
|
||||
Decision of the evening: the Igneum Miner software takes a visible, switchable 1% dev fee (one block template in 100
|
||||
requested with the dev payout address, chosen by a template counter, never at random); the protocol carries no fee.
|
||||
Branch `dev-fee` of both repositories; `docs/design/miner-dev-fee.md`; FUD ledger E18.
|
||||
|
||||
Machine: Apple M5 Max, macOS 26.6.2, load 140 to 170 (many other agents' builds and runs alongside; only counts were
|
||||
taken, no rates). Network: `node tools/dev-fee/run.mjs --secs 600 --hold-ms 500`, two devnet-v4 nodes (`igneumd`
|
||||
3bfe346f) on 127.0.0.1 ports 29900 and 29910, network id igneum-devnet-957, the fast-time profile with proof of work
|
||||
skipped and `genesis_bits` at the floor so a CPU stub miner solves every template it holds. Three `igneum-miner`
|
||||
processes (dev-fee branch a2c7ba83, `--engine stub`, 1 thread, exponential hold with mean 500 ms, no voting), each
|
||||
paying its own test address: a and b at the default `--dev-fee 1`, c the control at `--dev-fee 0`. 600 s. Then
|
||||
`igneum-miner payouts` on both nodes: every block the node holds, counted by the `IGNA` payout address in its coinbase.
|
||||
|
||||
What the miners printed at start, verbatim:
|
||||
|
||||
dev fee 1% (1 block in 100) to 0xdfaea67368f3e3753397d878f97efe6aa8020c2e; --dev-fee 0 turns it off (a, b)
|
||||
dev fee off (--dev-fee 0); the default is 1% (1 block in 100) to 0xdfaea67368f3e3753397d878f97efe6aa8020c2e (c)
|
||||
|
||||
| Miner | `--dev-fee` | Blocks found (its summary) | Rejected | `fee=` in its summary | `dev-fee block` lines | Blocks to its own address on the chain |
|
||||
|---|---|---|---|---|---|---|
|
||||
| a | 1 (default) | 385 | 0 | 5 | 5 | 380 |
|
||||
| b | 1 | 400 | 0 | 4 | 4 | 396 |
|
||||
| c | 0 (control) | 397 | 0 | 0 | 0 | 397 |
|
||||
|
||||
The chain (`payouts`, identical on node 0, the miners' node, and node 1, its peer): 1,183 blocks; 380 + 396 + 397 to
|
||||
the three user addresses, 9 to the dev-fee address `0xdfaea6...0c2e` (0.761% of all blocks, 1.146% of the 785 blocks
|
||||
of the two fee-paying miners), and 1 block with no `IGNA` field, the genesis block. Found per miner = own blocks + fee
|
||||
blocks exactly (380 + 5, 396 + 4, 397 + 0), so every fee block the miners logged is on the chain and no other block
|
||||
went to the dev address. The control miner paid nothing.
|
||||
|
||||
Reading. The expectation is 1 in 100 templates; the stub miner found a block on most but not every template once the
|
||||
difficulty had risen on three miners at about 2 blocks/s against the 1 block/s target (a and b held about 500 templates
|
||||
each, 5 and 4 of them fee templates at positions 99, 199, ..., and converted 77 to 80% of templates into blocks), so
|
||||
the block share lands near 1% with the sampling noise of 9 events (1.15% here). The exactness claim is on the template
|
||||
side and is the unit test (`dev_fee_tests`: 100 of 10,000 at positions 99, 199, ...; 0 at `--dev-fee 0`; exact at 2 to
|
||||
100%); the chain test shows the fee blocks reach the chain and are counted the same by the miner and by both nodes.
|
||||
Not measured: worker (GPU) mode, where the fee template is one of the templates the background fetcher rotates through
|
||||
once a second per identity, so the share is 1 in 100 templates by time, not by job; and nothing on Windows.
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
|
@ -50,6 +50,11 @@
|
|||
}
|
||||
],
|
||||
"log": [
|
||||
{
|
||||
"date": "2026-10-04",
|
||||
"text": ", the software dev fee measured on a test network: 9 fee blocks in 785, the chain and the miners' counters agree",
|
||||
"short": ", the software dev fee measured on a test network"
|
||||
},
|
||||
{
|
||||
"date": "2026-10-04",
|
||||
"text": "Miner fault guards and the app watchdog measured against a fake worker",
|
||||
|
|
@ -195,6 +200,26 @@
|
|||
"text": "Devnet-v4 integration: nine branches merged, 3-node test network on the merged node, Windows cross-build",
|
||||
"short": "Devnet v4: nine branches merged into one node"
|
||||
},
|
||||
{
|
||||
"date": "2026-10-03",
|
||||
"text": "Proto-opencl: OpenCL path built and proven without AMD silicon",
|
||||
"short": "OpenCL worker built and proven without AMD silicon"
|
||||
},
|
||||
{
|
||||
"date": "2026-10-03",
|
||||
"text": "First devnet blocks on the real lottery hash: CPU, then Metal GPU, three worker implementations",
|
||||
"short": "First devnet blocks on the real lottery hash"
|
||||
},
|
||||
{
|
||||
"date": "2026-10-03",
|
||||
"text": "R3.26 / M15: PoW checked after the cheap checks, cache-build cap, attack before and after",
|
||||
"short": "Cache-build attack closed: 10.6 s of rebuilds to 14 ms"
|
||||
},
|
||||
{
|
||||
"date": "2026-10-03",
|
||||
"text": "Difficulty controller: devnet record, simulator, Igneum dual-lane rule, 3-node CPU test network",
|
||||
"short": "Igneum dual-lane difficulty rule built and simulated"
|
||||
},
|
||||
{
|
||||
"date": "2026-10-03",
|
||||
"text": "AMD gfx1036 , AMD OpenCL 2.1 driver 3652.0",
|
||||
|
|
@ -224,31 +249,6 @@
|
|||
"date": "2026-10-03",
|
||||
"text": "Per-identity hash rate \"decay\" on the RTX 5090: diagnosis and Metal reproduction",
|
||||
"short": "RTX 5090 hash-rate decay diagnosed: a miner bug, fixed"
|
||||
},
|
||||
{
|
||||
"date": "2026-10-03",
|
||||
"text": "Igneum-node devnet v2: sustained-mining finality rule v2 on a four-miner test network, and as a follower of the live devnet",
|
||||
"short": "Finality rule v2 live on a four-miner test network"
|
||||
},
|
||||
{
|
||||
"date": "2026-10-03",
|
||||
"text": "Execution layer devnet v3: revm over the selected chain, 3-node simnet, viem smoke test",
|
||||
"short": "EVM execution layer: identical state on three nodes"
|
||||
},
|
||||
{
|
||||
"date": "2026-10-03",
|
||||
"text": "Weak-program census: 400,000 program runs through the CPU reference, the redundant-load finding, and the rules for M5 and M6",
|
||||
"short": "Census of 400,000 programs: redundant loads found"
|
||||
},
|
||||
{
|
||||
"date": "2026-10-03",
|
||||
"text": "Proving v0: first SP1 proof of an Igneum block, Apple M5 Max CPU, loaded machine",
|
||||
"short": "First SP1 proof of an Igneum block, on a laptop CPU"
|
||||
},
|
||||
{
|
||||
"date": "2026-10-03",
|
||||
"text": "Windows node package: igneumd cross-compiled for x86_64-pc-windows-gnu, two-peer sync test",
|
||||
"short": "Windows node package: cross-compiled, two-peer sync"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,10 +30,13 @@ for (const b of [IGNEUMD, MINER]) if (!existsSync(b)) { console.error(`missing $
|
|||
|
||||
rmSync(TMP, { recursive: true, force: true }); mkdirSync(TMP, { recursive: true });
|
||||
const override = `${TMP}/override.json`;
|
||||
const params = JSON.parse(readFileSync(FILE, 'utf8'));
|
||||
params.skip_proof_of_work = true; // the node accepts any nonce; the stub miner still checks its own kHeavyHash
|
||||
params.genesis_bits = 0x207fffff; // target at the floor: the first nonce of every template passes the miner's check
|
||||
writeFileSync(override, JSON.stringify(params));
|
||||
// edited as text: JSON.parse would turn the u64 "never" sentinels into floats the node refuses
|
||||
const overrideText = readFileSync(FILE, 'utf8')
|
||||
.replace(/"skip_proof_of_work":\s*(true|false)/, '"skip_proof_of_work": true') // the node accepts any nonce; the stub miner still checks its own kHeavyHash
|
||||
.replace(/"genesis_bits":\s*\d+/, `"genesis_bits": ${0x207fffff}`) // target at the floor: the first nonce of every template passes that check
|
||||
.replace(/,\s*"proving_v0_activation_daa":\s*\d+/, ''); // a proving-branch field the devnet-v4 node does not know
|
||||
if (!/"skip_proof_of_work": true/.test(overrideText) || !/"genesis_bits": 545259519/.test(overrideText)) throw new Error('override edit failed');
|
||||
writeFileSync(override, overrideText);
|
||||
|
||||
// the user addresses: fixed test values, no keys behind them (the fee address is the miner's DEV_FEE_ADDRESS_DEVNET)
|
||||
const USER_A = '0x' + 'a1'.repeat(20), USER_B = '0x' + 'b2'.repeat(20), USER_C = '0x' + 'c3'.repeat(20);
|
||||
|
|
@ -53,7 +56,11 @@ class Node {
|
|||
const out = openSync(this.logFile, 'a');
|
||||
this.proc = spawn(IGNEUMD, a, { stdio: ['ignore', out, out] });
|
||||
started.push(this.proc);
|
||||
await sleep(1500);
|
||||
this.proc.on('exit', (c) => { if (!stopping) { console.error(`node ${this.i} exited with ${c}; see ${this.logFile}`); stopAll().then(() => process.exit(1)); } });
|
||||
for (let k = 0; k < 60; k++) { // until the node answers RPC
|
||||
if (spawnSync(MINER, ['watch', '1', this.grpc], { encoding: 'utf8', timeout: 15000 }).status === 0) break;
|
||||
await sleep(1000);
|
||||
}
|
||||
log(`n${this.i} up pid ${this.proc.pid} grpc ${this.grpcPort} p2p ${this.p2pPort}`);
|
||||
return this;
|
||||
}
|
||||
|
|
@ -64,7 +71,9 @@ function miner(argv, name) {
|
|||
started.push(p);
|
||||
return p;
|
||||
}
|
||||
let stopping = false;
|
||||
async function stopAll() {
|
||||
stopping = true;
|
||||
for (const p of started.slice().reverse()) { try { p.kill('SIGINT'); } catch { } }
|
||||
await sleep(1500);
|
||||
for (const p of started) { try { p.kill('SIGKILL'); } catch { } }
|
||||
|
|
@ -83,7 +92,8 @@ const pb = miner([...common('devfee-b', USER_B), '--dev-fee', '1'], 'miner-b');
|
|||
const pc = miner([...common('devfee-c', USER_C), '--dev-fee', '0'], 'miner-c');
|
||||
await sleep(3000);
|
||||
for (const n of ['a', 'b', 'c']) log(`miner-${n}: ${tailOf(`${TMP}/miner-${n}.log`, / dev fee /).map(l => l.replace(/^\S+ /, ''))[0] || '(no dev fee line yet)'}`);
|
||||
await new Promise(r => { let left = 3; for (const p of [pa, pb, pc]) p.on('exit', () => { if (--left === 0) r(); }); });
|
||||
await new Promise(r => { let left = 3; for (const p of [pa, pb, pc]) p.on('exit', (c) => { if (c !== 0 && !stopping) { console.error(`a miner exited with ${c} after ${((Date.now() - t0) / 1000).toFixed(0)} s; see ${TMP}/miner-*.log`); } if (--left === 0) r(); }); });
|
||||
if ((Date.now() - t0) / 1000 < SECS * 0.9) { console.error('the miners stopped early; no measurement'); await stopAll(); process.exit(1); }
|
||||
log(`miners done after ${((Date.now() - t0) / 1000).toFixed(0)} s`);
|
||||
await sleep(3000);
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue