Dev fee: the test-network measurement in the bench log; run.mjs waits for the nodes and edits the override as text
9 fee blocks in the 785 blocks of the two fee-paying miners (1.15%, expected 1 in 100 templates), the miners' fee counters equal the chain's count on both nodes, the control miner at --dev-fee 0 paid nothing. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
parent
6b4ec59648
commit
161e48c953
2 changed files with 56 additions and 6 deletions
|
|
@ -1051,3 +1051,43 @@ moving (150.8M at the height, then stepping down as PC 2's card paused for a pro
|
|||
the chain; a consensus rule changed under a running network with miners on three platforms. The first measurement of
|
||||
v2 on the devnet's own regime (two large miners, bursty parallel blocks) needs PC 2 back from its job; the cloud
|
||||
numbers stand meanwhile (settle 157 to 272 s, no swing).
|
||||
|
||||
## 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.
|
||||
|
|
|
|||
|
|
@ -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