From 72486a7cf9371f8c8fc66dd861ef31b8f071fbbc Mon Sep 17 00:00:00 2001 From: igneum-labs <337424239+igneum-labs@users.noreply.github.com> Date: Tue, 6 Oct 2026 22:03:12 +0000 Subject: [PATCH] Vote or burn, weighed: verdict against the burn, for the signing bonus at genesis (docs/analysis/vote-or-burn.md, vote_weigh.py) Devnet 24-h silence measured per key from the observer (participation and bitmap), tonight's pause closed at 7082 (20:42:57Z, the frozen table's expiry), precedent for twelve penalty and reward episodes with sources, the 95 percent test made operational, the attack arithmetic extended from cost_model.py (one base: the producer share; 6,206 IGN/h at 34 percent, not 7,757), the replay-test gate before either switch leaves never. Co-Authored-By: Claude Fable 5.1 --- docs/analysis/vote-or-burn.md | 155 ++++++++++++++ sim/horizon/consensus-security/vote_weigh.py | 200 ++++++++++++++++++ .../consensus-security/vote_weigh_results.md | 83 ++++++++ 3 files changed, 438 insertions(+) create mode 100644 docs/analysis/vote-or-burn.md create mode 100644 sim/horizon/consensus-security/vote_weigh.py create mode 100644 sim/horizon/consensus-security/vote_weigh_results.md diff --git a/docs/analysis/vote-or-burn.md b/docs/analysis/vote-or-burn.md new file mode 100644 index 00000000..d025614a --- /dev/null +++ b/docs/analysis/vote-or-burn.md @@ -0,0 +1,155 @@ +# Vote or burn, weighed + +6 October 2026, 22:00 to 23:30 UK (21:00 to 22:30Z), written while the live devnet's pause of the evening ended. Lane: vote-weigh (research). The owner's order, verbatim: "Vote or burn, weigh it up, implement only if 95%+ of the mining community would respect it." The two mechanisms the node lane is building behind switches tonight: the burn (a key in the weight table that signed no vote in the last window has 20 percent of its producer share burned on every block it mines until it signs; lane 1's rank 3, `docs/analysis/horizon/consensus-security.md`) and the signing bonus (10 percent of the producer share paid only to keys that signed in the last window, the unsigned part to the proving pool, nothing destroyed). Arithmetic: `sim/horizon/consensus-security/vote_weigh.py` and its `vote_weigh_results.md`. Data: the observer's Neon tables (`live_certificates`, `live_checkpoints`, `live_blocks`, `miner_logs`), read with SELECTs only; the hub's `/api/checkpoint` and `/api/stats`. Precedent: sourced per case in section 2, approximate where marked. + +## The verdict, one page + +**Neither mechanism closes the line. Both price silence. Only the bonus passes the 95 percent test, and only at genesis.** + +1. **Honest silence, measured.** 10.4 percent of the 83 staying keys' 45,176 key-checkpoints over 24 hours sat under participation 0.5; 79 percent of that is 15 fleet keys the Devnet 2 gate swapped off the live chain and back, mining nothing while away. The 19 always-on desktop keys dipped under 0.5 in 3.4 percent of checkpoints, longest dip 34 minutes, which on mainnet's 2-hour window never reaches 0.5. Tonight's 20 silent keys mined nothing while silent, so the burn would not have shortened the pause. + +2. **History.** Every reward cut was fought and lost by the miners who stayed (Ethereum three times, Zcash three times, Ergo at 92 percent); where a cut removed a class's subsidy, the class left (Decred: two thirds of hash gone in a month). Offline penalties are accepted only as the reward forgone (Ethereum 0.625 against 0.844 earned; Cosmos 0.01 percent). No proof-of-work chain takes coins from a found block for a liveness fault. + +3. **The 95 percent test.** Respect: 7-day hash at least 95 percent of the week before, no fork over 5 percent at 30 days, 95 percent of weight signing. Estimates: burn 70 to 80 percent (a 20 percent cut of a found block for an outage, without precedent, and for ever from `--no-vote` miners and pool members without a verifier). Bonus at genesis 93 to 97 percent (nobody loses what they had). Bonus by signal after launch 85 to 90 percent. A bonus from the proving pool: 97 percent, deters nothing. + +4. **Security.** Weight is blue blocks (W2); an unpaid block is still weight, so a silent third keeps the veto under every mechanism. Base: the producer share. The burn prices a 34 percent set's silence at 6,206 IGN an hour (51-percent.md's 7,757 was 20 percent of the whole subsidy), the bonus at 3,103: USD 372 or 186 per 12-hour pause at USD 0.005; a deposit worth a double spend covers either. Weight-gated deep fork choice removes the prize; LEAVE ends tonight's class of pause. + +5. **Recommendation.** No burn: `vote_burn_bps` stays never and leaves the tree before the testnet code is public. The bonus, `signing_bonus_bps` 1,000 (node tree ca3-v4-0316 10db4b61), on from the testnet genesis as the schedule, never by signal: silence = a voter of the table at the latest checkpoint in the block's past with no vote in the presence window (7,200 s, 240 indices); a young key and a key under dust read as present; the unsigned tenth to the proving pool. Gate before the switch leaves never: the replay test of section 5, then the owner's word. The miner's sentence: **"Igneum pays 80 percent of each block to its miner. 8 of those 80 points are for signing finality, which your miner does by itself every 30 seconds. Miss two hours of signing and your next blocks pay 72 until you sign again. Nothing is burned."** + +## 1. Who is silent honestly, and how often + +### 1.1 The devnet's last 24 hours (observer `live_certificates`, 21:50Z 5 Oct to 21:50Z 6 Oct, 2,880 certificates) + +Two readings per key per certificate: the node's participation (spec 03 Q2, block reading over the presence window, 20 indices on the devnet) stored in the voter table, and the certificate's own bitmap. The bitmap is the first certificate the observer saw, before the Q4 fold adds the votes that arrive after quorum (lane 3: the first certificate carries 7 to 10 of 12 signers, the last vote lands 1.45 s later), so "signed" under-reads by about 10 points for every always-on key; participation is the measure the burn would test. + +| Population | Keys | Key-checkpoints | Participation 0 | Under 0.5 | Under 1 | +|---|---|---|---|---|---| +| Every voter key | 116 | 57,739 | 14.3% | 16.1% | 20.5% | +| Stayers (in the table at the end) | 83 | 45,176 | 8.9% | 10.4% | 15.1% | +| Leavers (gone before the end) | 33 | 12,563 | 33.8% | 36.3% | | +| The 19 always-on keys of the three desktops (two 1-key, one 8-key, one 9-key set) | 19 | 24,994 | | 3.4% | | + +Where the stayers' silence sits: 15 fleet keys (first seen at index 6111 to 6599, weights 17 to 228) hold 3,182 of the stayers' 4,034 participation-0 checkpoints (79 percent): `a5c164cafce7` 438 of 620, `aedc45a38203` 412 of 658, `9132e86d8eed` 293 of 387 and twelve more. The first desktop's 8-key set holds 417 (the 34-minute job pause), the third desktop's key 278, everything else 157. These are the Devnet 2 gate's boxes, swapped off the live chain for a rehearsal and back (`tools/fleet/box-node-swap.sh`), with the same vote key. They mined no blocks while away (0 blocks in any whole hour at participation 0). The honest-silence catalogue the task names, against what the devnet shows: + +| Class | What the rule sees | Devnet evidence | Burn on mainnet (2-h window, participation under 0.5) | Bonus (one vote in the last 2 h) | +|---|---|---|---|---| +| Solo miner whose node is behind or offline | no blocks while off (nothing to burn); on return participation 1 - h/2 for an outage of h hours | a third Windows desktop: 5 streaks of 20 to 139 checkpoints (10 to 70 min) at participation 0 or 0.05 while producing blocks, 44 of its 603 blocks mined under 0.5; the one key that mined through silence in 24 h | bites only after an outage over 1 h, for up to 1 h of blocks; the desktop's 70-min streak would have cost 20% of about 10 blocks | one checkpoint (30 s) after return | +| Pool whose signer process died | the pool's key silent, every member key unaffected under 9.6 (members sign their own); a custodial pool's one key silent | none on the devnet (no pool runs) | 20% of the pool key's blocks after the first hour until restart plus 1 h | 10% from the second hour until restart plus 30 s | +| Miner behind a NAT that never receives votes | receiving votes is the aggregator's need, not the voter's; a voter needs blocks (any outbound peer) and its own vote reaches the chain in its own blocks (Q2) and over gossip | the rented boxes peer outbound through the seed only (bench-log, "finality route") and signed 83 of 91 at 6824 to 6842 | none, unless the node has no peer at all, which is the offline row | none | +| HiveOS rig that restarts nightly | a dip of minutes; vote key derived from the identity label so it survives the restart (`finality.rs` line 100) | the 8-key desktop: 34-min miners-stopped pause (07:22 to 07:57Z, the bench-log's run 2), then dips of 3 to 9 checkpoints | a 6-min reboot leaves participation at 0.95: nothing | nothing | +| Laptop miner | asleep 8 h a day; mines nothing asleep | the Mac's hibernation of 4 Oct (bench-log); no laptop key in tonight's table | 20% of the first hour's blocks after each wake: 2.5% of its income | 0.01% | +| Miner on `--no-vote` | never signs | the app ships the switch (`config.rs` `vote: true` default, `engine.rs` passes `--no-vote`); one miner on the third desktop ran an hour without a vote: 147 blocks, 51 checkpoints as a voter, 0 signed | 20% for ever | 10% for ever | +| Pool member whose only checkpoint source is the pool | MUST NOT vote (spec 09 9.7 item 2) | none yet | 20% for ever | 10% for ever | +| Key under dust (under 100 blocks a month, about 0.004% of hash at 1 block/s) | not a voter (W3), cannot sign | 0 producers under dust in the observer's history | 0 if a non-voter reads as signed; else 20% for ever | 0 if a non-voter reads as signed; else 10% for ever | + +Missed-vote streaks in the bitmap reading (24 h, every key): 4,511 single-checkpoint misses, 1,813 of 2 to 4, 267 of 5 to 20, 69 of 21 to 120 (to 1 h), 31 over 120 across 28 keys. Every streak over 120 is a fleet departure or swap, or the third desktop. On mainnet's 240-index window a streak must pass 120 before the burn's test is met. + +### 1.2 Tonight's pause, closed (observer `live_checkpoints`) + +| Index | Time (UTC, UK) | What | Signing share of total | +|---|---|---|---| +| 6842 | 18:39:40Z, 19:39 UK | last lock before the pause; 79 of 91 signers | 79.7% | +| 6843 | 18:40Z | first unlocked checkpoint; 20 departed keys hold 42.7% of the table frozen at 6842 | 53.1% | +| 6876 to 6885 | 18:58 to 19:03Z | votes seen fall to 49 (the hands' own restarts) | 48.5 to 52.0% | +| 6912 | 19:14:53Z | stayers over two thirds of the sliding table; held by the frozen table (Q5) | 74.9% | +| 7081 | 20:42:40Z | last unlocked checkpoint; 239 in the run | 98.8% | +| 7082 | 20:42:57Z, 21:42 UK | first lock, DAA 216,412, 10 DAA past the frozen table's expiry at 216,402 (lane 3 predicted about 20:40Z); 47 of 75 voters | 86.8% | + +2 hours 0 minutes, the window exactly as spec 3.7 item 2 states for rule v3. The 20 keys were silent for a reason that was not theirs (the rehearsal job) and mined nothing while silent, so neither mechanism would have shortened the pause by one checkpoint or cost the departed keys a coin; the returners (`9825a3571f08`, `918f8ffa2d4b`, `ad7a53e9f2d5` and others back by 21:2xZ) would have paid 20 percent on their first 10 devnet minutes, or their first hour on mainnet. The 10 pause episodes of three or more unlocked checkpoints since 4 October (94, 164, 11, 15, 54, 239, 3, 10, 239 checkpoints, plus the first-month fill) all have the same cause class: weight leaving at once. + +### 1.3 Consequence of the measurements per tier + +A home card under 100 blocks a month is paid in full under the recommended rule; a rig or pool key loses 8 points only after two hours without a vote, which the client never does by itself; a pool member runs a verifier or earns 72; a holder's finality is unchanged by either mechanism; a prover gains the tenth. The 3.4 percent honest dip rate of always-on machines is a devnet-window number; on mainnet's window it is 0.0 percent burnable, so a rig loses nothing to the burn unless its node is down over an hour. A laptop loses 2.5 percent of income to the burn and 0.01 percent to the bonus. The third desktop's 44 silent-mined blocks are the real honest case: a node that stalls after restarts, which the app should alarm on (lane 1 rank 4: "two checkpoints without a vote") whichever mechanism ships. A pool member on the pool's checkpoint feed loses 20 or 10 percent for ever under the rule as specified; the pool spec's answer is the light client (section 10), which is not built. + +## 2. Precedent: how mining communities took penalties and rewards + +Figures from the two research passes of this evening; approximate where marked; sources under each block. + +| Case | What was asked of miners | Acceptance | How measured | What they did when it bit | +|---|---|---|---|---| +| Ethereum uncle rewards (2015 to 2022) | include uncles for 1/32 of the reward each; an uncle earns 7/8 down to 2/8 by distance | uncle rate 6 to 8% in 2016, long-run about 5.7%, peak about 16% in 2018 (approx.) | network uncle rate | complied and optimised (spread nodes); EIP-100 removed the "inflate your uncle rate" exploit with no protest | +| Ethereum EIP-649 and EIP-1234 (5 to 3 to 2 ETH) | a 40% then 33% reward cut, bundled with bomb relief | no miner vote; counter-EIPs 1295 and 1227 filed and refused | hash 157 to 136 TH/s in the month after Constantinople (-13%), back up within weeks | lobbied, lost, complied | +| Ethereum EIP-1559 | base fee burned | pools holding over 50% of hash stated opposition (Sparkpool, Ethermine, Flexpool); F2Pool for | the 1 April 2021 51% "show of force" was planned and not executed; hash at a new high a month after London | threatened, folded, mined on | +| Ethereum PoS inactivity leak and offline penalty | attest every epoch; offline costs 0.625 of the base reward against 0.844 earned; the leak is quadratic once finality fails 4 epochs | the only mainnet leak (12 May 2023, 9 epochs, 64 min, 65% offline) cost about 28 ETH across about 360,000 offline validators, under 0.0001 ETH each | post-mortem figures | patched clients; no dispute; the symmetry (penalty about equal to reward forgone) is the accepted norm | +| Bitcoin SegWit (BIP9 95%, BIP148, BIP91 80%) | signal, then accept that non-signalling blocks are orphaned | 25 to 45% for 8 months; 90% within days of BIP91; 100% over the next 2,016 blocks | signal share | miners accepted a rule that orphaned their own blocks only once 80% had already signalled and the UASF would have orphaned them anyway; about zero blocks orphaned (approx.); the minority forked to BCH at 5 to 10% of SHA-256 long-run | +| Zcash dev funds (20% three times) | mine for 80% | miners given a coinbase vote in 2019 and cast 0 votes; no pool signalled in 2024; "100% to miners" polled 9.2% in 2025 | polls, hashrate | complied under all three regimes; Ycash fork negligible | +| Monero tail emission (June 2022) | nothing new; a floor | celebrated; no fork | hashrate | not a penalty case | +| Monero RandomX and the three CryptoNight forks | lose your hardware's edge | hash -75 to -90% at each fork, honest hash up after | hashrate | ASICs forked once (XMC, now under 0.3% of XMR hash) then left; GPUs left for other coins; no pool resisted | +| Monero Qubic selfish mining (2025) | adopt "publish or perish" (late blocks lose weight) | no miner or pool objection in the thread; soft-fork variant needs honest majority adoption only | thread, hashrate | the community moved hash off Qubic under social pressure; the rule change is still proposed, not shipped | +| Kaspa Crescendo (May 2025) | upgrade nodes and pool software; no reward change | 99% of mining share on v1.0.0 four days before the flag day | mining share by version | complied; the easy case, nothing taken | +| Decred DCP-0010 and 0011/0012 (PoW 60% to 10% to 1%, BLAKE3) | lose most of the subsidy, then the algorithm | stakeholders 99.75% of non-abstaining tickets; miners had no vote | hash 345 to 115 PH/s in the month of the first cut, about 0 after BLAKE3 | two thirds left in a month; the ASIC remainder was obsoleted; no fork | +| Ergo EIP-27 (12 ERG per block held back) | a 19% cut for current miners, for a longer emission | 888 of 1,024 blocks needed (86.7%); passed at over 92% after months of pool campaigning (HeroMiners, GetBlok vote) | signal share | grumbled, signalled, complied | +| Ergo storage rent | extra income for miners | indifferent uptake (one pool collecting by 2025) | collected ERG | no objection: it pays them | +| Cosmos Hub downtime slashing | sign; miss 95% of a 10,000-block window and you are jailed and slashed 0.01%; 5% for double signing | the known gripe of Cosmos validators and still accepted | jail events | restart and unjail | + +Sources. Ethereum: https://eips.ethereum.org/EIPS/eip-649 , https://eips.ethereum.org/EIPS/eip-1234 , https://github.com/ethereum/EIPs/pull/1295 , https://www.minerupdate.com/news/miner-insights/effects-of-constantinople-upgrade-on-ethereum-network-difficulty , https://www.theblock.co/post/96316/ethereum-mining-pools-divided-eip1559 , https://cointelegraph.com/news/ethereum-miners-plot-hash-power-show-of-force-against-eip-1559 , https://www.coindesk.com/tech/2021/09/13/ethereum-hashrate-reaches-all-time-high ; PoS: https://eth2book.info/latest/part2/incentives/rewards/ , https://eth2book.info/latest/part2/incentives/inactivity/ , https://medium.com/offchainlabs/post-mortem-report-ethereum-mainnet-finality-05-11-2023-95e271dfd8b2 , https://docs.ethstaker.org/help/validator-offline ; Bitcoin: https://github.com/bitcoin/bips/blob/master/bip-0091.mediawiki , https://github.com/bitcoin/bips/blob/master/bip-0148.mediawiki , https://bitcoinmagazine.com/technical/bip-91-has-activated-heres-what-means-and-what-it-does-not , https://news.bitcoin.com/bip91-activates-while-fork-still-looms-in-the-backdrop/ , https://en.bitcoin.it/wiki/Pay_to_script_hash ; Zcash: https://zfnd.org/community-sentiment-polling-results-nu4/ , https://zips.z.cash/zip-1014 , https://zips.z.cash/zip-1015 , https://forum.zcashcommunity.com/t/miner-signaling-for-dev-fund-discussion-2024/47860 , https://zfnd.org/results-of-zcap-dev-fund-poll/ ; Monero: https://monero.observer/monero-enters-tail-emission-era/ , https://www.trustnodes.com/2018/04/09/moneros-hashrate-plunges-80-asics-hardfork , https://en.cryptonomist.ch/2019/05/08/mining-monero-hashrate-pow-change/ , https://www.minerupdate.com/news/miner-insights/cpu-mining-dominates-monero-since-randomx-upgrade , https://github.com/monero-project/research-lab/issues/144 , https://arxiv.org/html/2512.01437v2 ; Kaspa: https://github.com/kaspanet/kips/blob/master/kip-0014.md , https://github.com/kaspanet/rusty-kaspa/releases/tag/v1.0.0 , https://x.com/kaspaunchained/status/1918066300816929059 ; Decred: https://docs.decred.org/governance/consensus-rule-voting/consensus-vote-archive/ , https://github.com/decred/dcps/blob/master/dcp-0010/dcp-0010.mediawiki , https://xaur.github.io/decred-news/journal/202205 , https://xaur.github.io/decred-news/journal/202309 ; Ergo: https://www.ergoforum.org/t/eip-27-mainnet-activation-voting-and-final-details/3585 , https://docs.ergoplatform.com/mining/standards/eip27/ , https://docs.ergoplatform.com/mining/rent/ ; Cosmos: https://github.com/cosmos/mainnet/blob/master/params/README.md . + +What the record says, in three lines. A rule that costs nobody (Kaspa, tail emission, storage rent) is adopted at 99 percent without a vote. A rule that cuts a found block's reward is fought every time and accepted under duress, with 13 percent (Ethereum) to 67 percent (Decred) of hash leaving, and never by a miner vote (the only two miner votes on a cut, Zcash 2019 and Ergo 2022, drew 0 votes and 92 percent). A rule that penalises an offline validator is accepted only when the penalty is the reward forgone, or 0.01 percent of stake; no proof-of-work chain has one. + +## 3. The 95 percent test, made operational + +| Measure of respect | Proxy | Pass line | Where it is read | +|---|---|---|---| +| Keep mining | 7-day mean network hash after activation against the 7 days before, net of the GPU market (the same ratio for a reference GPU coin over the same window) | at least 95% | the hub's `/api/stats` hash series; the detector's epoch rows | +| Do not fork | the heaviest rival chain's share of hash at 30 days | under 5% | any explorer of a fork, if one appears | +| Run the signer | weight signing at steady state (participation 1 over the presence window, per key, weight-summed) | at least 95% of weight | `getFinalityWeights`; the hub's `/api/checkpoint` voters | +| Signal, when the change is by signal | 95% of a day's blue blocks on 7 consecutive days (lane 1 rank 6) | the rule itself | the P2 tally | +| Statements | the five largest pools and the two largest exchanges by volume | none against at activation | public | + +The estimates, and why: + +| Mechanism | Estimated respect | Reasoning | +|---|---|---| +| Vote-or-burn, 20% of the producer share, participation under 0.5 over the window | 70 to 80% | It is a 20 percent cut of a found block's reward on a liveness test. The record has no proof-of-work precedent; the nearest are Decred (two thirds left) and the Ethereum cuts (lobbied, 13 percent left). The relative size: Cosmos's downtime slash is 0.01 percent of stake once per jail; the burn is 20 percent of income for every hour of silence past the first. Honest classes it hits for ever: `--no-vote` miners (the app offers the switch) and pool members without a verifier (spec 09 9.7). The word "burn" on a liveness rule is itself a cost in every miner forum, and the rule does not end a pause (section 4). | +| Signing bonus, 10% of the producer share, at genesis | 93 to 97% | Nothing anyone had is taken: the schedule is 72 unconditional plus 8 for signing plus 20 for proving, and the official client signs by default. Ethereum's offline model (lose what you would have earned) is the accepted shape with a million validators. Fails only if a key under dust is read as unsigned (every small solo miner then earns 72 for ever, which is 10 percent of the solo tier on a Sybil pretext); the fix is one line. Pool members without a verifier earn 72, which is the pool spec's own incentive to ship the light client. | +| The same bonus, by signal after launch | 85 to 90% | Then it is a cut of 8 points from 80 and reads as EIP-1234: lobbied, bundled, resented. Passing a 95 percent signal for it is unlikely on the Ergo evidence (92 percent after months, for a cut that extended emission). | +| Burn with a 2-hour grace, 5 points per further window to 20 | 75 to 85% | A smaller burn is still a burn; the grace removes the laptop case and leaves the no-vote and pool-member cases. | +| Signing bonus carved from the proving pool, 2% of emission | 97%+ with miners, under 90% with provers | The producer share is never touched, so no miner objects; the pool loses a tenth; the price of silence is 2.5 percent of income, which deters nothing. A label, not a rule. | + +Grade: the burn fails the order's bar; the bonus passes it only as part of the genesis schedule; the third shapes do not beat the bonus. + +## 4. Security: does the bonus close the silent-majority line as well as the burn? + +Neither closes it, because the line is not about coins. Weight is blue blocks in the window (spec 03 W2); the veto is a third of that weight; a block that pays 72 or 64 instead of 80 is the same blue block. From `vote_weigh.py` (price USD 11.7 per GH/s-hour measured 6 Oct, subsidy 31.688 IGN/s, producer share 80 percent, IGN price inputs USD 0.005, 0.02 and 0.10, assumptions not predictions): + +| Silent share | Mechanism | Forgone per hour | Per 12-h pause at USD 0.005 / 0.02 / 0.10 | Over 30 days at USD 0.02 | Weight share | The pause | +|---|---|---|---|---|---|---| +| 34% | today | 0 | 0 | 0 | 34% | holds while silent | +| 34% | burn 20% | 6,206 IGN | USD 372 / 1k / 7k | USD 89k | 34% | holds | +| 34% | bonus 10% | 3,103 IGN | USD 186 / 745 / 4k | USD 45k | 34% | holds | +| 34% | pool-funded bonus 2% | 776 IGN | USD 47 / 186 / 931 | USD 11k | 34% | holds | +| 51% | burn 20% | 9,309 IGN | USD 558 / 2k / 11k | USD 134k | 51% (56% red-flooding) | holds | +| 51% | bonus 10% | 4,654 IGN | USD 279 / 1k / 6k | USD 67k | 51% (56%) | holds | + +Lane 1's 7,757 IGN an hour at 34 percent (`consensus-security.md` rank 3) omitted the 0.8 producer share; the figure is 6,206. Against what the pause buys: the 12-hour proof-of-work double spend costs USD 146 per GH/s of honest hash in rent (`cost_model.py` row 3) and the silent set at 34 percent already mines a third of it; the burn adds USD 372 to 7k per 12-hour window, the bonus half that. A deposit worth attacking covers either. At the equilibrium network the burn's daily price to a 34 percent set is USD 745 / 3k / 15k against a double-spend rent of USD 6k / 23k / 114k; both are small beside a deposit. + +What the bonus does that the burn does not: it destroys nothing (the unsigned points go to the proving pool of the same block, so the emission schedule and the cap are untouched); it gives every miner a reason to keep the signer on without giving any producer a reason to drop another key's votes (the points go to provers, not to the other voters, so 3.4.1's grinding argument is not even needed); and it survives a partition for the same reason the burn does (the test is on the block's own past, each side's keys sign their own checkpoints). What the burn does that the bonus does not: price silence at twice the rate. Neither touches the 56 percent red-flooding ceiling (that is block withholding, not vote withholding), neither shortens tonight's departure pause (the departed mined nothing), and neither moves the one-third bound. The security work remains: weight-gated deep fork choice removes the double spend during a pause (rank 2), LEAVE ends a departure pause in one hour (rank 7), the peer floor stops a star (rank 4). Not run on the fast-time harness; `vote_weigh_results.md` section 5 lists what the arithmetic leaves out. + +## 5. Recommendation + +| Parameter | Value | Why | +|---|---|---| +| Mechanism | signing bonus; no burn | section 3: the bonus passes at genesis, the burn does not pass anywhere | +| Fraction | 10% of the producer share (8 points of emission) | the node lane's figure; large enough to be the schedule's visible "signing" line, small enough that a miner reads 72 as a floor, not a fine | +| Test | the node lane's reading: a voter of the table at the latest checkpoint in the block's past that signed no vote in the presence window (7,200 s of median time, 240 indices) is silent; a young key counts as present | binary, computed from the block's own past like Q2, clears on the first checkpoint after a return (an outage costs one checkpoint, not an hour); the participation-under-0.5 test would cost a laptop 2.5 percent and a 70-min stall an hour of blocks | +| Non-voters | a key under dust (W3) reads as signed | otherwise the solo tier pays 10 percent for ever on a Sybil pretext; a key that splits itself to stay under dust forgoes its vote, which is the Sybil's own loss | +| Unsigned part | to the proving pool of the same block | nothing destroyed, no transfer to other voters, cap and schedule untouched | +| Grace | none beyond the window | the window is the grace: two hours without one vote | +| Activation | `signing_bonus_bps` 1,000 on from the testnet's first block as a genesis parameter, and on at mainnet genesis; never by signal | at genesis it is the schedule; after launch it is a cut (section 3); confirm against the testnet-infra branch whether the params field enters the genesis hash | +| Gate before the switch leaves never | the replay test: a fresh node synced from genesis across a switched-on span agrees on every coinbase with a node that was present throughout; then the owner's word | the silence reading comes from carried-vote records, which are pruned two windows back, so a syncing node must reach the same reading from what the chain carries or the rule forks the coinbase (coordinator, 6 Oct 2026, 22:4x UK) | +| The burn switch | `vote_burn_bps` (2,000 on the 0.3.17 tree, at never) removed before the public testnet repository, not left dormant | a dormant "burn" in a public tree is read as intent | +| Pool members | spec 09 9.7 stands: no verifier, no vote, so 72; the light client of section 10 is the pool tier's path to 80 | the bonus is the incentive the pool spec lacked | +| Companions | LEAVE (0.3.16), weight-gated deep fork choice, the peer floor and the "two checkpoints without a vote" alarm | these close the line; the bonus only prices it | + +The public sentence a miner reads (site, app, litepaper): + +"Igneum pays 80 percent of each block to its miner. 8 of those 80 points are for signing finality, which your miner does by itself every 30 seconds. Miss two hours of signing and your next blocks pay 72 until you sign again. Nothing is burned." + +If the order's bar is read strictly, "95 percent or more would respect it", the honest answer is: the burn no; the bonus yes at genesis only, with the dust line; nothing by signal after launch. What passes the bar without question is the work that does not touch the coinbase at all: LEAVE, the fork-choice gate and the peer floor, which are also the three that change what an attacker or an outage can do. + +## 6. What this lane could not do + +- No fast-time harness run of either mechanism (the node lane's switches were not in a built binary this lane could reach); the arithmetic is closed-form over spec 03 and `cost_model.py`. +- The devnet's honest-silence figures are a 24-hour sample of a fleet of rented boxes and three desktops, on a 10-minute window; the mainnet classes (laptops, HiveOS rigs, pools) are modelled, not measured. +- The third desktop's stalls (44 blocks mined at participation under 0.5, one hour with no vote at all) are measured and not diagnosed; the app's log lines for that hour are the next read. +- Precedent figures marked approximate were not pinned to a primary source by the research passes; the sourced ones are cited above. diff --git a/sim/horizon/consensus-security/vote_weigh.py b/sim/horizon/consensus-security/vote_weigh.py new file mode 100644 index 00000000..76039873 --- /dev/null +++ b/sim/horizon/consensus-security/vote_weigh.py @@ -0,0 +1,200 @@ +#!/usr/bin/env python3 +"""Vote-or-burn against a finality signing bonus: what each mechanism costs a silent attacker, what it costs an honest +miner whose key goes quiet for ordinary reasons, and what neither does to the weight table. The arithmetic behind +docs/analysis/vote-or-burn.md. Extends cost_model.py (same price, subsidy and share inputs; every input labelled there). + +Mechanisms (the producer share is 80% of the block subsidy, spec 02 2.5; the proving pool the other 20%): + none today's rule: silence costs nothing (docs/analysis/51-percent.md section 4 item 1) + burn20 a block whose key has participation under 0.5 over the presence window in the block's own past pays + 80% of its producer share; 20% is destroyed (lane 1 rank 3, horizon/consensus-security.md) + bonus10 10% of the producer share is paid only when the key signed in the last window; the unsigned part goes to + the proving pool; nothing destroyed (the node lane's sibling switch) + grace burn20 with a grace of one presence window: the first window of silence costs nothing, then the burn + rises 5 points per further window to 20 (a third shape) + poolbonus a signing bonus carved from the proving pool, 2% of emission (a tenth of the pool), paid pro rata to + the signing weight of each checkpoint; the producer share is never touched (a third shape) + +Participation and windows: presence window P = 7,200 s of past-median time on mainnet (spec 03 Q1, 240 indices of +30 s); the devnet's is 20 indices (10 min). Participation is the block reading of Q2: indices in the window with a +vote by the key over the window length, so an outage of h hours leaves participation at max(0, 1 - h/2) at the +moment of return and it climbs back by 1/240 per index afterwards. + +Run: python3 sim/horizon/consensus-security/vote_weigh.py [--outage-rate X] [--out file.md] + --outage-rate: the measured share of an always-on key's checkpoints at participation under 0.5 (devnet 6 Oct 2026 + over 24 h on the 10-min window: 3.4%; the simulator's resting guess is 2.2% of time in outage). +""" + +import argparse +import sys +import os + +sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) +from cost_model import PRICE, SUBSIDY_IGN_PER_S, PRODUCER_SHARE, IGN_PRICES, usd, md # noqa: E402 + +POOL_SHARE = 1.0 - PRODUCER_SHARE +P_HOURS = 2.0 # presence window, mainnet +EMISSION_PER_H = SUBSIDY_IGN_PER_S * 3600.0 + + +def producer_ign_per_hour(A): + return PRODUCER_SHARE * A * EMISSION_PER_H + + +# ---- what a silent set forgoes per hour, as a fraction of its producer income ---- +def silent_fraction(mech, hours_silent): + """Fraction of the producer share a key forgoes while silent, after hours_silent of silence.""" + if mech == "none": + return 0.0 + if mech == "burn20": + return 0.20 if hours_silent >= P_HOURS / 2 else 0.0 # participation under 0.5 after one hour + if mech == "bonus10": + return 0.10 if hours_silent >= P_HOURS else 0.0 # no vote in the last window + if mech == "grace": + if hours_silent < P_HOURS: + return 0.0 + steps = int((hours_silent - P_HOURS) // P_HOURS) + 1 + return min(0.20, 0.05 * steps) + if mech == "poolbonus": + # 2% of emission over the producer's 80%: the bonus a signing key of share A would have received is + # 0.02 x A x E; relative to its producer income 0.8 x A x E that is 2.5% + return 0.02 / PRODUCER_SHARE if hours_silent >= P_HOURS else 0.0 + raise ValueError(mech) + + +MECHS = ["none", "burn20", "bonus10", "grace", "poolbonus"] +MECH_NAMES = {"none": "today (no rule)", "burn20": "vote-or-burn 20%", "bonus10": "signing bonus 10% of producer share", + "grace": "burn with a 2-h grace, 5 points per window to 20", "poolbonus": "signing bonus from the pool, 2% of emission"} + + +def attacker_table(): + rows = [] + for A in (0.34, 0.45, 0.51): + for mech in MECHS: + f = silent_fraction(mech, 24.0) # the sustained case + per_h = f * producer_ign_per_hour(A) + rows.append([MECH_NAMES[mech], "%.0f%%" % (100 * A), "%.0f IGN" % per_h, + "%.1f M IGN" % (per_h * 24 * 30 / 1e6)] + + [usd(per_h * 24 * 30 * P) for P in IGN_PRICES] + + ["%.0f%%" % (100 * f), "unchanged: weight is blue blocks (W2), not coins"]) + return md(["mechanism", "silent share A", "forgone per hour", "forgone over a 30-day pause"] + + ["30 days at USD %g" % P for P in IGN_PRICES] + ["of its producer income", "its weight share"], rows) + + +def pause_vs_prize_table(): + """The pause's only cash value in the attack catalogue is the 12-h PoW double spend (cost_model row 3). How many + hours of pause each mechanism's price buys against a deposit of size D, at the equilibrium network.""" + rows = [] + for P in IGN_PRICES: + for mech in ("burn20", "bonus10", "poolbonus"): + f = silent_fraction(mech, 24.0) + per_h_usd = f * producer_ign_per_hour(0.34) * P + rows.append(["USD %g" % P, MECH_NAMES[mech], usd(per_h_usd), usd(per_h_usd * 12), usd(per_h_usd * 24 * 7), usd(per_h_usd * 24 * 30)]) + return md(["IGN price", "mechanism", "a 34% silent set forgoes per hour", "per 12-h pause (one double-spend window)", "per week", "per 30 days"], rows) + + +# ---- honest profiles ---- +def honest_loss(mech, profile): + """Expected fraction of a key's monthly producer income lost, by profile. Blocks are mined only while the machine + is up, so an outage costs nothing while it lasts; the cost is on the blocks mined after return while the test + still reads the key as silent, and on every block for a key that never votes.""" + name, up_hours_per_day, outages = profile + # outages: list of (count per 30 days, length in hours) + lost_hours = 0.0 + for count, length in outages: + if mech == "burn20": + # participation on return = max(0, 1 - length/2); under 0.5 when length > 1 h; climbs 1/240 per 30 s, + # so the blocks of the next (length - 1) hours, capped at 1 h, pay 80% + recovery = min(1.0, max(0.0, length - 1.0)) + lost_hours += count * recovery * 0.20 + elif mech == "bonus10": + # no vote in the last 2 h on return: the first checkpoint after return (30 s) pays 90%, then the key has signed + lost_hours += count * (30 / 3600.0) * 0.10 if length >= P_HOURS else 0.0 + elif mech == "grace": + if length >= P_HOURS: + steps = int((length - P_HOURS) // P_HOURS) + 1 + frac = min(0.20, 0.05 * steps) + # under grace the test is the same participation read, so the recovery hour applies at the stepped rate + lost_hours += count * 1.0 * frac + elif mech == "poolbonus": + lost_hours += count * (30 / 3600.0) * (0.02 / PRODUCER_SHARE) if length >= P_HOURS else 0.0 + mined_hours = up_hours_per_day * 30 - sum(c * l for c, l in outages) + return lost_hours / mined_hours if mined_hours > 0 else 0.0 + + +PROFILES = [ + ("always-on rig, one 2-min restart a night", 24, [(30, 2 / 60)]), + ("HiveOS rig, nightly reboot of 6 min", 24, [(30, 0.1)]), + ("home PC, node re-sync of 90 min once a week", 24, [(4, 1.5)]), + ("laptop miner, asleep 8 h a day", 16, [(30, 8.0)]), + ("pool signer process dead 6 h once a month (custodial pool key)", 24, [(1, 6.0)]), + ("solo miner whose box dies for 3 days once", 24, [(1, 72.0)]), +] + + +def honest_table(): + rows = [] + for prof in PROFILES: + cells = [prof[0]] + for mech in MECHS: + cells.append("%.3f%%" % (100 * honest_loss(mech, prof))) + rows.append(cells) + # the permanently silent, who mine every block they find without a vote + rows.append(["a miner on --no-vote, or a pool member with no verifier (spec 09 9.7 item 2), for ever"] + + ["%.1f%%" % (100 * silent_fraction(m, 1e9)) for m in MECHS]) + rows.append(["a key under dust (fewer than 100 blocks in 30 days): not a voter (W3)"] + + ["0%" if m in ("none",) else "0% only if the rule reads a non-voter as signed; else " + "%.1f%%" % (100 * silent_fraction(m, 1e9)) for m in MECHS]) + return md(["honest profile", "share of monthly producer income lost under: " + MECH_NAMES["none"]] + [MECH_NAMES[m] for m in MECHS[1:]], rows) + + +def outage_rate_table(rate): + """The always-on fleet as measured: the share of a key's checkpoints at participation under 0.5. On the devnet's + 10-min window a 26-min restart reads as 52 checkpoints at 0; on mainnet's 2-h window the same restart never + reaches 0.5. Scale: a dip of d minutes gives min participation 1 - d/W; under 0.5 needs d > W/2.""" + rows = [] + for d in (2, 6, 26, 60, 90, 180): + rows.append(["%d min" % d, "%.2f" % max(0.0, 1 - d / 10.0), "%.2f" % max(0.0, 1 - d / 120.0), + "yes" if d > 5 else "no", "yes" if d > 60 else "no"]) + t = md(["outage", "min participation, devnet 10-min window", "mainnet 2-h window", "burnable on the devnet", "burnable on mainnet"], rows) + t += "\n\nMeasured on the devnet, 6 October 2026, 24 h, the 19 always-on keys of the two PCs and the Mac (observer `live_certificates`): %.1f%% of key-checkpoints at participation under 0.5, the longest dip 34 min (the first Windows desktop's 8-key set at participation 0 for 69 checkpoints, 07:22 to 07:57Z, the Ember Tune run-2 miners-stopped pause of the bench-log), then 12 min (the second Windows desktop's 9 keys, 17:36Z), the rest under 5 min; so on the mainnet window the honest burnable share of these machines is 0.0%%." % (100 * rate) + return t + + +def equilibrium_note(): + hourly = producer_ign_per_hour(1.0) + out = [] + for P in IGN_PRICES: + neq = hourly * P / PRICE + out.append("| USD %g | %.0f GH/s | %s | %s | %s |" % (P, neq, usd(0.2 * producer_ign_per_hour(0.34) * P * 24), + usd(0.1 * producer_ign_per_hour(0.34) * P * 24), usd(0.51 / 0.49 * neq * 12 * PRICE))) + return "| IGN price | N_eq | burn: a 34% set forgoes per day | bonus: per day | 12-h double spend rent at N_eq |\n|---|---|---|---|---|\n" + "\n".join(out) + + +def main(argv=None): + ap = argparse.ArgumentParser() + ap.add_argument("--outage-rate", type=float, default=0.034) + ap.add_argument("--out", default="") + args = ap.parse_args(argv) + out = ["# Vote-or-burn against a signing bonus: the arithmetic", "", + "Generated by `sim/horizon/consensus-security/vote_weigh.py`. Inputs from `cost_model.py`: USD %.1f per GH/s-hour (measured 6 Oct 2026), subsidy %.3f IGN/s at full ramp, producer share %.0f%%, IGN price inputs USD %s (assumptions, not predictions). Presence window %.0f h (spec 03 Q1). An attacker at share A holds A of blocks and A of weight after 30 days (3.1)." % (PRICE, SUBSIDY_IGN_PER_S, 100 * PRODUCER_SHARE, ", ".join("%g" % p for p in IGN_PRICES), P_HOURS), "", + "## 1. What a silent set forgoes, and what it keeps", "", attacker_table(), "", + "Reading: no mechanism touches the weight table. Weight is blue blocks in the window (W2); a burned or unpaid block is still a blue block and still a vote-weight unit. A silent third holds the veto under every row. What changes is the price of holding it: zero today, 20 percent of its producer income under the burn, 10 percent under the bonus, 2.5 percent under the pool-funded bonus.", "", + "## 2. The price of a pause against what a pause buys", "", + "The catalogue gives the pause one cash value: the 12-hour proof-of-work double spend (`cost_model.py` row 3, USD 146 at 1 GH/s of honest hash to rent 51 percent for 12 hours). A 34 percent silent set already mines at 34 percent; to double-spend it rents the rest. The table is what the silence itself costs it, per window of use.", "", pause_vs_prize_table(), "", + "At the equilibrium network (hash joins until rent equals subsidy):", "", equilibrium_note(), "", + "Reading: at every price the burn makes a one-off 12-hour pause cost about half of one hour of the chain's whole producer subsidy, and the bonus about a quarter; a sustained pause costs the silent set 20 or 10 percent of its income for as long as it lasts. Neither changes the one-off calculus when the deposit is large: a double spend worth more than the forgone share pays either price. What removes the prize is the weight-gated deep fork choice (51-percent.md section 5 rank 2) and the LEAVE item (rank 7), not the price of silence.", "", + "## 3. What honest silence costs", "", honest_table(), "", + "Blocks are found only while a machine is up, so an outage costs nothing while it lasts under every mechanism; the burn bites on the blocks mined after return while participation is still under 0.5, the bonus on the one checkpoint after return. Both mechanisms, as specified, take 20 or 10 percent for ever from a key that mines without voting. Two honest classes do that today: a miner who switched voting off (the app ships the switch, `app/igneum-app/src/config.rs` `vote`, passed to the miner as `--no-vote`) and, under the pool protocol as designed, a pool member whose only checkpoint source is the pool (spec 09 9.7 item 2: no verifier, no vote). A key under dust is not a voter at all (W3); whether a non-voter reads as signed is a one-line choice in the rule and decides whether every small solo miner pays the bonus's 10 percent for ever.", "", + "## 4. Outage length against the window", "", outage_rate_table(args.outage_rate), "", + "## 5. What is not modelled", "", + "The pool-funded bonus's pro-rata payout changes the proving pool's size by a tenth and needs the pool rule of spec 05 5.3 re-cut; the bonus redirect to the proving pool pays a share of the silent set's forgone coins back to the silent set when it also proves (at 34 percent of blocks and some share of proofs); a partition is read from each block's own past under every mechanism, so neither side burns or loses the bonus for the other side's silence (lane 1's partition-safety argument holds for both); none of this is run on the fast-time harness.", + ] + text = "\n".join(out) + if args.out: + with open(args.out, "w") as fh: + fh.write(text + "\n") + print(text) + return 0 + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/sim/horizon/consensus-security/vote_weigh_results.md b/sim/horizon/consensus-security/vote_weigh_results.md new file mode 100644 index 00000000..3fc9aa92 --- /dev/null +++ b/sim/horizon/consensus-security/vote_weigh_results.md @@ -0,0 +1,83 @@ +# Vote-or-burn against a signing bonus: the arithmetic + +Generated by `sim/horizon/consensus-security/vote_weigh.py`. Inputs from `cost_model.py`: USD 11.7 per GH/s-hour (measured 6 Oct 2026), subsidy 31.688 IGN/s at full ramp, producer share 80%, IGN price inputs USD 0.005, 0.02, 0.1 (assumptions, not predictions). Presence window 2 h (spec 03 Q1). An attacker at share A holds A of blocks and A of weight after 30 days (3.1). + +## 1. What a silent set forgoes, and what it keeps + +| mechanism | silent share A | forgone per hour | forgone over a 30-day pause | 30 days at USD 0.005 | 30 days at USD 0.02 | 30 days at USD 0.1 | of its producer income | its weight share | +|---|---|---|---|---|---|---|---|---| +| today (no rule) | 34% | 0 IGN | 0.0 M IGN | USD 0 | USD 0 | USD 0 | 0% | unchanged: weight is blue blocks (W2), not coins | +| vote-or-burn 20% | 34% | 6206 IGN | 4.5 M IGN | USD 22k | USD 89k | USD 447k | 20% | unchanged: weight is blue blocks (W2), not coins | +| signing bonus 10% of producer share | 34% | 3103 IGN | 2.2 M IGN | USD 11k | USD 45k | USD 223k | 10% | unchanged: weight is blue blocks (W2), not coins | +| burn with a 2-h grace, 5 points per window to 20 | 34% | 6206 IGN | 4.5 M IGN | USD 22k | USD 89k | USD 447k | 20% | unchanged: weight is blue blocks (W2), not coins | +| signing bonus from the pool, 2% of emission | 34% | 776 IGN | 0.6 M IGN | USD 3k | USD 11k | USD 56k | 2% | unchanged: weight is blue blocks (W2), not coins | +| today (no rule) | 45% | 0 IGN | 0.0 M IGN | USD 0 | USD 0 | USD 0 | 0% | unchanged: weight is blue blocks (W2), not coins | +| vote-or-burn 20% | 45% | 8214 IGN | 5.9 M IGN | USD 30k | USD 118k | USD 591k | 20% | unchanged: weight is blue blocks (W2), not coins | +| signing bonus 10% of producer share | 45% | 4107 IGN | 3.0 M IGN | USD 15k | USD 59k | USD 296k | 10% | unchanged: weight is blue blocks (W2), not coins | +| burn with a 2-h grace, 5 points per window to 20 | 45% | 8214 IGN | 5.9 M IGN | USD 30k | USD 118k | USD 591k | 20% | unchanged: weight is blue blocks (W2), not coins | +| signing bonus from the pool, 2% of emission | 45% | 1027 IGN | 0.7 M IGN | USD 4k | USD 15k | USD 74k | 2% | unchanged: weight is blue blocks (W2), not coins | +| today (no rule) | 51% | 0 IGN | 0.0 M IGN | USD 0 | USD 0 | USD 0 | 0% | unchanged: weight is blue blocks (W2), not coins | +| vote-or-burn 20% | 51% | 9309 IGN | 6.7 M IGN | USD 34k | USD 134k | USD 670k | 20% | unchanged: weight is blue blocks (W2), not coins | +| signing bonus 10% of producer share | 51% | 4654 IGN | 3.4 M IGN | USD 17k | USD 67k | USD 335k | 10% | unchanged: weight is blue blocks (W2), not coins | +| burn with a 2-h grace, 5 points per window to 20 | 51% | 9309 IGN | 6.7 M IGN | USD 34k | USD 134k | USD 670k | 20% | unchanged: weight is blue blocks (W2), not coins | +| signing bonus from the pool, 2% of emission | 51% | 1164 IGN | 0.8 M IGN | USD 4k | USD 17k | USD 84k | 2% | unchanged: weight is blue blocks (W2), not coins | + +Reading: no mechanism touches the weight table. Weight is blue blocks in the window (W2); a burned or unpaid block is still a blue block and still a vote-weight unit. A silent third holds the veto under every row. What changes is the price of holding it: zero today, 20 percent of its producer income under the burn, 10 percent under the bonus, 2.5 percent under the pool-funded bonus. + +## 2. The price of a pause against what a pause buys + +The catalogue gives the pause one cash value: the 12-hour proof-of-work double spend (`cost_model.py` row 3, USD 146 at 1 GH/s of honest hash to rent 51 percent for 12 hours). A 34 percent silent set already mines at 34 percent; to double-spend it rents the rest. The table is what the silence itself costs it, per window of use. + +| IGN price | mechanism | a 34% silent set forgoes per hour | per 12-h pause (one double-spend window) | per week | per 30 days | +|---|---|---|---|---|---| +| USD 0.005 | vote-or-burn 20% | USD 31 | USD 372 | USD 5k | USD 22k | +| USD 0.005 | signing bonus 10% of producer share | USD 16 | USD 186 | USD 3k | USD 11k | +| USD 0.005 | signing bonus from the pool, 2% of emission | USD 4 | USD 47 | USD 652 | USD 3k | +| USD 0.02 | vote-or-burn 20% | USD 124 | USD 1k | USD 21k | USD 89k | +| USD 0.02 | signing bonus 10% of producer share | USD 62 | USD 745 | USD 10k | USD 45k | +| USD 0.02 | signing bonus from the pool, 2% of emission | USD 16 | USD 186 | USD 3k | USD 11k | +| USD 0.1 | vote-or-burn 20% | USD 621 | USD 7k | USD 104k | USD 447k | +| USD 0.1 | signing bonus 10% of producer share | USD 310 | USD 4k | USD 52k | USD 223k | +| USD 0.1 | signing bonus from the pool, 2% of emission | USD 78 | USD 931 | USD 13k | USD 56k | + +At the equilibrium network (hash joins until rent equals subsidy): + +| IGN price | N_eq | burn: a 34% set forgoes per day | bonus: per day | 12-h double spend rent at N_eq | +|---|---|---|---|---| +| USD 0.005 | 39 GH/s | USD 745 | USD 372 | USD 6k | +| USD 0.02 | 156 GH/s | USD 3k | USD 1k | USD 23k | +| USD 0.1 | 780 GH/s | USD 15k | USD 7k | USD 114k | + +Reading: at every price the burn makes a one-off 12-hour pause cost about half of one hour of the chain's whole producer subsidy, and the bonus about a quarter; a sustained pause costs the silent set 20 or 10 percent of its income for as long as it lasts. Neither changes the one-off calculus when the deposit is large: a double spend worth more than the forgone share pays either price. What removes the prize is the weight-gated deep fork choice (51-percent.md section 5 rank 2) and the LEAVE item (rank 7), not the price of silence. + +## 3. What honest silence costs + +| honest profile | share of monthly producer income lost under: today (no rule) | vote-or-burn 20% | signing bonus 10% of producer share | burn with a 2-h grace, 5 points per window to 20 | signing bonus from the pool, 2% of emission | +|---|---|---|---|---|---| +| always-on rig, one 2-min restart a night | 0.000% | 0.000% | 0.000% | 0.000% | 0.000% | +| HiveOS rig, nightly reboot of 6 min | 0.000% | 0.000% | 0.000% | 0.000% | 0.000% | +| home PC, node re-sync of 90 min once a week | 0.000% | 0.056% | 0.000% | 0.000% | 0.000% | +| laptop miner, asleep 8 h a day | 0.000% | 2.500% | 0.010% | 2.500% | 0.003% | +| pool signer process dead 6 h once a month (custodial pool key) | 0.000% | 0.028% | 0.000% | 0.021% | 0.000% | +| solo miner whose box dies for 3 days once | 0.000% | 0.031% | 0.000% | 0.031% | 0.000% | +| a miner on --no-vote, or a pool member with no verifier (spec 09 9.7 item 2), for ever | 0.0% | 20.0% | 10.0% | 20.0% | 2.5% | +| a key under dust (fewer than 100 blocks in 30 days): not a voter (W3) | 0% | 0% only if the rule reads a non-voter as signed; else 20.0% | 0% only if the rule reads a non-voter as signed; else 10.0% | 0% only if the rule reads a non-voter as signed; else 20.0% | 0% only if the rule reads a non-voter as signed; else 2.5% | + +Blocks are found only while a machine is up, so an outage costs nothing while it lasts under every mechanism; the burn bites on the blocks mined after return while participation is still under 0.5, the bonus on the one checkpoint after return. Both mechanisms, as specified, take 20 or 10 percent for ever from a key that mines without voting. Two honest classes do that today: a miner who switched voting off (the app ships the switch, `app/igneum-app/src/config.rs` `vote`, passed to the miner as `--no-vote`) and, under the pool protocol as designed, a pool member whose only checkpoint source is the pool (spec 09 9.7 item 2: no verifier, no vote). A key under dust is not a voter at all (W3); whether a non-voter reads as signed is a one-line choice in the rule and decides whether every small solo miner pays the bonus's 10 percent for ever. + +## 4. Outage length against the window + +| outage | min participation, devnet 10-min window | mainnet 2-h window | burnable on the devnet | burnable on mainnet | +|---|---|---|---|---| +| 2 min | 0.80 | 0.98 | no | no | +| 6 min | 0.40 | 0.95 | yes | no | +| 26 min | 0.00 | 0.78 | yes | no | +| 60 min | 0.00 | 0.50 | yes | no | +| 90 min | 0.00 | 0.25 | yes | yes | +| 180 min | 0.00 | 0.00 | yes | yes | + +Measured on the devnet, 6 October 2026, 24 h, the 19 always-on keys of the two PCs and the Mac (observer `live_certificates`): 3.4% of key-checkpoints at participation under 0.5, the longest dip 34 min (the first Windows desktop's 8-key set at participation 0 for 69 checkpoints, 07:22 to 07:57Z, the Ember Tune run-2 miners-stopped pause of the bench-log), then 12 min (the second Windows desktop's 9 keys, 17:36Z), the rest under 5 min; so on the mainnet window the honest burnable share of these machines is 0.0%. + +## 5. What is not modelled + +The pool-funded bonus's pro-rata payout changes the proving pool's size by a tenth and needs the pool rule of spec 05 5.3 re-cut; the bonus redirect to the proving pool pays a share of the silent set's forgone coins back to the silent set when it also proves (at 34 percent of blocks and some share of proofs); a partition is read from each block's own past under every mechanism, so neither side burns or loses the bonus for the other side's silence (lane 1's partition-safety argument holds for both); none of this is run on the fast-time harness.