Merge fee-switch into release-0.3.9: the prover mirrors both fee tables and fees_v1_activation_daa (new pinned guest), the devnet runbook for H = 210,000
Conflicts: proving/igneum-prove/export/src/main.rs (the two use lines: master's ensure kept, fee-switch's FeeParams and FeeSchedule taken, SHARD_PROVING_GAS_BUDGET gone), docs/bench-log.md (both entries), docs/testnet/README.md (both sentences), site/index.html and site/journey.json (master's, then node site/build.mjs: 518 links, 0 broken).
This commit is contained in:
commit
f7a41a2c71
33 changed files with 4317 additions and 117 deletions
|
|
@ -124,7 +124,7 @@ a full block costs tens of milliseconds of CPU; its floor is set by the spam ari
|
|||
| The other opcode and precompile entries | prototype shapes; calibrate per entry in SP1 with three input sizes (design R1) |
|
||||
| The intrinsic 300 | an upper bound that includes the per-shard fixed cost; a shard with many transfers will show the marginal number |
|
||||
| The 12 GB card time for `S_p` | approximate, from the simulation's share ratios; the phase 2 gate measures it |
|
||||
| The prover's mirror of the table | `proving/igneum-prove/core/src/config.rs` and `pgas.rs` carry the prototype values at `b7fca5a0`; they must change in lockstep with the node (the guest program's id changes, every fixture is re-cut at the new `S_p`), or the shard statement differs from the node's. Not changed tonight |
|
||||
| The prover's mirror of the table | Done 5 October 2026 (`docs/plans/fee-switch-devnet.md`): `proving/igneum-prove/core/src/config.rs` mirrors the node's `fees.rs` (both tables, `FeeSchedule::at`), the shard input carries the schedule and the block's DAA score, the guest was re-pinned. The prototype fixtures stay valid (no `fees` field = prototype, never); v1 fixtures were cut from a simnet run across the switch |
|
||||
| The devnet rollout | done as a height switch (5 October 2026): `Params.fees_v1_activation_daa` (override file, default never on devnet and simnet, 0 on testnet and mainnet, in the consensus digest). Chain blocks at or above the switch meter with v1 (every metering site in `igneum/exec` takes the block's DAA score, `fees::fee_params_at`); the first such block raises both base fees to the v1 floors. The live devnet keeps its history and its prototype rules until the switch is published with the 0.3.6 update (`docs/plans/release-0.3.6.md`, section 5). A fresh chain can instead carry `fees` in the override file (the fast-time profile does) |
|
||||
| The price assumption | $0.10 is an arithmetic assumption. The floor is a parameter the genesis rules leave to miners (60% signalling) and can be moved by them |
|
||||
|
||||
|
|
|
|||
|
|
@ -1435,3 +1435,18 @@ The fix, both sides ours. Fork (`vendor/igneum-node-txgen`, branch `txgen-export
|
|||
Also noted: the collect job uploads the first 256 KiB of a log file, so a tail needs `--command "powershell -NoProfile -Command Get-Content -Tail 500 logs\app-....log"`.
|
||||
|
||||
Commands: `tools/lock/with-lock.sh run node tools/txgen/run.mjs --duration 1200 --rate 2 --wallets 16 --fund 2 --cap 40 --summary <file>`; `node tools/txgen/proving-watch.mjs watch --interval 30 --duration 1560 --out <jsonl>`; `node tools/txgen/proving-watch.mjs report --summary <summary.json> --pc2-log <collected app log>`; `node tools/prove-fixtures/complete-export.mjs seq.json out.json 72803,72854`; `igneum-prove-export out.json 72803 proving/fixtures/block-72803-skipped-copies.json`.
|
||||
|
||||
## 5 October 2026, the prover carries both fee tables and the height switch: one pinned guest on either side of DAA 210,000
|
||||
|
||||
The adopted fee table (spec 05 section 5.11) reaches the devnet by `fees_v1_activation_daa` (`docs/plans/fee-switch-devnet.md`). Until today the prover's guest carried only the prototype table (`B_p` 30 M, `S_p` 7.5 M, intrinsic 200), so every shard statement after the switch would have differed from the node's plan. Now `igneum-prove-core` mirrors the node's `fees.rs` (both tables, `FeeSchedule::at`), the shard input carries the schedule and the block's DAA score, and the executor raises the carried base fees to the set's floors as the node does. The 328-byte public values are unchanged: the node's native veto (it recomputes every statement) is what pins the schedule a prover claims.
|
||||
|
||||
| Check | Command | Result |
|
||||
|---|---|---|
|
||||
| The node reads the switch | `cargo test --release -p igneum-exec` on fork 2b6d23ef (this Mac, target `vendor/igneum-node/target-036`, 15:32:27Z to 15:36:30Z) | 11 passed, 0 failed, among them `the_fee_switch_meters_by_the_block_daa_score` |
|
||||
| The digest for H = 210,000 | 20 s scratch node, override `{"difficulty_v2_activation_daa":33000,"proving_v0_activation_daa":84100,"fees_v1_activation_daa":210000}` | `ab8847da538dead1dc10e046dfaadab3c1c35928e3748810c4e050d4a886087a` |
|
||||
| One chain across the switch | private simnet on the 2b6d23ef binaries, override `{"fees_v1_activation_daa": 200}`, `tools/prove-fixtures/gen.mjs` before and after DAA 200, one `igneum_exportSegments` dump with every segment's `daaScore` | one chain, 358 segments, DAA 0 to 1,121: block 51 (DAA 187, prototype, 11 transactions, 7,494,392 pgas, one shard at `S_p` 7.5 M) before the switch; blocks 351 (DAA 1,105, 11 transactions, 36,934 pgas, two shards at `S_p` 30,000) and 355 (DAA 1,117, 14 transactions, 69,292 pgas, three shards) after it; `igneum_getBudgets` went from `provingGasLimit` 0x1c9c380 to 0x1d4c0 and the base fees to 100 gwei and 10,000 gwei at the switch. Found on the way: a burst signed with a 21 gwei cap just before the switch never executed after it (the floor is 100 gwei), and under v1 a modexp bomb's proving charge (pgas x 10,000 gwei) crosses the signed budget unless the gas limit covers it (design 4.1); gen.mjs now sizes both from the node's budgets |
|
||||
| The port replays both sides | `igneum-prove-export` on that dump: every segment's state root equals the node's, prototype below 200 and v1 at and above it | `replayed 358 segments from genesis; every state root equals the node's` for each of the three cuts; fixtures `fees-switch-prototype`, `fees-v1-shards2`, `fees-v1-shards3`; `igneum-prove-host --mode native` on each: MATCHES, the three tamper cases REJECTED |
|
||||
| The pinned guest on both sides | `igneum-prove-host <fixture> --mode execute` on this Mac (setup 37 s, `pinned: setup matches the manifest`) | `fees-switch-prototype` shard 0: 66,043,259 cycles, 44 cycles per EVM gas, 9 cycles per prototype pgas, 2.88 s; `fees-v1-shards2` shard 0: 4,717,439 cycles (213 cycles per v1 pgas, 0.38 s), shard 1: 3,485,430 cycles (236 per pgas, 0.26 s); aggregator 1.4 M cycles over 2 shards; every tamper case REJECTED. Under v1 these transfer-and-modexp shards run at about a quarter of the unit (1,000 cycles per pgas): the table over-charges them, which is the safe side of design R1's calibration |
|
||||
| The new pin | `proving/igneum-prove/pin-guests.sh` | shard program id `0x2b1a81cb413236cf063077b46ed3111628f6c41036bcf6e23ee4cbbf5679ef7a` (2,832,504 bytes), aggregator `0x474678f35f7545db28055d5e5bbc308231d84a5a072202087a2a8d5b09123896`, pinned 16:20:38Z; the 0.3.8 ids (`0x0dfade07...`, `0x135e67e7...`) are what every machine runs until 0.3.9 |
|
||||
|
||||
Block rate for H: DAA 111,230 at 15:23Z, 112,227 at 15:40:13Z, 0.965 blocks/s; H = 210,000 is 24 h ahead of a publish before about 19:50Z on 5 October (the runbook moves it otherwise).
|
||||
|
|
|
|||
127
docs/plans/fee-switch-devnet.md
Normal file
127
docs/plans/fee-switch-devnet.md
Normal file
|
|
@ -0,0 +1,127 @@
|
|||
# The devnet fee switch: calibrated v1 behind `fees_v1_activation_daa`, runbook (5 October 2026)
|
||||
|
||||
Owner's decision: "2 execute". The adopted fee table (spec 05 section 5.11: `B_p` 120,000 pgas, `S_p` 30,000,
|
||||
intrinsic 300, modexp 10 + 1 per 10 bytes, floors 100 gwei per gas and 10,000 gwei per pgas) goes live on the
|
||||
devnet at a DAA score H, by the height switch the 0.3.6 node fork carries (`docs/plans/release-0.3.6.md` section 5).
|
||||
Prepared by the consensus and execution engineer on branch `fee-switch` (worktree `igneum-wt-feeswitch`). Steps 1 to
|
||||
3 below are done; step 4 (the publish) waits for Igneum Miner 0.3.9, which must carry the new prover tools on the
|
||||
Mac. Nothing was published, no node was restarted, no override file was changed.
|
||||
|
||||
## 1. What changed, and what did not
|
||||
|
||||
| Side | Change | Where |
|
||||
|---|---|---|
|
||||
| Prover (changed) | `igneum-prove-core` mirrors the node's `fees.rs`: `PgasTable`, `FeeParams` (`PROTOTYPE`, `CALIBRATED_V1`), `FeeSchedule { base, v1_activation_daa }` with `at(daa)`. The shard input carries the schedule (`ShardInput.fees`) and the block's DAA score (`FixtureEnv.daa_score`); `execute_range` reads the set at that score, raises the carried base fees to its floors (as the node's `execute_segment` does), and meters with its intrinsic, `B_p` and modexp entry. One pinned guest serves before and after H | `proving/igneum-prove/core/src/{config,pgas,executor,shard,fixture}.rs` |
|
||||
| Prover (changed) | The exporter reads the schedule from the dump (`feesV1ActivationDaa`, `fees`) and each segment's `daaScore`, replays the whole chain with the switch applied per segment (every state root must equal the node's on both sides), and cuts at the set's `S_p` at the block | `proving/igneum-prove/export/src/main.rs`, `tools/prove-fixtures/{gen.mjs,net.sh}` |
|
||||
| Prover (changed) | The host prints and records the set, refuses a fixture whose consensus plan was cut at the wrong `S_p`, and tests fixtures on both sides of the switch: `fees-switch-prototype` (block 51, DAA 187, one 7.5 M shard) and `fees-v1-shards2`, `fees-v1-shards3` (blocks 351 and 355, DAA 1,105 and 1,117, 30,000-pgas shards), all from ONE private simnet chain with the switch at DAA 800, replayed from genesis across the switch with every state root equal to the node's (`docs/bench-log.md`, 5 October 2026, "the prover carries both fee tables") | `proving/igneum-prove/host/src/main.rs`, `proving/fixtures/` |
|
||||
| Prover (unchanged) | The 328-byte public values (`ShardOutput`). The switch is NOT a field of the statement. Reason: the node recomputes the statement natively (`igneum/exec/src/proving.rs::statement_bytes`) and a vetoed record pays nothing, so the layout is consensus (payouts land in state). A new layout would need its own digest-bearing switch and would fork any 0.3.8 node after it. What pins the schedule instead: a shard metered under another table has another `pgas_used`, another post-root (the floors change what is burned) and so another statement, and the node vetoes it (spec 7.2 item 5). A light verifier that needs the schedule in the statement is a follow-up (design 2.1 removes the duplicate executor) | |
|
||||
| Node (unchanged) | Fork 2b6d23ef already reads the switch everywhere (`fee_params_at(daa)`, the digest rule, the daemon's print). Confirmed on this Mac: `cargo test --release -p igneum-exec` 11 passed, 0 failed, among them `the_fee_switch_meters_by_the_block_daa_score` (15:32:27Z to 15:36:30Z, 4 min 03 s wall, target `vendor/igneum-node/target-036`) | |
|
||||
| Guest | Re-pinned: new program ids (section 3) | `proving/igneum-prove/elf/` |
|
||||
|
||||
## 2. The new pin (shard program id)
|
||||
|
||||
`proving/igneum-prove/pin-guests.sh` on this Mac, pinned 2026-10-05T16:20:38Z (SP1 crate 6.8.1, circuit v6.1.0):
|
||||
|
||||
| Guest | Program id | ELF |
|
||||
|---|---|---|
|
||||
| shard (`igneum-prove-program`) | `0x2b1a81cb413236cf063077b46ed3111628f6c41036bcf6e23ee4cbbf5679ef7a` | 2,832,504 bytes, sha256 `0x150f4c05a2951fc5...` |
|
||||
| aggregator (`igneum-prove-aggregator`, embeds the shard key) | `0x474678f35f7545db28055d5e5bbc308231d84a5a072202087a2a8d5b09123896` | 319,744 bytes |
|
||||
|
||||
The 0.3.8 ids, running on the Mac and PC 2 today: shard `0x0dfade071ffc05a50be5f7e6640fb12638bac0ea63697ec252863f55658be16a`, aggregator
|
||||
`0x135e67e742fbbcc8303676765266f25a6520ab36299820280125541051fb6c62`. A verifier on one id rejects proofs made under the other
|
||||
(`program id 0x... IS NOT OURS`), so every prover and verifier moves together (section 5, steps 2 to 5). `tools/ci/pinned-guests-check.sh` passes
|
||||
on the new `elf/`.
|
||||
|
||||
## 3. H and the digest
|
||||
|
||||
Measured block rate: DAA 111,230 at 15:23Z and 112,227 at 15:40:13Z (`igneum_getProvingStatus.tipDaa` of the Mac
|
||||
app node), 997 blocks in 1,033 s = 0.965 blocks/s, about 3,470 an hour, 83,300 a day.
|
||||
|
||||
H = 210,000. From 15:40Z that is 97,773 blocks, 28.1 h at the measured rate, so the devnet reaches H around
|
||||
19:50Z on 6 October 2026. The 24-hour rule at the moment of the publish: `H - tipDaa >= 86,400`, which holds for a
|
||||
publish before about 19:50Z on 5 October. If the publish is later than that, H moves to the next round thousand
|
||||
above `tipDaa + 86,400` and the digest is re-read (one 20-second scratch node, the command below; nothing else
|
||||
changes).
|
||||
|
||||
The digest with the override `{"difficulty_v2_activation_daa":33000,"proving_v0_activation_daa":84100,"fees_v1_activation_daa":210000}`,
|
||||
read on the 2b6d23ef node (`vendor/igneum-node/target-036/release/igneumd --devnet --override-params-file=<file>
|
||||
--appdir=<scratch> --rpclisten=127.0.0.1:60985 --listen=127.0.0.1:60986 --nodnsseed --nologfiles --yes`, 20 s,
|
||||
15:41:27Z to 15:41:50Z, then killed):
|
||||
|
||||
```
|
||||
Calibrated v1 fees from the override file: chain blocks metered with the adopted table, budgets and floors from DAA score 210000
|
||||
Proving v0 from the override file: provers paid from DAA score 84100
|
||||
Difficulty rule v2 from the override file: active from DAA score 33000
|
||||
Fees on igneum-devnet: pgas table v0, B_p 30000000 pgas, S_p 7500000 pgas, floors 1000000000 wei per gas and 1000000000 wei per pgas; calibrated v1 from DAA score 210000
|
||||
Consensus params digest: ab8847da538dead1dc10e046dfaadab3c1c35928e3748810c4e050d4a886087a (exchanged in the p2p handshake; a peer with another digest is refused)
|
||||
igneumd/2.1.0-2b6d23ef
|
||||
```
|
||||
|
||||
The live digest today (no fee switch) is `f10a4eab4b1f4f341d54b0b0221161d1122fac302bca90d6b61d14939b69fbd6`
|
||||
(`release-0.3.6.md` 8g). A node with the switch and a node without it never handshake, which is why section 5 moves
|
||||
every node in one sweep.
|
||||
|
||||
## 4. What every machine runs today, and what it must run before H
|
||||
|
||||
| Node | Binary today | Reads the switch | Before the override is published |
|
||||
|---|---|---|---|
|
||||
| App nodes (Mac d937c69d, PC 1 ae432dc7, PC 2 1ccfe586, PC 37ba0461, Sam's Mac 3a9bf309) | 0.3.8 app, node 2b6d23ef (PC 37ba0461 and Sam's Mac were on 0.3.7 and 0.3.5 at the 0.3.8 cut, `release-0.3.8.md` 9) | yes on 2b6d23ef | every app on 0.3.9 (section 5 step 3); a 0.3.5 node refuses an override file with `fees_v1_activation_daa` (`OverrideParams` is `deny_unknown_fields`) and dies at start |
|
||||
| Node 1 and the observer (hand nodes on this Mac) | `vendor/igneum-node/target-release/release/igneumd` = fork 20139145 (their logs: `igneumd/2.1.0-20139145`, no `Fees on` line) | NO | move to `vendor/igneum-node/target-036/release/igneumd` (2b6d23ef, sha256 64138a17..., `release-0.3.6.md` 8e) with the restart script of section 5 |
|
||||
| The seed (188.245.5.161, unit igneumd-v4) | `/opt/igneum/v4/bin/igneumd` sha c98a23da (the 0.3.5 build, journal: `igneumd/2.1.0-20139145`) | NO | move to the Linux cross-build of 2b6d23ef, `igneum-wt-ship036/infra/cross/out/igneumd` (sha256 c24fd2c5e8c4f976e2b3abc55873bca29ae6b97b47046c946f779d3a04947025, 48,733,480 bytes, `release-0.3.6.md` 8e) with the restart script of section 5 |
|
||||
| Provers (the Mac app's host, PC 2's `/opt/igneum` host) | shard program id `0x0dfade07...` (0.3.8 pin) | | the new pin (section 2) on both, by the 0.3.8 order: provers off, pool empty, install, `--mode id` equal, provers on |
|
||||
|
||||
The two restart scripts now live in the repository, `infra/devnet/restart-hand-nodes.sh` and `infra/devnet/restart-seed.sh`,
|
||||
and take the override object as their one argument (the scratchpad forms of 5 October took only the proving height
|
||||
and hard-coded the rest; both pointed at the 20139145 binaries). Each refuses a binary that is not 2b6d23ef and ends
|
||||
by printing the new pids with their start times and the fee and digest lines.
|
||||
|
||||
## 5. The rollout, in order
|
||||
|
||||
Everything before step 6 can run as soon as 0.3.9 is published; step 6 is the point of no return; H is at least
|
||||
24 h after step 6.
|
||||
|
||||
| Step | What | Check |
|
||||
|---|---|---|
|
||||
| 1 | Ship 0.3.9 with the new prover tools in the DMG (`igneum-prove-host` built from this branch's `elf/`) and `igneum-prove-wsl2.zip` from this branch (`SKIP_GATE=1 proving/windows-wsl2/make-package.sh`), node 2b6d23ef unchanged. The manifest's `consensus.override` is CARRIED OVER unchanged at this step (no `fees_v1_activation_daa` yet): `--activation-height 84100 --deadline-note "proving v0"` as 0.3.8 did | the live manifest's consensus object identical to 0.3.8's; `--mode id` on the DMG's host prints the section 2 shard id |
|
||||
| 2 | Provers off: Mac (the app's prove setting) and PC 2 (job `prove-off-pc2-039`: `POST <app.url>/api/prove {"on":false}`) | `igneum_getProvingStatus` on the Mac app node: pool `pending 0`, no new records for 10 min (the 0.3.8 watch treated a connection error as "not empty" and said nothing: this watch prints every error line) |
|
||||
| 3 | Every app to 0.3.9: `update-now` job to all; wait for every app to log `update to 0.3.9 complete` and its node to report a DAA score (`node tools/console.mjs machines`) | Machines card: all on 0.3.9, node 2b6d23ef; PC 37ba0461 and Sam's Mac may lag, see section 7 |
|
||||
| 4 | PC 2's WSL tools: `fetch-prove-039` then `rebuild-prover-pc2-039` as 0.3.8 7a did (rsync of the package, every source re-stamped, `cargo build --release -p igneum-prove-export -p igneum-prove-host --features igneum-prove-host/cuda`, install into `/opt/igneum`) | `/opt/igneum/igneum-prove-host --mode id` prints the section 2 shard id, equal to the Mac's installed `/Applications/Igneum Miner.app/Contents/Resources/bin/igneum-prove-host --mode id` |
|
||||
| 5 | Provers on: Mac setting on, PC 2 job `prove-on-pc2-039` | the Mac node logs `VERIFIED in` for a PC 2 record under the new id; the live page shows a paid shard |
|
||||
| 6 | Publish the switch, every node at once, in this order (`release-0.3.6.md` section 7, "Operational lessons"): (a) `packaging/ota/publish-manifest.sh --version 0.3.9 --override '{"difficulty_v2_activation_daa":33000,"proving_v0_activation_daa":84100,"fees_v1_activation_daa":210000}' --activation-height 210000 --deadline-note "fees v1" --notes "<the 0.3.9 note>" --deploy` (the Mac and Windows entries are carried over from the folder's 0.3.9 manifest; the override object is the whole set of switches, not only the new one); (b) `update-now` job to every app: the apps re-read the manifest and restart their node at a safe moment with the new override; wait until every app node logs `Calibrated v1 fees from the override file: ... from DAA score 210000`; (c) `infra/devnet/restart-hand-nodes.sh '<the same object>'`; (d) `infra/devnet/restart-seed.sh '<the same object>'` | every node prints digest `ab8847da538dead1dc10e046dfaadab3c1c35928e3748810c4e050d4a886087a`; the peer lists stay full (a node with the old digest is refused by the new ones and shows as a dropped peer) |
|
||||
| 7 | Before H: the digest sweep. On every app node's log and the two hand nodes' `.out` files and the seed's journal: one digest. The console's Machines card: every node's DAA score within a few blocks of the others (an isolated node falls behind at once, as the early-restarted hand node did on 5 October) | one digest, one height |
|
||||
| 8 | At H (about 19:50Z, 6 October): the first chain block at or above 210,000 meters with v1 and its base fees jump to the floors | `igneum_getBudgets` returns `provingGasLimit` 120000 and the two base fees 100 gwei and 10,000 gwei; `eth_getBlockByNumber` of the switch block shows `provingBaseFeePerGas` 0x9184e72a000; the first shard proven after H verifies and pays (its plan is 30,000-pgas shards) |
|
||||
|
||||
Why the order: a 0.3.5 node refuses the override file (dies), a node restarted early with the switch is refused by
|
||||
every peer (isolated), and a prover on the old pin is rejected by a verifier on the new one (and the reverse). So:
|
||||
tools first with provers off, then every node in one sweep, then H a day later.
|
||||
|
||||
## 6. Commands for the release engineer
|
||||
|
||||
```
|
||||
# 0.3.9 ship (release engineer): this branch merged, then as 0.3.8 did, override carried over unchanged
|
||||
node tools/ship-app.mjs 0.3.9 --node vendor/igneum-node-036 --branch release-0.3.9 --dl-both \
|
||||
--activation-height 84100 --deadline-note "proving v0" --notes "The prover mirrors the fee switch (new pinned guest); node 2b6d23ef unchanged" --from ci
|
||||
|
||||
# step 6a, the switch (ONLY after steps 2 to 5 are checked)
|
||||
packaging/ota/publish-manifest.sh --version 0.3.9 \
|
||||
--override '{"difficulty_v2_activation_daa":33000,"proving_v0_activation_daa":84100,"fees_v1_activation_daa":210000}' \
|
||||
--activation-height 210000 --deadline-note "fees v1" --notes "Calibrated v1 fees from DAA score 210000" --deploy
|
||||
# step 6b: the update-now job to every app, then wait for the "Calibrated v1 fees" line on every app node
|
||||
# step 6c and 6d
|
||||
infra/devnet/restart-hand-nodes.sh '{"difficulty_v2_activation_daa":33000,"proving_v0_activation_daa":84100,"fees_v1_activation_daa":210000}'
|
||||
infra/devnet/restart-seed.sh '{"difficulty_v2_activation_daa":33000,"proving_v0_activation_daa":84100,"fees_v1_activation_daa":210000}'
|
||||
|
||||
# re-reading the digest for another H (20 s)
|
||||
printf '{"difficulty_v2_activation_daa":33000,"proving_v0_activation_daa":84100,"fees_v1_activation_daa":H}\n' > /tmp/ov-H.json
|
||||
vendor/igneum-node/target-036/release/igneumd --devnet --override-params-file=/tmp/ov-H.json --appdir=/tmp/digest-H \
|
||||
--rpclisten=127.0.0.1:60985 --listen=127.0.0.1:60986 --nodnsseed --nologfiles --yes # 20 s, then Ctrl-C; read "Consensus params digest"
|
||||
```
|
||||
|
||||
## 7. Open
|
||||
|
||||
| Item | State |
|
||||
|---|---|
|
||||
| PC 37ba0461 and Sam's Mac | silent at the 0.3.8 cut; they take 0.3.9 on their next check. A node that has not restarted with the switch by H is refused by every peer from its next restart; it is not a fork, it is an isolated node until its override file is updated (the app writes the manifest's object on its next update cycle) |
|
||||
| The statement does not name the schedule | section 1; the native veto pins it. Follow-up: a statement v2 with the switch and the DAA score, behind its own digest-bearing switch, when a light verifier needs it |
|
||||
| The export RPC carries no `daaScore` and no switch | `igneum_exportSegments` writes neither; gen.mjs adds them from `eth_getBlockByNumber` and the environment. Follow-up on the fork: write `daaScore` per segment and `feesV1ActivationDaa` at the top level, so a dump is self-describing |
|
||||
| The prototype-side fixtures at `S_p` 7.5 M | unchanged and still valid: a fixture without `fees` is the devnet schedule (prototype, never) |
|
||||
|
|
@ -142,7 +142,9 @@ genesis. The devnet and the simnet keep the prototype values (both base fees 1 g
|
|||
`B_e` = 30,000,000, intrinsic 200, modexp 1,000 + 10 per byte; `FeeParams::PROTOTYPE`) until the
|
||||
`fees_v1_activation_daa` height switch, carried by the override file and the consensus digest, moves them: chain
|
||||
blocks at or above that DAA score meter with the adopted table, budgets and floors, and the first such block raises
|
||||
both base fees to the floors.
|
||||
both base fees to the floors. Devnet switch: DAA score 210,000 (chosen 5 October 2026, about 19:50 UTC on
|
||||
6 October at the measured 0.965 blocks/s; the rollout is `docs/plans/fee-switch-devnet.md`). The prover's guest
|
||||
carries both tables and the switch (5 October 2026), so one program serves on either side of it.
|
||||
|
||||
| Parameter | Adopted | Basis |
|
||||
|---|---|---|
|
||||
|
|
|
|||
|
|
@ -7,7 +7,8 @@ branch `testnet-params` (worktree `vendor/igneum-node-testnet`, forked from `fin
|
|||
merged on 5 October 2026 into the fork's `release-0.3.6` (worktree `vendor/igneum-node-036`), with one change the
|
||||
sign-off added: the devnet and the simnet keep the prototype fee set until a height switch
|
||||
(`fees_v1_activation_daa`) or a `fees` object in the override file moves them; the testnet and the mainnet carry
|
||||
calibrated v1 from genesis (section 3). The three seed nodes went up on 5 October 2026 from the final genesis below (`docs/plans/testnet-go.md`); nothing mines until the owner's go.
|
||||
calibrated v1 from genesis (section 3). The devnet's switch is DAA score 210,000 (5 October 2026,
|
||||
`docs/plans/fee-switch-devnet.md`). The three seed nodes went up on 5 October 2026 from the final genesis below (`docs/plans/testnet-go.md`); nothing mines until the owner's go.
|
||||
|
||||
## 1. Identity
|
||||
|
||||
|
|
|
|||
29
infra/devnet/restart-hand-nodes.sh
Executable file
29
infra/devnet/restart-hand-nodes.sh
Executable file
|
|
@ -0,0 +1,29 @@
|
|||
#!/usr/bin/env bash
|
||||
# Restarts the two hand-run devnet nodes on this Mac (the observer, then node 1) on the 2b6d23ef node binary with
|
||||
# the override file given as ONE JSON argument, the exact object the update manifest's consensus.override carries
|
||||
# (docs/plans/fee-switch-devnet.md). Both nodes must print the same consensus digest as every app node before the
|
||||
# fee switch height, or the handshake splits the network (docs/plans/release-0.3.6.md section 7).
|
||||
# infra/devnet/restart-hand-nodes.sh '{"difficulty_v2_activation_daa":33000,"proving_v0_activation_daa":84100,"fees_v1_activation_daa":210000}'
|
||||
# Ends by printing the new pids with their start times and the fee and digest lines of each node (5 October 2026
|
||||
# lesson: a restart script that does not print the new pids has not proven the restart).
|
||||
set -euo pipefail
|
||||
OVJSON="${1:?override JSON object}"
|
||||
BIN="${IGNEUMD:-/Users/joshm/Projects/igneum/vendor/igneum-node/target-036/release/igneumd}"
|
||||
OV=/tmp/igneum-devnet/override-v3.json
|
||||
echo "$OVJSON" | python3 -c 'import json,sys; o=json.load(sys.stdin); assert isinstance(o, dict) and "fees_v1_activation_daa" in o, "the object must carry fees_v1_activation_daa"; print("override:", json.dumps(o, sort_keys=True))'
|
||||
strings "$BIN" | grep -q 2b6d23ef || { echo "$BIN is not the 2b6d23ef node (a 0.3.5 node refuses an override file with fees_v1_activation_daa)"; exit 1; }
|
||||
cp -p "$OV" "$OV.prev-$(date -u +%Y%m%dT%H%M%SZ)" 2>/dev/null || true
|
||||
printf '%s\n' "$OVJSON" > "$OV"
|
||||
stop() { local p; p=$(pgrep -f "$1" | head -1 || true); if [ -n "$p" ]; then kill -INT "$p"; while kill -0 "$p" 2>/dev/null; do sleep 1; done; fi; }
|
||||
lines() { sleep 10; grep -E "Calibrated v1 fees from the override file|Fees on igneum-devnet|Consensus params digest" "$1" | tail -3; }
|
||||
# the observer first
|
||||
stop "igneumd --devnet.*observer-v4"
|
||||
nohup "$BIN" --devnet --nodnsseed --disable-upnp --appdir=/tmp/igneum-devnet/observer-v4 --rpclisten=127.0.0.1:26640 --rpclisten-json=127.0.0.1:28640 --listen=127.0.0.1:26641 \
|
||||
--addpeer=127.0.0.1:26611 --addpeer=188.245.5.161:26611 --addpeer=192.168.68.67:26611 --override-params-file="$OV" --nologfiles --yes >> /tmp/igneum-devnet/observer-v4.out 2>&1 &
|
||||
lines /tmp/igneum-devnet/observer-v4.out
|
||||
# node 1, under caffeinate as it runs today
|
||||
stop "igneumd --devnet.*appdir=/tmp/igneum-devnet/node1 "
|
||||
nohup caffeinate -dims "$BIN" --devnet --nodnsseed --disable-upnp --enable-unsynced-mining --appdir=/tmp/igneum-devnet/node1 --rpclisten=0.0.0.0:26610 --listen=0.0.0.0:26611 \
|
||||
--addpeer=188.245.5.161:26611 --addpeer=192.168.68.67:26611 --override-params-file="$OV" --nologfiles --yes >> /tmp/igneum-devnet/node1.out 2>&1 &
|
||||
lines /tmp/igneum-devnet/node1.out
|
||||
echo "running now:"; ps -o pid=,lstart=,command= -p "$(pgrep -f 'igneumd --devnet' | tr '\n' ',' | sed 's/,$//')" | cut -c1-160
|
||||
27
infra/devnet/restart-seed.sh
Executable file
27
infra/devnet/restart-seed.sh
Executable file
|
|
@ -0,0 +1,27 @@
|
|||
#!/usr/bin/env bash
|
||||
# Moves the seed (188.245.5.161, systemd unit igneumd-v4) to the 2b6d23ef Linux node and restarts it with the
|
||||
# override file given as ONE JSON argument, the same object as restart-hand-nodes.sh and the manifest's
|
||||
# consensus.override. The binary is the Linux cross-build of fork 2b6d23ef recorded in docs/plans/release-0.3.6.md
|
||||
# 8e (sha256 c24fd2c5e8c4f976e2b3abc55873bca29ae6b97b47046c946f779d3a04947025, 48,733,480 bytes); IGNEUMD_LINUX
|
||||
# names it. Ends by printing the unit state and the fee and digest lines.
|
||||
# infra/devnet/restart-seed.sh '{"difficulty_v2_activation_daa":33000,"proving_v0_activation_daa":84100,"fees_v1_activation_daa":210000}'
|
||||
set -euo pipefail
|
||||
OVJSON="${1:?override JSON object}"
|
||||
SRC="${IGNEUMD_LINUX:-/Users/joshm/Projects/igneum-wt-ship036/infra/cross/out/igneumd}"
|
||||
WANT=c24fd2c5e8c4f976e2b3abc55873bca29ae6b97b47046c946f779d3a04947025
|
||||
echo "$OVJSON" | python3 -c 'import json,sys; o=json.load(sys.stdin); assert isinstance(o, dict) and "fees_v1_activation_daa" in o; print("override:", json.dumps(o, sort_keys=True))'
|
||||
test "$(shasum -a 256 "$SRC" | cut -c1-64)" = "$WANT" || { echo "$SRC is not the 2b6d23ef Linux node ($WANT)"; exit 1; }
|
||||
SSH="ssh -i $HOME/.ssh/igneum_ed25519 -o ConnectTimeout=20 root@188.245.5.161"
|
||||
scp -i "$HOME/.ssh/igneum_ed25519" "$SRC" root@188.245.5.161:/root/v4/out/igneumd.036
|
||||
$SSH "set -e
|
||||
test \"\$(sha256sum /root/v4/out/igneumd.036 | cut -c1-64)\" = $WANT
|
||||
cp -p /opt/igneum/v4/bin/igneumd /opt/igneum/v4/bin/igneumd.prev-035
|
||||
cp /root/v4/out/igneumd.036 /opt/igneum/v4/bin/igneumd.new && chmod +x /opt/igneum/v4/bin/igneumd.new
|
||||
cp -p /etc/igneum/override-v3.json /etc/igneum/override-v3.json.prev-\$(date -u +%Y%m%dT%H%M%SZ) || true
|
||||
printf '%s\n' '$OVJSON' > /etc/igneum/override-v3.json
|
||||
grep -q '^EXTRA_ARGS=--override-params-file=/etc/igneum/override-v3.json' /etc/igneum/seed-v4.env
|
||||
systemctl stop igneumd-v4
|
||||
mv -f /opt/igneum/v4/bin/igneumd.new /opt/igneum/v4/bin/igneumd
|
||||
systemctl start igneumd-v4
|
||||
sleep 10; systemctl is-active igneumd-v4; systemctl show -p ActiveEnterTimestamp,MainPID igneumd-v4
|
||||
journalctl -u igneumd-v4 --no-pager -n 80 -o cat | grep -E 'igneumd/2.1.0-|Calibrated v1 fees from the override file|Fees on igneum-devnet|Consensus params digest' | tail -4"
|
||||
|
|
@ -3,7 +3,8 @@
|
|||
Igneum proving: v0 (3 October 2026, one SP1 proof per block) and the devnet v4 shards (4 October 2026). Plan, status and measurements: `docs/plans/proving-v0.md`; numbers: `docs/bench-log.md`.
|
||||
|
||||
- `igneum-prove/`: Cargo workspace. `core` (the port of the execution layer's executor at b7fca5a0; the cutter `plan.rs`, the partial-trie witnesses `trie.rs` and `witness.rs`, the shard statement `shard.rs`, the block statement `agg.rs`), `program` (the shard guest), `aggregator` (the aggregator guest, SP1 deferred proofs of the shard program), `host` (modes native, execute, shard, block, all; the versioned `ProofSystem` trait with the stub and the SP1 implementation in `host/src/proof_system.rs`), `export` (cuts a real block out of an `igneum_exportSegments` dump, checks the port against the node's state roots, plans the shards and checks every witness).
|
||||
- `fixtures/`: `block-338-shard1`, `block-341-shards2`, `block-344-shards4` (one, two and four shards at `S_p` = 7.5 M pgas, from the private simnet of `tools/prove-fixtures`), `block-78-increment` and `block-56-transfers` (the v0 blocks, one shard each), `block-56-transfers-3shards` (a test cut at 200 pgas for the CPU multi-shard check).
|
||||
- `fixtures/`: `block-338-shard1`, `block-341-shards2`, `block-344-shards4` (one, two and four shards at `S_p` = 7.5 M pgas, from the private simnet of `tools/prove-fixtures`), `block-78-increment` and `block-56-transfers` (the v0 blocks, one shard each), `block-56-transfers-3shards` (a test cut at 200 pgas for the CPU multi-shard check), `fees-switch-prototype`, `fees-v1-shards2` and `fees-v1-shards3` (5 October 2026: one simnet chain across the `fees_v1_activation_daa` switch at DAA 800, a prototype block below it and v1 blocks at `S_p` = 30,000 pgas above it; `docs/plans/fee-switch-devnet.md`).
|
||||
- The fee schedule (5 October 2026): every fixture and shard input carries the node's schedule (`fees`: both tables and the switch, `core/src/config.rs`) and the block's DAA score; the executor reads the set at that score and raises the base fees to its floors as the node does. A fixture without `fees` is the devnet as compiled (prototype, never). The exporter takes the schedule from the dump (`feesV1ActivationDaa`, `fees`, per-segment `daaScore`, written by `tools/prove-fixtures/gen.mjs`) or from `--fees-v1-activation-daa` and `--fees-base`.
|
||||
- `windows-wsl2/`: SETUP-PROVER.bat, PROVE-SHARD.bat (the shard at `S_p` and the two- and four-shard blocks on the GPU), PROVE-BLOCK.bat (the small block) and the Linux scripts for Josh's PC; `make-package.sh` builds the zip.
|
||||
|
||||
## Pinned guest programs (5 October 2026)
|
||||
|
|
|
|||
562
proving/fixtures/fees-switch-prototype.json
Normal file
562
proving/fixtures/fees-switch-prototype.json
Normal file
|
|
@ -0,0 +1,562 @@
|
|||
{
|
||||
"format": "igneum-prove-fixture-v1",
|
||||
"source": "private simnet (tools/prove-fixtures/net.sh, node 2b6d23ef, override fees_v1_activation_daa 800), block 51 below the switch, 5 October 2026",
|
||||
"block": {
|
||||
"chain_id": 4463,
|
||||
"env": {
|
||||
"number": 51,
|
||||
"hash": "0x44946d4dadb4e11834532bb65357f247b6ce0108bbff5f6b6f47e0c505f573cc",
|
||||
"parent_hash": "0x7a0989018fcc63317e3bcb48aa3acd118bcf8f62671947a9d59a07505c13ad3c",
|
||||
"timestamp": 1791215591,
|
||||
"miner": "0x70997970c51812dc3a010c7d01b50e0d17dc79c8",
|
||||
"prevrandao": "0x86ba2d42419135e222524356a20f03bebd6fc9eae89453558f3c19b4fe64feba",
|
||||
"base_fee_exec": 1000000000,
|
||||
"base_fee_proving": 1000000000,
|
||||
"daa_score": 185
|
||||
},
|
||||
"block_hashes": [
|
||||
[
|
||||
0,
|
||||
"0x3c19f19d3d77bfc2f367482eb7f28aa907ca5d31470c7d7722a68f44436236d5"
|
||||
],
|
||||
[
|
||||
1,
|
||||
"0xb8ae215672d921abe8996b5de508abb27240f174758e7859959498792735325e"
|
||||
],
|
||||
[
|
||||
2,
|
||||
"0xc99a09bb56cf317da83bd378dad2844d0fa403f7b02ab7c5b07776f30b2836bf"
|
||||
],
|
||||
[
|
||||
3,
|
||||
"0xe722e0e06420232df8a72a10bef207670fad3f02b5d417425026d50e75bb6da6"
|
||||
],
|
||||
[
|
||||
4,
|
||||
"0xe8a3c8a56d5b9b667ac5e90a40ff38ca9bd1ad62710423616ef1e3cf06033518"
|
||||
],
|
||||
[
|
||||
5,
|
||||
"0x928cd98ad1d1baba9e2e9cf180e922caec1779cad26105b69e717ae39b1e4630"
|
||||
],
|
||||
[
|
||||
6,
|
||||
"0x3981df0a74f007de4f71437c6d11579b426c6ad98d9e9b4eb206f515153301a8"
|
||||
],
|
||||
[
|
||||
7,
|
||||
"0xb84bda4ab7c6a27c197d21fabc14616bc90ffd194e006d6168a80f9093c32084"
|
||||
],
|
||||
[
|
||||
8,
|
||||
"0xbd329cf2074514dc0b1d23a50c2438cf5cdd09534a56af665c691da17fde067b"
|
||||
],
|
||||
[
|
||||
9,
|
||||
"0xcaa23fbb44860da914c3d02e71d1914c9752abbd659c4926631a7ce9be59985f"
|
||||
],
|
||||
[
|
||||
10,
|
||||
"0xa778da83ead0bb12921db64e96ad4479e48c8b3078f8b4a63e2524a99f19baa1"
|
||||
],
|
||||
[
|
||||
11,
|
||||
"0x131865d5aeb909b98801b5fdc815ccb5ddc35deebe00af87d935f917704041cb"
|
||||
],
|
||||
[
|
||||
12,
|
||||
"0x950b38ef16fa7b69e67d58bd9cc6600d6ba2a886c6230fe230aa37349b1776eb"
|
||||
],
|
||||
[
|
||||
13,
|
||||
"0xe1a2ab03d94104902fed447b2a68b0211bb00a88c5d026c949008ccfa5b82c6e"
|
||||
],
|
||||
[
|
||||
14,
|
||||
"0x377fbd045da13c0ffd631812c72c69f755c85837176b598c7281f0960ec4a06e"
|
||||
],
|
||||
[
|
||||
15,
|
||||
"0xdaef4f55e7bdecdbbdd1c8350708f3acc85955ef6affea3c752af76c9f997041"
|
||||
],
|
||||
[
|
||||
16,
|
||||
"0xf2f291bbdb463a73fc3f8724d5e12e70b1e970a18746187d1bd60981d3e22e1d"
|
||||
],
|
||||
[
|
||||
17,
|
||||
"0xa9f645779dec5ffc921b4b34bd0fc3d7269ceafc7e8c073e58c93faedbe15496"
|
||||
],
|
||||
[
|
||||
18,
|
||||
"0xb338505304c4fa7d5ba90eae9e23e54cf87fbfdf2bcf12cb6379563237019b0f"
|
||||
],
|
||||
[
|
||||
19,
|
||||
"0xac7bf355e9b5462e2a557f56b4c8e93b448ce64789809fa98100794fa067a03e"
|
||||
],
|
||||
[
|
||||
20,
|
||||
"0xcae1b0272da35e2fda587edaf7d13f4e97ad44a13f1d654f33d9fcfcb81e5621"
|
||||
],
|
||||
[
|
||||
21,
|
||||
"0x749985bc035b115f26f14af86a9a9937234f0272c1585b1b9bb6e36c6d3ef683"
|
||||
],
|
||||
[
|
||||
22,
|
||||
"0x85446baba49d0a5c0c9fd39c1428eca3229ac15fc6df58d28ebbf1d5241c4645"
|
||||
],
|
||||
[
|
||||
23,
|
||||
"0x87231ebafb4002d897d8604c9be770b2f7b64cdf709ef054418f2cad6824e286"
|
||||
],
|
||||
[
|
||||
24,
|
||||
"0x7017cfefcefad8312081aedc79a5543f194267be2ad21c26cb584a6e76bc9a66"
|
||||
],
|
||||
[
|
||||
25,
|
||||
"0xc61268ad71975388c2fde1232e8ee8581ecdd5441032f7c33d1f6e9c57ebea87"
|
||||
],
|
||||
[
|
||||
26,
|
||||
"0xde8b2d01b5b01603fb9c64aa60f600eda81ae89f07aba1f21a3a1ad45f27872c"
|
||||
],
|
||||
[
|
||||
27,
|
||||
"0xad34fe496df35f536d1c6ec2dd1663209a0c74786d0a60a5196631a50683df8e"
|
||||
],
|
||||
[
|
||||
28,
|
||||
"0x758393ccef39ab177705781b7e423373f174c9e35fd37c333a38a97808b851fc"
|
||||
],
|
||||
[
|
||||
29,
|
||||
"0xaf6bc97e6307488e0603af075d16eb2889f77cd71fb9d4687815603091d02343"
|
||||
],
|
||||
[
|
||||
30,
|
||||
"0xc5198af5543566c88dc15d6bbaf330610d03b8eb71c3d935a6461ecbeb3de054"
|
||||
],
|
||||
[
|
||||
31,
|
||||
"0x58227e0b5c2d307089ee332e49714909e204e826073942b449b87fcdbbb79c8d"
|
||||
],
|
||||
[
|
||||
32,
|
||||
"0xea6b2e847759bf01512d8eba3f3a070c3522bc33703a8a8e768537dba3bc3e9c"
|
||||
],
|
||||
[
|
||||
33,
|
||||
"0x420f95702ba4b696cde23bea52d17ce3aeabe3f5dd50e65532045764432b61df"
|
||||
],
|
||||
[
|
||||
34,
|
||||
"0x595180b55f6daeb09ae37dd4ee3d009d810286802e0053c69b34c9d307ea782e"
|
||||
],
|
||||
[
|
||||
35,
|
||||
"0xcd2a19b5341491b37a0da9db99536a0ef867e2e52adaa1e051c569d34b06e9fc"
|
||||
],
|
||||
[
|
||||
36,
|
||||
"0xeb1d2a0c38f74c82d661485f9bb921c5f0789a5bd6a75feb408369f2054cfaea"
|
||||
],
|
||||
[
|
||||
37,
|
||||
"0x18d87f7481f7de65ca41cae3bb28905e56518a252600920c21db2e52cff82277"
|
||||
],
|
||||
[
|
||||
38,
|
||||
"0x0b14fb90af6f7dfc4089e51f384fc6d695367ac5bf54ce0b30b7aae79a64cabd"
|
||||
],
|
||||
[
|
||||
39,
|
||||
"0xf3b908ce0daeb467d6fe96d4c4d09a9b2e052ca8e8d41ba4e35a12b143366e92"
|
||||
],
|
||||
[
|
||||
40,
|
||||
"0xda73f70451fc52cf9c7286abed367e5e47323fa9e832d361f1d35df163f0ed10"
|
||||
],
|
||||
[
|
||||
41,
|
||||
"0xfdcb4e03f8006c7f77906c039066cf4285e5cd15624ec18023a6afb921acf67e"
|
||||
],
|
||||
[
|
||||
42,
|
||||
"0xfdec6141e5a241fa2a3484d3ee870630e01daae0d0c2daba3c780a82941fbc4d"
|
||||
],
|
||||
[
|
||||
43,
|
||||
"0x2d5c16783560b867847311ca5353c4b4f458fbfe759fe3260c85d1b71505cec7"
|
||||
],
|
||||
[
|
||||
44,
|
||||
"0xf08c6adf31900cb8a1180c2896d3d3f8ed0f7d4cc277065e4bfe42a1a04ca0bb"
|
||||
],
|
||||
[
|
||||
45,
|
||||
"0x251fc254642addfbe034cb206f274f1092ff9998e40cff955f6c137edd9e8f65"
|
||||
],
|
||||
[
|
||||
46,
|
||||
"0xae16a6c93f0892c361506514614696b7709816194dea7c7f0b65bdbe372ea3ce"
|
||||
],
|
||||
[
|
||||
47,
|
||||
"0x2af1cb49995375589e854b4d6734cece36ce80f8b10eb384e646dde60aaa08e9"
|
||||
],
|
||||
[
|
||||
48,
|
||||
"0xd7aced4490fef2c7b3937ce9016233cdec0d37e8c558b292b1314770de5c2cff"
|
||||
],
|
||||
[
|
||||
49,
|
||||
"0x9332f244b2ab46504a6f5e10f071c2c389398f511904aebcd01bb304a39387ca"
|
||||
],
|
||||
[
|
||||
50,
|
||||
"0x7a0989018fcc63317e3bcb48aa3acd118bcf8f62671947a9d59a07505c13ad3c"
|
||||
]
|
||||
],
|
||||
"rewards": [
|
||||
[
|
||||
"0x70997970c51812dc3a010c7d01b50e0d17dc79c8",
|
||||
"0x233424e14167e000"
|
||||
],
|
||||
[
|
||||
"0x70997970c51812dc3a010c7d01b50e0d17dc79c8",
|
||||
"0x233424e14167e000"
|
||||
],
|
||||
[
|
||||
"0x70997970c51812dc3a010c7d01b50e0d17dc79c8",
|
||||
"0x233424e14167e000"
|
||||
],
|
||||
[
|
||||
"0x70997970c51812dc3a010c7d01b50e0d17dc79c8",
|
||||
"0x233424e14167e000"
|
||||
],
|
||||
[
|
||||
"0xdfaea67368f3e3753397d878f97efe6aa8020c2e",
|
||||
"0x233424e14167e000"
|
||||
],
|
||||
[
|
||||
"0x70997970c51812dc3a010c7d01b50e0d17dc79c8",
|
||||
"0x233424e14167e000"
|
||||
]
|
||||
],
|
||||
"proving_pool_credit": "0x34ce3751e21bd000",
|
||||
"payouts": [],
|
||||
"blocks": [
|
||||
{
|
||||
"miner": "0x70997970c51812dc3a010c7d01b50e0d17dc79c8",
|
||||
"blue": true,
|
||||
"txs": [
|
||||
"0x02f89282116f80847735940085051f4d5c00830cf48194aaab651f3784e163f3c03517a3bc9e675636c67980a4dc9f0cb300000000000000000000000000000000000000000000000000000000000002d3c080a0adef344984f430471167805c15f5e7a2cad7f87774874f950a6ae1eadc2ce261a060c71f9da470d1a07d51b07b4da97e9ef88e649782855eaab84b241ca807b3e2",
|
||||
"0x02f87482116f01841dcd65008504c5e52d008252089439553e621b00d6d19aa0ee4155ef063ccc163590872386f26fc1000080c001a0acfac944ac60874817276c1a552d021be50db2dcae519a814834e9470bb2c678a06b242fcb76eb682e4d2068f206552d7c54198269aea951eddbe3b02055ff45f0",
|
||||
"0x02f89282116f8084769cfd8085051eb4c580830cf48194aaab651f3784e163f3c03517a3bc9e675636c67980a4dc9f0cb300000000000000000000000000000000000000000000000000000000000002d3c080a025710c7dd2197ce307ce80d9601c88df5eb259a2b1366342845927ee5e30998fa00c3fb93ffefd8f9016b546833215c9f6979c4a60c9ed5e24271c4ec584a8c269",
|
||||
"0x02f87482116f01841dcd65008504c5e52d0082520894d9b1d748851689d015a69972be1e5e6f59e24feb872386f26fc1000080c001a06b7dca436f5a64ef49e1715910838a08aeaa0d8ae5b33766593802215da1b5c7a035b0ef6dc3ec0d12176a89cfa3976fc0af7485ccc70a50f100b7429c27f68460",
|
||||
"0x02f89282116f80847604670085051e1c2f00830cf48194aaab651f3784e163f3c03517a3bc9e675636c67980a4dc9f0cb300000000000000000000000000000000000000000000000000000000000002d3c001a0a2117d759e64e95ebc96de091d9aef6198a681ad2c3e38be4aaaadff3948ac4ba07df414628e62c80818591b26ff802ebb2b05770bcb14f8cc5654c06847be3d7d",
|
||||
"0x02f87482116f01841dcd65008504c5e52d00825208946bf0aac4270a54000f3482d65c080fdb776cbc5c872386f26fc1000080c001a0edf60a326ab3d4af45c6d43ed15c0101c1bb84fa239db8f50489a4821ff033a5a02ce39e97b716f1c475dccc4084b24287d8be88cad766268e3b26946cc0dc9360",
|
||||
"0x02f87482116f02841dcd65008504c5e52d00825208945fa00e9411cd9f48f6b9c5318ae6b8fc4acd04e4872386f26fc1000080c080a0b08b8d232e41e03415ca7123933541f01fbeaf25673829f8d7811b28b3589d90a018cf801823495d3c124ccbd684cbfb4add17faf3b286971486148bfab8943b60",
|
||||
"0x02f87482116f01841dcd65008504c5e52d008252089419f3122510673424bd26823b4b366a0e4818a93d872386f26fc1000080c001a092c76d77690b157d17ad7af2a16e29f7dd4471cc1eba762c3d961d67759369aaa003e2cd4cfabf3a0b241bd4f82ec6b283a04ad066023f3e1a917c5b55963bebeb",
|
||||
"0x02f87482116f01841dcd65008504c5e52d0082520894ea747b5286a148a3ca5aa186b84506eeba3eba18872386f26fc1000080c080a0bcd71520ac19b89cf2b6717f675f87cb03f2fff1bdaacf3e10736c7b0adba290a073d36aa3cb7400e0f50b8f2502f51ac7b0906d5523af45a5b2eb5ed75fce9f19",
|
||||
"0x02f89282116f808417d784008504bfef4c008301d4c094356d4140ff5501dd8447be370a267acc56dde96180a47cf5dab00000000000000000000000000000000000000000000000000000000000000002c080a0db4623be9c05c0b3eb3ab56d69e6ca3e7835625bf5c3f92596a4d3113b43ef5aa04f548068c98c65c00bacc77de36e57265043b2a48228da88d3cd5252016a9c1a",
|
||||
"0x02f89282116f808417d784008504bfef4c008301d4c094356d4140ff5501dd8447be370a267acc56dde96180a47cf5dab00000000000000000000000000000000000000000000000000000000000000001c080a07775a425aeaa2b4165eeefcb569cc5f4f8f45c2c0061945b6576532a5d8ff748a05c64ccc5190a670cb03bd705b711ed088550e957f70e024be2c8f2fd589d843a"
|
||||
]
|
||||
}
|
||||
],
|
||||
"pre_state": [
|
||||
{
|
||||
"address": "0x0000000000000000000000000000000000000210",
|
||||
"nonce": 1,
|
||||
"balance": "0x0",
|
||||
"code": "0x608060405234801561000f575f5ffd5b506004361061003f575f3560e01c8063aa67735414610043578063dea5c2e014610058578063fe7e05d51461009f575b5f5ffd5b6100566100513660046101e0565b6100ca565b005b610083610066366004610211565b6001600160a01b039081165f908152600160205260409020541690565b6040516001600160a01b03909116815260200160405180910390f35b6100836100ad366004610211565b6001600160a01b039081165f908152602081905260409020541690565b336001600160a01b03831614806100f957506001600160a01b038281165f908152600160205260409020541633145b6101635760405162461bcd60e51b815260206004820152603160248201527f446576656c6f70657252656769737472793a206e6f7420746865206163636f75604482015270373a1037b91034ba399031b932b0ba37b960791b606482015260840160405180910390fd5b6001600160a01b038281165f818152602081815260409182902080546001600160a01b031916948616948517905590513381527fa47563c41dab010f91a8ef9dc7ac2bcdfa0ef2af697e575048e71e6eec60dda3910160405180910390a35050565b80356001600160a01b03811681146101db575f5ffd5b919050565b5f5f604083850312156101f1575f5ffd5b6101fa836101c5565b9150610208602084016101c5565b90509250929050565b5f60208284031215610221575f5ffd5b61022a826101c5565b939250505056fea2646970667358221220cbf48f5aa6f911f83b3c2b09adf8c418f5da6fc530c3d5db9d4ba0be24c4bf5864736f6c63430008250033",
|
||||
"storage": [
|
||||
[
|
||||
"0x41be36c37bd1f497e0227730320270e53a95b0a932455c1203d3363afcd8b14e",
|
||||
"0x2546bcd3c84621e976d8185a91a922ae77ecec30"
|
||||
],
|
||||
[
|
||||
"0x987c2fc8409fbb4378b0522a7cd2d8760d6e6d5505c10f80def58f7eb25d0c5c",
|
||||
"0x1e38522ef05112d99efebacae1f64bde6e719c3e"
|
||||
],
|
||||
[
|
||||
"0xeaaceac0b589339a73598cb23929522fc7772e460c174697b9d8c88c416d4dc2",
|
||||
"0xef8e8f195c2ed9cad14fb8ff3e28452e4a09da70"
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"address": "0x0000000000000000000000000000000000000220",
|
||||
"nonce": 0,
|
||||
"balance": "0x6413dbb443991c400",
|
||||
"code": "0x",
|
||||
"storage": []
|
||||
},
|
||||
{
|
||||
"address": "0x0d6f1cf49d099befe57342f08d69f34488aed59c",
|
||||
"nonce": 0,
|
||||
"balance": "0xa688906bd8b00000",
|
||||
"code": "0x",
|
||||
"storage": []
|
||||
},
|
||||
{
|
||||
"address": "0x19f3122510673424bd26823b4b366a0e4818a93d",
|
||||
"nonce": 0,
|
||||
"balance": "0xa688906bd8b00000",
|
||||
"code": "0x",
|
||||
"storage": []
|
||||
},
|
||||
{
|
||||
"address": "0x1a6de6aa3545c6b133c2151bd5d9a8f5205d351e",
|
||||
"nonce": 0,
|
||||
"balance": "0xa688906bd8b00000",
|
||||
"code": "0x",
|
||||
"storage": []
|
||||
},
|
||||
{
|
||||
"address": "0x1e38522ef05112d99efebacae1f64bde6e719c3e",
|
||||
"nonce": 1,
|
||||
"balance": "0xa686c224eb721a00",
|
||||
"code": "0x",
|
||||
"storage": []
|
||||
},
|
||||
{
|
||||
"address": "0x23b73ba458cba8f4b6e5ee78ddf3c1c9e326b1d3",
|
||||
"nonce": 0,
|
||||
"balance": "0xa688906bd8b00000",
|
||||
"code": "0x",
|
||||
"storage": []
|
||||
},
|
||||
{
|
||||
"address": "0x2546bcd3c84621e976d8185a91a922ae77ecec30",
|
||||
"nonce": 0,
|
||||
"balance": "0x20d881fa49e5",
|
||||
"code": "0x",
|
||||
"storage": []
|
||||
},
|
||||
{
|
||||
"address": "0x274c3596f8275293f8c88819e1b2aa95e859f07b",
|
||||
"nonce": 0,
|
||||
"balance": "0xa688906bd8b00000",
|
||||
"code": "0x",
|
||||
"storage": []
|
||||
},
|
||||
{
|
||||
"address": "0x288f82697c3dadf540711e3c8e692de23c7b83c4",
|
||||
"nonce": 0,
|
||||
"balance": "0xa688906bd8b00000",
|
||||
"code": "0x",
|
||||
"storage": []
|
||||
},
|
||||
{
|
||||
"address": "0x2f4f9b3a1dea4a5ada8e135cb1576e7cb4994ca7",
|
||||
"nonce": 0,
|
||||
"balance": "0xa688906bd8b00000",
|
||||
"code": "0x",
|
||||
"storage": []
|
||||
},
|
||||
{
|
||||
"address": "0x2ffc0500827211e5e4a95191cb0a79f3a427a218",
|
||||
"nonce": 0,
|
||||
"balance": "0xa688906bd8b00000",
|
||||
"code": "0x",
|
||||
"storage": []
|
||||
},
|
||||
{
|
||||
"address": "0x356d4140ff5501dd8447be370a267acc56dde961",
|
||||
"nonce": 1,
|
||||
"balance": "0x0",
|
||||
"code": "0x608060405234801561000f575f5ffd5b506004361061003f575f3560e01c806306661abd14610043578063671513191461005d5780637cf5dab014610070575b5f5ffd5b61004b5f5481565b60405190815260200160405180910390f35b61004b61006b366004610161565b610083565b61004b61007e366004610161565b6100ca565b5f805b828110156100c457604080516020810184905290810182905260600160408051601f1981840301815291905280516020909101209150600101610086565b50919050565b5f5f821161010e5760405162461bcd60e51b815260206004820152600d60248201526c436f756e7465723a207a65726f60981b604482015260640160405180910390fd5b815f5f82825461011e9190610178565b90915550505f5460405190815233907f38ac789ed44572701765277c4d0970f2db1c1a571ed39e84358095ae4eaa54209060200160405180910390a250505f5490565b5f60208284031215610171575f5ffd5b5035919050565b8082018082111561019757634e487b7160e01b5f52601160045260245ffd5b9291505056fea2646970667358221220550fbe02c34bbf880b632f2e9e937266b869dc777da392b2cfceaf158da2014364736f6c63430008250033",
|
||||
"storage": []
|
||||
},
|
||||
{
|
||||
"address": "0x39553e621b00d6d19aa0ee4155ef063ccc163590",
|
||||
"nonce": 0,
|
||||
"balance": "0xa688906bd8b00000",
|
||||
"code": "0x",
|
||||
"storage": []
|
||||
},
|
||||
{
|
||||
"address": "0x3a5accad2dfdfd9b1b179aed5875ed46830659c6",
|
||||
"nonce": 0,
|
||||
"balance": "0xa688906bd8b00000",
|
||||
"code": "0x",
|
||||
"storage": []
|
||||
},
|
||||
{
|
||||
"address": "0x48e153068b4008323024b09285c521027bed1638",
|
||||
"nonce": 2,
|
||||
"balance": "0xa67fc3ac80bdbc00",
|
||||
"code": "0x",
|
||||
"storage": []
|
||||
},
|
||||
{
|
||||
"address": "0x5fa00e9411cd9f48f6b9c5318ae6b8fc4acd04e4",
|
||||
"nonce": 0,
|
||||
"balance": "0xa688906bd8b00000",
|
||||
"code": "0x",
|
||||
"storage": []
|
||||
},
|
||||
{
|
||||
"address": "0x6bf0aac4270a54000f3482d65c080fdb776cbc5c",
|
||||
"nonce": 0,
|
||||
"balance": "0xa688906bd8b00000",
|
||||
"code": "0x",
|
||||
"storage": []
|
||||
},
|
||||
{
|
||||
"address": "0x6f0b69a357fb4d5e3d10342e939f41221517f206",
|
||||
"nonce": 0,
|
||||
"balance": "0xa688906bd8b00000",
|
||||
"code": "0x",
|
||||
"storage": []
|
||||
},
|
||||
{
|
||||
"address": "0x70997970c51812dc3a010c7d01b50e0d17dc79c8",
|
||||
"nonce": 24,
|
||||
"balance": "0x944f63b525ed10800",
|
||||
"code": "0x",
|
||||
"storage": []
|
||||
},
|
||||
{
|
||||
"address": "0x7cae7e5337aed23fdc1e6423fda5aaa27f41421d",
|
||||
"nonce": 0,
|
||||
"balance": "0xa688906bd8b00000",
|
||||
"code": "0x",
|
||||
"storage": []
|
||||
},
|
||||
{
|
||||
"address": "0xaaab651f3784e163f3c03517a3bc9e675636c679",
|
||||
"nonce": 1,
|
||||
"balance": "0x0",
|
||||
"code": "0x608060405234801561000f575f5ffd5b5060043610610034575f3560e01c806322afaa4e14610038578063dc9f0cb31461005d575b5f5ffd5b61004b61004636600461031a565b610070565b60405190815260200160405180910390f35b61004b61006b36600461031a565b6100d0565b604080514360208083019190915282518083038201815291830190925280519101205f5b828110156100ca5760408051602081018490520160408051601f1981840301815291905280516020909101209150600101610094565b50919050565b6040805160e280825261012082019092525f91829190602082018180368337019050509050600160f81b81601f8151811061010d5761010d610331565b60200101906001600160f81b03191690815f1a905350600160f81b81603f8151811061013b5761013b610331565b60200101906001600160f81b03191690815f1a905350608060f81b81605f8151811061016957610169610331565b60200101906001600160f81b03191690815f1a905350600260f81b8160608151811061019757610197610331565b60200101906001600160f81b03191690815f1a905350600160f81b816061815181106101c5576101c5610331565b60200101906001600160f81b03191690815f1a9053505f5b6080811015610229576001600160f81b0319826101fb836062610345565b8151811061020b5761020b610331565b60200101906001600160f81b03191690815f1a9053506001016101dd565b5060408051608080825260a082019092525f916020820181803683370190505090505f5b848110156102d9575f60806020840185516020870160055afa9050806102a95760405162461bcd60e51b815260206004820152600d60248201526c1b5bd9195e1c0819985a5b1959609a1b604482015260640160405180910390fd5b82607f815181106102bc576102bc610331565b01602001516102ce9060f81c86610345565b94505060010161024d565b5060408051858152602081018590527f2006d76973ad24d89bba111e205a6594eb6ed9ed5bf0b64862bf758fed1445b9910160405180910390a15050919050565b5f6020828403121561032a575f5ffd5b5035919050565b634e487b7160e01b5f52603260045260245ffd5b8082018082111561036457634e487b7160e01b5f52601160045260245ffd5b9291505056fea2646970667358221220a99d434cf434c37014c8aa77d4d149d70b8d9fa45edd81e95ff4fd768fcec9cf64736f6c63430008250033",
|
||||
"storage": []
|
||||
},
|
||||
{
|
||||
"address": "0xabc42e209db7c7832728bffcb69072d8ce460c2e",
|
||||
"nonce": 0,
|
||||
"balance": "0xa688906bd8b00000",
|
||||
"code": "0x",
|
||||
"storage": []
|
||||
},
|
||||
{
|
||||
"address": "0xc9918c41fb0d85b9d3ffc851d5ffd6dd03de77ef",
|
||||
"nonce": 0,
|
||||
"balance": "0xa688906bd8b00000",
|
||||
"code": "0x",
|
||||
"storage": []
|
||||
},
|
||||
{
|
||||
"address": "0xd7edc12ca8cb2c80f567d82916b749ec160fe918",
|
||||
"nonce": 0,
|
||||
"balance": "0xa688906bd8b00000",
|
||||
"code": "0x",
|
||||
"storage": []
|
||||
},
|
||||
{
|
||||
"address": "0xd9b1d748851689d015a69972be1e5e6f59e24feb",
|
||||
"nonce": 0,
|
||||
"balance": "0xa688906bd8b00000",
|
||||
"code": "0x",
|
||||
"storage": []
|
||||
},
|
||||
{
|
||||
"address": "0xdfaea67368f3e3753397d878f97efe6aa8020c2e",
|
||||
"nonce": 0,
|
||||
"balance": "0x23334cbd0d932c00",
|
||||
"code": "0x",
|
||||
"storage": []
|
||||
},
|
||||
{
|
||||
"address": "0xe12a4a9bdc4674e77c52ecde6bbaffcb20c8db6f",
|
||||
"nonce": 0,
|
||||
"balance": "0xa688906bd8b00000",
|
||||
"code": "0x",
|
||||
"storage": []
|
||||
},
|
||||
{
|
||||
"address": "0xea747b5286a148a3ca5aa186b84506eeba3eba18",
|
||||
"nonce": 0,
|
||||
"balance": "0xa688906bd8b00000",
|
||||
"code": "0x",
|
||||
"storage": []
|
||||
},
|
||||
{
|
||||
"address": "0xef8e8f195c2ed9cad14fb8ff3e28452e4a09da70",
|
||||
"nonce": 1,
|
||||
"balance": "0xa6873ce0403c2400",
|
||||
"code": "0x",
|
||||
"storage": []
|
||||
},
|
||||
{
|
||||
"address": "0xf5e9b682f6f64e9a6ca6cd6a04ffeee8b8e5aea4",
|
||||
"nonce": 0,
|
||||
"balance": "0xa688906bd8b00000",
|
||||
"code": "0x",
|
||||
"storage": []
|
||||
}
|
||||
],
|
||||
"fees": {
|
||||
"base": {
|
||||
"pgas": {
|
||||
"version": 0,
|
||||
"cycles_per_pgas": 1000,
|
||||
"intrinsic_pgas_per_tx": 200,
|
||||
"modexp_base": 1000,
|
||||
"modexp_per_byte_numer": 10,
|
||||
"modexp_per_byte_denom": 1
|
||||
},
|
||||
"block_proving_gas_limit": 30000000,
|
||||
"shard_proving_gas_budget": 7500000,
|
||||
"min_execution_base_fee_wei": 1000000000,
|
||||
"min_proving_base_fee_wei": 1000000000,
|
||||
"initial_execution_base_fee_wei": 1000000000,
|
||||
"initial_proving_base_fee_wei": 1000000000,
|
||||
"base_fee_change_denominator": 8
|
||||
},
|
||||
"v1_activation_daa": 800
|
||||
}
|
||||
},
|
||||
"plan": {
|
||||
"shard_budget": 7500000,
|
||||
"consensus": true,
|
||||
"shards": [
|
||||
{
|
||||
"index": 0,
|
||||
"tx_start": 0,
|
||||
"tx_end": 11,
|
||||
"over_budget": false,
|
||||
"pre_root": "0x099878ad5b57ca0e20c4f3057f4ff2390499875e7fb11e9d3843dfb0a31cdfa4",
|
||||
"post_root": "0x690600b38d297ddc9ffabc13035c58c70690fbcad2aaf4571dfe67a92e3ca8d0",
|
||||
"receipts_root": "0x1bbad80da2492a15360fa6c761d78b6d78ca62740ce7dc0279924c04ab74c569",
|
||||
"link_in": "0x38046159e1bf364d16df7645adc5a18f254dd70ffab279ed30785b727b52a3d5",
|
||||
"link_out": "0x067e4f8593981a8518a60f20c0bf4348cfe84ed2a30d1e4707d8dfdd4de4e140",
|
||||
"gas_used": 1505469,
|
||||
"pgas_used": 7494392,
|
||||
"executed": 11,
|
||||
"skipped": 0,
|
||||
"witness": [
|
||||
20,
|
||||
3,
|
||||
24,
|
||||
7,
|
||||
11928
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"expected": {
|
||||
"pre_state_root": "0x099878ad5b57ca0e20c4f3057f4ff2390499875e7fb11e9d3843dfb0a31cdfa4",
|
||||
"post_state_root": "0x690600b38d297ddc9ffabc13035c58c70690fbcad2aaf4571dfe67a92e3ca8d0",
|
||||
"receipts_root": "0x1bbad80da2492a15360fa6c761d78b6d78ca62740ce7dc0279924c04ab74c569",
|
||||
"tx_commitment": "0x382d00f9535f1962f4e06b33c206cd68139e26670d19f7ac7ed79f1c279ea193",
|
||||
"gas_used": 1505469,
|
||||
"pgas_used": 7494392,
|
||||
"executed": 11,
|
||||
"skipped": 0,
|
||||
"node_state_root": "0x690600b38d297ddc9ffabc13035c58c70690fbcad2aaf4571dfe67a92e3ca8d0"
|
||||
}
|
||||
}
|
||||
1476
proving/fixtures/fees-v1-shards2.json
Normal file
1476
proving/fixtures/fees-v1-shards2.json
Normal file
File diff suppressed because it is too large
Load diff
1506
proving/fixtures/fees-v1-shards3.json
Normal file
1506
proving/fixtures/fees-v1-shards3.json
Normal file
File diff suppressed because it is too large
Load diff
1
proving/igneum-prove/Cargo.lock
generated
1
proving/igneum-prove/Cargo.lock
generated
|
|
@ -2784,6 +2784,7 @@ dependencies = [
|
|||
"igneum-evm-types",
|
||||
"revm",
|
||||
"serde",
|
||||
"serde_json",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
|
|||
|
|
@ -14,3 +14,6 @@ alloy-eips.workspace = true
|
|||
alloy-rlp.workspace = true
|
||||
alloy-trie.workspace = true
|
||||
serde.workspace = true
|
||||
|
||||
[dev-dependencies]
|
||||
serde_json.workspace = true
|
||||
|
|
|
|||
|
|
@ -1,18 +1,221 @@
|
|||
//! Consensus constants of the execution layer, devnet v4 values (mirror of igneum-exec `config.rs` at b7fca5a0),
|
||||
//! plus the shard budget of design 5.1.
|
||||
//! Consensus constants of the execution layer (mirror of igneum-exec `config.rs`) and the fee rules of
|
||||
//! `kaspa_consensus_core::fees` at fork 2b6d23ef (5 October 2026): BOTH pgas tables, both fee sets and the
|
||||
//! `fees_v1_activation_daa` height switch. The guest reads the schedule and the block's DAA score from its input
|
||||
//! (`shard::ShardInput`) and meters exactly as the node does for that block, so one pinned guest serves before
|
||||
//! and after the switch. The node recomputes every statement natively (`igneum_exec::proving::statement_bytes`)
|
||||
//! and vetoes a record that differs, which is what pins the schedule a prover claims: a shard metered with the
|
||||
//! wrong table has another `pgas_used`, another post-root (the floors change what is burned) and so another
|
||||
//! statement. The 328-byte public-values layout is unchanged.
|
||||
|
||||
use alloy_primitives::{address, Address};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
pub const BLOCK_EXECUTION_GAS_LIMIT: u64 = 30_000_000;
|
||||
pub const BLOCK_PROVING_GAS_LIMIT: u64 = 30_000_000;
|
||||
/// `S_p`, the most proving gas one shard carries (design 5.1, spec 7.2). The specification gives no number yet
|
||||
/// (Target: about 20 s on a 12 GB card; the provisional value is "the project's own first run", benchmark
|
||||
/// standard 9). Provisional, 4 October 2026: a quarter of `B_p`, so a block at its proving budget is exactly
|
||||
/// four shards and the devnet v4 fixtures are one, two and four shards. Set from the RTX 5090 and 3060-class
|
||||
/// measurements, never from the fixtures (benchmark standard 2.3).
|
||||
pub const SHARD_PROVING_GAS_BUDGET: u64 = BLOCK_PROVING_GAS_LIMIT / 4;
|
||||
pub const DEVELOPER_REGISTRY_ADDRESS: Address = address!("0000000000000000000000000000000000000210");
|
||||
pub const PROVING_POOL_ADDRESS: Address = address!("0000000000000000000000000000000000000220");
|
||||
pub const BLOCKHASH_WINDOW: u64 = 256;
|
||||
pub const INTRINSIC_PGAS_PER_TX: u64 = 200;
|
||||
pub const DEVELOPER_SHARE_PERCENT: u128 = 20;
|
||||
|
||||
/// One gwei in wei.
|
||||
pub const GWEI: u128 = 1_000_000_000;
|
||||
|
||||
/// The proving-gas table: the unit and the entries that have been calibrated. Every other opcode and precompile
|
||||
/// entry keeps its prototype shape (`pgas.rs`) until it is measured. Field for field the node's `PgasTable`.
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct PgasTable {
|
||||
/// 0 = the prototype table of 3 October 2026; 1 = calibrated v1 (4 October 2026: modexp and the intrinsic).
|
||||
pub version: u32,
|
||||
/// How many reference SP1 cycles one pgas stands for. Prototype and v1 both use 1,000.
|
||||
pub cycles_per_pgas: u64,
|
||||
/// Intrinsic pgas per included transaction. Prototype 200; v1 300.
|
||||
pub intrinsic_pgas_per_tx: u64,
|
||||
/// modexp (precompile 0x05): `modexp_base + input_bytes x modexp_per_byte_numer / modexp_per_byte_denom`.
|
||||
/// Prototype 1,000 + 10 per byte; v1 10 + 1 per 10 bytes.
|
||||
pub modexp_base: u64,
|
||||
pub modexp_per_byte_numer: u64,
|
||||
pub modexp_per_byte_denom: u64,
|
||||
}
|
||||
|
||||
impl Default for PgasTable {
|
||||
fn default() -> Self {
|
||||
PgasTable::PROTOTYPE
|
||||
}
|
||||
}
|
||||
|
||||
impl PgasTable {
|
||||
pub const PROTOTYPE: PgasTable =
|
||||
PgasTable { version: 0, cycles_per_pgas: 1_000, intrinsic_pgas_per_tx: 200, modexp_base: 1_000, modexp_per_byte_numer: 10, modexp_per_byte_denom: 1 };
|
||||
pub const CALIBRATED_V1: PgasTable =
|
||||
PgasTable { version: 1, cycles_per_pgas: 1_000, intrinsic_pgas_per_tx: 300, modexp_base: 10, modexp_per_byte_numer: 1, modexp_per_byte_denom: 10 };
|
||||
|
||||
/// The modexp entry for an input of `input_bytes`.
|
||||
pub fn modexp(&self, input_bytes: u64) -> u64 {
|
||||
self.modexp_base.saturating_add(input_bytes.saturating_mul(self.modexp_per_byte_numer) / self.modexp_per_byte_denom.max(1))
|
||||
}
|
||||
}
|
||||
|
||||
/// The fee parameters of one network, field for field the node's `FeeParams` (and the override file's `fees`
|
||||
/// object).
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct FeeParams {
|
||||
pub pgas: PgasTable,
|
||||
/// `B_p`: proving gas per block (design 4.3).
|
||||
pub block_proving_gas_limit: u64,
|
||||
/// `S_p`: proving gas per shard (spec 7.4). `B_p / 4` on every table so far.
|
||||
pub shard_proving_gas_budget: u64,
|
||||
/// The floor of the execution-gas base fee, wei per gas.
|
||||
pub min_execution_base_fee_wei: u128,
|
||||
/// The floor of the proving-gas base fee, wei per pgas.
|
||||
pub min_proving_base_fee_wei: u128,
|
||||
pub initial_execution_base_fee_wei: u128,
|
||||
pub initial_proving_base_fee_wei: u128,
|
||||
pub base_fee_change_denominator: u128,
|
||||
}
|
||||
|
||||
impl FeeParams {
|
||||
/// The devnet v3 and v4 values (3 October 2026): what the live devnet runs until its switch.
|
||||
pub const PROTOTYPE: FeeParams = FeeParams {
|
||||
pgas: PgasTable::PROTOTYPE,
|
||||
block_proving_gas_limit: 30_000_000,
|
||||
shard_proving_gas_budget: 7_500_000,
|
||||
min_execution_base_fee_wei: GWEI,
|
||||
min_proving_base_fee_wei: GWEI,
|
||||
initial_execution_base_fee_wei: GWEI,
|
||||
initial_proving_base_fee_wei: GWEI,
|
||||
base_fee_change_denominator: 8,
|
||||
};
|
||||
|
||||
/// Calibrated v1, adopted 5 October 2026 (spec 05 section 5.11, `docs/analysis/base-fee-floor.md`).
|
||||
pub const CALIBRATED_V1: FeeParams = FeeParams {
|
||||
pgas: PgasTable::CALIBRATED_V1,
|
||||
block_proving_gas_limit: 120_000,
|
||||
shard_proving_gas_budget: 30_000,
|
||||
min_execution_base_fee_wei: 100 * GWEI,
|
||||
min_proving_base_fee_wei: 10_000 * GWEI,
|
||||
initial_execution_base_fee_wei: 100 * GWEI,
|
||||
initial_proving_base_fee_wei: 10_000 * GWEI,
|
||||
base_fee_change_denominator: 8,
|
||||
};
|
||||
|
||||
pub const DEVNET: FeeParams = FeeParams::PROTOTYPE;
|
||||
pub const SIMNET: FeeParams = FeeParams::PROTOTYPE;
|
||||
pub const TESTNET: FeeParams = FeeParams::CALIBRATED_V1;
|
||||
pub const MAINNET: FeeParams = FeeParams::CALIBRATED_V1;
|
||||
|
||||
/// A short name for logs and results.
|
||||
pub fn name(&self) -> &'static str {
|
||||
if *self == FeeParams::CALIBRATED_V1 {
|
||||
"calibrated v1"
|
||||
} else if *self == FeeParams::PROTOTYPE {
|
||||
"prototype"
|
||||
} else {
|
||||
"custom"
|
||||
}
|
||||
}
|
||||
|
||||
/// The floors, as the `u64` base fees of the fixture environment carry them.
|
||||
pub fn floor_exec_u64(&self) -> u64 {
|
||||
u64::try_from(self.min_execution_base_fee_wei).unwrap_or(u64::MAX)
|
||||
}
|
||||
pub fn floor_proving_u64(&self) -> u64 {
|
||||
u64::try_from(self.min_proving_base_fee_wei).unwrap_or(u64::MAX)
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for FeeParams {
|
||||
fn default() -> Self {
|
||||
FeeParams::PROTOTYPE
|
||||
}
|
||||
}
|
||||
|
||||
/// A network's fee schedule: the base set and the DAA score from which calibrated v1 applies instead (the node's
|
||||
/// `Params::fees` and `Params::fees_v1_activation_daa`; `u64::MAX` = never). Part of every shard input; the
|
||||
/// exporter writes it from the node the dump came from.
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct FeeSchedule {
|
||||
pub base: FeeParams,
|
||||
pub v1_activation_daa: u64,
|
||||
}
|
||||
|
||||
impl FeeSchedule {
|
||||
/// The devnet's schedule as compiled: the prototype set, the switch never. What a fixture written before the
|
||||
/// switch existed (no `fees` field) runs.
|
||||
pub const DEVNET: FeeSchedule = FeeSchedule { base: FeeParams::DEVNET, v1_activation_daa: u64::MAX };
|
||||
|
||||
pub const fn devnet() -> FeeSchedule {
|
||||
FeeSchedule::DEVNET
|
||||
}
|
||||
|
||||
/// The set that meters a chain block at DAA score `daa`: the node's `FeeSchedule::at`.
|
||||
pub fn at(&self, daa: u64) -> FeeParams {
|
||||
if daa >= self.v1_activation_daa {
|
||||
FeeParams::CALIBRATED_V1
|
||||
} else {
|
||||
self.base
|
||||
}
|
||||
}
|
||||
|
||||
/// For logs: "prototype, calibrated v1 from DAA score 197,000".
|
||||
pub fn describe(&self) -> String {
|
||||
let switch = if self.v1_activation_daa == u64::MAX { "never".to_string() } else { self.v1_activation_daa.to_string() };
|
||||
format!("{}, calibrated v1 from DAA score {switch}", self.base.name())
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for FeeSchedule {
|
||||
fn default() -> Self {
|
||||
FeeSchedule::DEVNET
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
/// The node's `fees.rs` tests, repeated here so a drift in the mirror fails on this side too.
|
||||
#[test]
|
||||
fn the_two_tables_are_the_nodes() {
|
||||
let v1 = FeeParams::CALIBRATED_V1;
|
||||
assert_eq!(v1.block_proving_gas_limit, 4 * v1.shard_proving_gas_budget);
|
||||
assert_eq!(v1.block_proving_gas_limit / v1.pgas.intrinsic_pgas_per_tx, 400);
|
||||
assert_eq!(v1.min_execution_base_fee_wei, 100_000_000_000);
|
||||
assert_eq!(v1.min_proving_base_fee_wei, 10_000_000_000_000);
|
||||
let p = FeeParams::PROTOTYPE;
|
||||
assert_eq!(p.block_proving_gas_limit, 4 * p.shard_proving_gas_budget);
|
||||
assert_eq!((p.shard_proving_gas_budget, p.pgas.intrinsic_pgas_per_tx), (7_500_000, 200));
|
||||
for bytes in [0u64, 96, 192, 384, 1_024, 4_096] {
|
||||
assert_eq!(PgasTable::PROTOTYPE.modexp(bytes), 1_000 + 10 * bytes);
|
||||
assert_eq!(PgasTable::CALIBRATED_V1.modexp(bytes), 10 + bytes / 10);
|
||||
}
|
||||
assert_eq!(FeeParams::DEVNET, FeeParams::PROTOTYPE);
|
||||
assert_eq!(FeeParams::TESTNET, FeeParams::CALIBRATED_V1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn the_v1_height_switch() {
|
||||
let s = FeeSchedule { base: FeeParams::PROTOTYPE, v1_activation_daa: 1_000 };
|
||||
assert_eq!(s.at(0), FeeParams::PROTOTYPE);
|
||||
assert_eq!(s.at(999), FeeParams::PROTOTYPE);
|
||||
assert_eq!(s.at(1_000), FeeParams::CALIBRATED_V1);
|
||||
assert_eq!(FeeSchedule::DEVNET.at(u64::MAX - 1), FeeParams::PROTOTYPE);
|
||||
let t = FeeSchedule { base: FeeParams::TESTNET, v1_activation_daa: 0 };
|
||||
assert_eq!(t.at(0), FeeParams::CALIBRATED_V1);
|
||||
let f = FeeSchedule { base: FeeParams::CALIBRATED_V1, v1_activation_daa: u64::MAX };
|
||||
assert_eq!(f.at(0), FeeParams::CALIBRATED_V1);
|
||||
assert_eq!(FeeSchedule::default(), FeeSchedule::DEVNET);
|
||||
assert_eq!(FeeSchedule::DEVNET.describe(), "prototype, calibrated v1 from DAA score never");
|
||||
}
|
||||
|
||||
/// The override file's `fees` object (infra/fast-time/override-60x.json) decodes into the same struct.
|
||||
#[test]
|
||||
fn the_override_fees_object_decodes() {
|
||||
let json = r#"{"pgas": {"version": 1, "cycles_per_pgas": 1000, "intrinsic_pgas_per_tx": 300, "modexp_base": 10, "modexp_per_byte_numer": 1, "modexp_per_byte_denom": 10}, "block_proving_gas_limit": 120000, "shard_proving_gas_budget": 30000, "min_execution_base_fee_wei": 100000000000, "min_proving_base_fee_wei": 10000000000000, "initial_execution_base_fee_wei": 100000000000, "initial_proving_base_fee_wei": 10000000000000, "base_fee_change_denominator": 8}"#;
|
||||
let f: FeeParams = serde_json::from_str(json).unwrap();
|
||||
assert_eq!(f, FeeParams::CALIBRATED_V1);
|
||||
let back: FeeParams = serde_json::from_str(&serde_json::to_string(&FeeParams::PROTOTYPE).unwrap()).unwrap();
|
||||
assert_eq!(back, FeeParams::PROTOTYPE);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,11 @@
|
|||
//! Segment execution, ported from igneum-exec `executor.rs` at b7fca5a0 (design sections 1 to 4, spec 7.5):
|
||||
//! Segment execution, ported from igneum-exec `executor.rs` at fork 2b6d23ef (design sections 1 to 4, spec 7.5):
|
||||
//! rewards by rule, every block's transactions in sequence order under the Igneum environment, two-dimensional
|
||||
//! gas with the incremental cap and the abort, fee flows and the nonce-rule skip. Devnet v4 addition: the
|
||||
//! executor runs any contiguous range of a segment's transactions from a carried-in position (design 5.1), and
|
||||
//! emits one boundary per transaction with the cumulative gas and pgas, the carry, and (natively) the state
|
||||
//! root, which is what the shard planner cuts on.
|
||||
//! root, which is what the shard planner cuts on. 5 October 2026: the fee set (table, budgets, floors) is the
|
||||
//! schedule's set at the block's DAA score (`fees_v1_activation_daa`), and the carried-in base fees are raised to
|
||||
//! that set's floors first, exactly as the node's `execute_segment` does.
|
||||
|
||||
use crate::config::*;
|
||||
use crate::fixture::FixtureEnv;
|
||||
|
|
@ -189,7 +191,14 @@ pub struct RangeOutcome {
|
|||
/// Executes a contiguous range of a segment's transactions on `db` from `carry_in` (design 1.2 and 5.1): the
|
||||
/// rewards first when given (the segment's first shard), then every transaction in order. `db` is the state
|
||||
/// before the range on entry and after it on return. With `roots`, the state root is computed at every boundary.
|
||||
pub fn execute_range(db: &mut IgneumDb, chain_id: u64, env: &FixtureEnv, rewards: Option<(&[(Address, U256)], U256, &[(Address, U256)])>, txs: &[ShardTx], carry_in: Carry, roots: bool) -> RangeOutcome {
|
||||
pub fn execute_range(db: &mut IgneumDb, chain_id: u64, env: &FixtureEnv, schedule: &FeeSchedule, rewards: Option<(&[(Address, U256)], U256, &[(Address, U256)])>, txs: &[ShardTx], carry_in: Carry, roots: bool) -> RangeOutcome {
|
||||
// The fee set that meters this chain block: the schedule read at the block's own DAA score, so the guest
|
||||
// replays the height switch as the node does. The base fees carried in are raised to this set's floors here
|
||||
// (the node does the same; the record, and so the fixture, already carry the raised values).
|
||||
let fees = schedule.at(env.daa_score);
|
||||
let env = &FixtureEnv { base_fee_exec: env.base_fee_exec.max(fees.floor_exec_u64()), base_fee_proving: env.base_fee_proving.max(fees.floor_proving_u64()), ..env.clone() };
|
||||
let intrinsic_pgas = fees.pgas.intrinsic_pgas_per_tx;
|
||||
let block_proving_limit = fees.block_proving_gas_limit;
|
||||
let base_fee_exec = env.base_fee_exec as u128;
|
||||
let base_fee_proving = env.base_fee_proving as u128;
|
||||
|
||||
|
|
@ -229,9 +238,9 @@ pub fn execute_range(db: &mut IgneumDb, chain_id: u64, env: &FixtureEnv, rewards
|
|||
break 'tx;
|
||||
}
|
||||
};
|
||||
carry.block_pgas = carry.block_pgas.saturating_add(INTRINSIC_PGAS_PER_TX);
|
||||
range_pgas = range_pgas.saturating_add(INTRINSIC_PGAS_PER_TX);
|
||||
if carry.block_pgas > BLOCK_PROVING_GAS_LIMIT {
|
||||
carry.block_pgas = carry.block_pgas.saturating_add(intrinsic_pgas);
|
||||
range_pgas = range_pgas.saturating_add(intrinsic_pgas);
|
||||
if carry.block_pgas > block_proving_limit {
|
||||
// Only the intrinsic pgas of the included copies can get here: one comparison, no execution.
|
||||
skipped.push((tx.hash, Skip::BlockProvingBudget));
|
||||
break 'tx;
|
||||
|
|
@ -245,8 +254,8 @@ pub fn execute_range(db: &mut IgneumDb, chain_id: u64, env: &FixtureEnv, rewards
|
|||
let budget = tx.wei_budget();
|
||||
// Spec 7.5 item 1: the transaction may meter at most the block's remaining proving budget; the
|
||||
// inspector halts it the moment one more opcode or precompile would cross that.
|
||||
let pgas_cap = BLOCK_PROVING_GAS_LIMIT - carry.block_pgas;
|
||||
let inspector = IgneumInspector::new(tx.intrinsic_gas, price, base_fee_proving, budget, pgas_cap);
|
||||
let pgas_cap = block_proving_limit - carry.block_pgas;
|
||||
let inspector = IgneumInspector::new(tx.intrinsic_gas, price, base_fee_proving, budget, pgas_cap, fees.pgas);
|
||||
let (result, state, insp) = {
|
||||
let ctx = Context::mainnet().with_db(DbRef(db)).with_cfg(cfg(chain_id)).with_block(block_env(env, t.miner));
|
||||
let mut evm = ctx.build_mainnet_with_inspector(inspector);
|
||||
|
|
@ -263,8 +272,8 @@ pub fn execute_range(db: &mut IgneumDb, chain_id: u64, env: &FixtureEnv, rewards
|
|||
}
|
||||
};
|
||||
|
||||
let pgas_used = insp.pgas.saturating_add(INTRINSIC_PGAS_PER_TX);
|
||||
debug_assert!(carry.block_pgas.saturating_add(insp.pgas) <= BLOCK_PROVING_GAS_LIMIT, "the inspector cap bounds the block's pgas");
|
||||
let pgas_used = insp.pgas.saturating_add(intrinsic_pgas);
|
||||
debug_assert!(carry.block_pgas.saturating_add(insp.pgas) <= block_proving_limit, "the inspector cap bounds the block's pgas");
|
||||
carry.block_pgas = carry.block_pgas.saturating_add(insp.pgas);
|
||||
range_pgas = range_pgas.saturating_add(insp.pgas);
|
||||
|
||||
|
|
@ -386,7 +395,7 @@ pub struct BlockOutcome {
|
|||
/// recorded after every transaction.
|
||||
pub fn execute_block(db: &mut IgneumDb, f: &crate::fixture::BlockFixture) -> BlockOutcome {
|
||||
let txs = f.flatten();
|
||||
let out = execute_range(db, f.chain_id, &f.env, Some((&f.rewards, f.proving_pool_credit, &f.payouts)), &txs, Carry::default(), true);
|
||||
let out = execute_range(db, f.chain_id, &f.env, &f.fees, Some((&f.rewards, f.proving_pool_credit, &f.payouts)), &txs, Carry::default(), true);
|
||||
let state_root = db.state_root();
|
||||
BlockOutcome {
|
||||
executed: out.executed,
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
//! The fixture: one real chain block as the execution layer exported it, with the pre-state it ran on, its
|
||||
//! shard plan and what every shard must reproduce. JSON on disk (`proving/fixtures/*.json`).
|
||||
|
||||
use crate::config::FeeSchedule;
|
||||
use crate::executor::ShardTx;
|
||||
use alloy_primitives::{Address, Bytes, B256, U256};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
|
@ -16,9 +17,14 @@ pub struct FixtureEnv {
|
|||
pub timestamp: u64,
|
||||
pub miner: Address,
|
||||
pub prevrandao: B256,
|
||||
/// Base fees in wei per unit, both dimensions (fit in u64 on the devnet; the executor widens to u128).
|
||||
/// Base fees in wei per unit, both dimensions (fit in u64 on the devnet; the executor widens to u128). As the
|
||||
/// node recorded them: already raised to the floors of the set that meters this block.
|
||||
pub base_fee_exec: u64,
|
||||
pub base_fee_proving: u64,
|
||||
/// The chain block's DAA score: what the fee schedule is read at (`fees_v1_activation_daa`, 5 October 2026).
|
||||
/// A fixture written before the switch existed has none, and 0 keeps it on the schedule's base set.
|
||||
#[serde(default)]
|
||||
pub daa_score: u64,
|
||||
}
|
||||
|
||||
/// One block of the segment in sequence order: its miner (the beneficiary of its transactions) and its
|
||||
|
|
@ -56,6 +62,10 @@ pub struct BlockFixture {
|
|||
pub payouts: Vec<(Address, U256)>,
|
||||
pub blocks: Vec<IncludingBlock>,
|
||||
pub pre_state: Vec<AccountFixture>,
|
||||
/// The fee schedule the node ran (its base set and `fees_v1_activation_daa`), read at `env.daa_score`. A
|
||||
/// fixture without it is the devnet as compiled: the prototype set, the switch never.
|
||||
#[serde(default = "FeeSchedule::devnet")]
|
||||
pub fees: FeeSchedule,
|
||||
}
|
||||
|
||||
impl BlockFixture {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
//! Mirror of igneum-exec `pgas.rs` at b7fca5a0 (the prototype pgas table, the per-frame developer attribution and
|
||||
//! the spec 7.5 cap: metering halts the transaction before the opcode or precompile that would cross it).
|
||||
//! Mirror of igneum-exec `pgas.rs` at fork 2b6d23ef (the pgas table of the block being metered, the per-frame
|
||||
//! developer attribution and the spec 7.5 cap: metering halts the transaction before the opcode or precompile
|
||||
//! that would cross it). The calibrated entries (the intrinsic, modexp) come from `config::PgasTable`.
|
||||
//! Proving gas (design 4.2) and the per-frame developer attribution (design 4.5), both measured by one revm
|
||||
//! inspector while the native execution runs.
|
||||
//!
|
||||
|
|
@ -8,6 +9,7 @@
|
|||
//! The design requires every entry to be calibrated in the reference prover (SP1) with three input sizes before
|
||||
//! the public testnet (R1). Unit: 1 pgas = 1,000 reference-prover cycles, rounded up.
|
||||
|
||||
use crate::config::PgasTable;
|
||||
use crate::registry::{address_from_word, creator_slot, payee_slot, word_from_address};
|
||||
use alloy_primitives::{Address, U256};
|
||||
use revm::context_interface::{ContextTr, JournalTr};
|
||||
|
|
@ -63,7 +65,7 @@ pub fn opcode_pgas(op: u8, interp: &Interpreter) -> u64 {
|
|||
}
|
||||
|
||||
/// Precompile pgas by address and input length (design 4.2 shapes, prototype magnitudes).
|
||||
pub fn precompile_pgas(address: Address, input_len: usize, input: &[u8]) -> Option<u64> {
|
||||
pub fn precompile_pgas(address: Address, input_len: usize, input: &[u8], table: &PgasTable) -> Option<u64> {
|
||||
let words = (input_len as u64).div_ceil(32);
|
||||
let last = address.as_slice()[19];
|
||||
if address.as_slice()[..19].iter().any(|b| *b != 0) {
|
||||
|
|
@ -74,7 +76,7 @@ pub fn precompile_pgas(address: Address, input_len: usize, input: &[u8]) -> Opti
|
|||
0x02 => 60 + 12 * words, // sha256
|
||||
0x03 => 600 + 120 * words, // ripemd160: no zkVM precompile
|
||||
0x04 => 15 + 3 * words, // identity
|
||||
0x05 => 1_000 + 10 * input_len as u64, // modexp: pure big-number arithmetic, expected to be the costliest per gas
|
||||
0x05 => table.modexp(input_len as u64), // modexp: the table's entry (prototype 1,000 + 10 per byte; v1 10 + 1 per 10 bytes)
|
||||
0x06 => 500, // ecadd
|
||||
0x07 => 6_000, // ecmul
|
||||
0x08 => 45_000 + 34_000 * (input_len as u64 / 192), // ecpairing per pair
|
||||
|
|
@ -129,6 +131,8 @@ pub struct IgneumInspector {
|
|||
pub budget_wei: u128,
|
||||
/// Set when the running charge crossed the budget and the current frame was halted (design 4.1).
|
||||
pub over_budget: bool,
|
||||
/// The pgas table of the block being metered (`FeeSchedule::at(daa).pgas`): the calibrated entries.
|
||||
pub pgas_table: PgasTable,
|
||||
pub attributions: Vec<FrameAttribution>,
|
||||
/// Successful CREATE and CREATE2 frames as (creator, new contract), in order.
|
||||
pub creates: Vec<(Address, Address)>,
|
||||
|
|
@ -138,8 +142,8 @@ pub struct IgneumInspector {
|
|||
}
|
||||
|
||||
impl IgneumInspector {
|
||||
pub fn new(intrinsic_gas: u64, exec_price: u128, proving_base_fee: u128, budget_wei: u128, pgas_cap: u64) -> Self {
|
||||
Self { intrinsic_gas, exec_price, proving_base_fee, budget_wei, pgas_cap, ..Default::default() }
|
||||
pub fn new(intrinsic_gas: u64, exec_price: u128, proving_base_fee: u128, budget_wei: u128, pgas_cap: u64, pgas_table: PgasTable) -> Self {
|
||||
Self { intrinsic_gas, exec_price, proving_base_fee, budget_wei, pgas_cap, pgas_table, ..Default::default() }
|
||||
}
|
||||
|
||||
/// Meters `delta` pgas unless that would cross the cap. Returns false, and marks the abort, when it would;
|
||||
|
|
@ -235,7 +239,7 @@ impl<CTX: ContextTr> Inspector<CTX> for IgneumInspector {
|
|||
};
|
||||
// Precompile frames are charged here (they run no opcodes); their attribution share burns (design 4.5).
|
||||
let input_bytes: Vec<u8> = inputs.input.bytes(_ctx).to_vec();
|
||||
if let Some(p) = precompile_pgas(inputs.bytecode_address, input_bytes.len(), &input_bytes) {
|
||||
if let Some(p) = precompile_pgas(inputs.bytecode_address, input_bytes.len(), &input_bytes, &self.pgas_table) {
|
||||
if !self.meter(p) {
|
||||
// Spec 7.5: the precompile is not run. The frame is answered with a revert that spends none of the
|
||||
// forwarded gas, so the parent's consumed gas stays exact; the parent halts at its next step
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
//! the shard's transactions from the carried-in position yields the post-root, the shard's receipts root, its
|
||||
//! gas and pgas, and the carried-out position; the prover's payout address is committed with it.
|
||||
|
||||
use crate::config::FeeSchedule;
|
||||
use crate::executor::{execute_range, Carry, ShardTx};
|
||||
use crate::fixture::FixtureEnv;
|
||||
use crate::witness::{self, StateWitness};
|
||||
|
|
@ -26,6 +27,9 @@ pub struct ShardInput {
|
|||
/// The payout address of the prover making this proof (ledger P12).
|
||||
pub prover: Address,
|
||||
pub witness: StateWitness,
|
||||
/// The fee schedule (both sets and the `fees_v1_activation_daa` switch), read at `env.daa_score`: which
|
||||
/// table, budgets and floors meter this block. The node vetoes a statement made under another schedule.
|
||||
pub fees: FeeSchedule,
|
||||
}
|
||||
|
||||
/// The public values of a shard proof, one fixed byte layout.
|
||||
|
|
@ -108,7 +112,7 @@ impl ShardOutput {
|
|||
pub fn shard_statement(input: &ShardInput) -> ShardOutput {
|
||||
let (mut db, pre_root) = witness::load(&input.witness, &input.block_hashes);
|
||||
let rewards = (input.shard_index == 0).then_some((&input.rewards[..], input.proving_pool_credit, &input.payouts[..]));
|
||||
let out = execute_range(&mut db, input.chain_id, &input.env, rewards, &input.txs, input.carry_in, false);
|
||||
let out = execute_range(&mut db, input.chain_id, &input.env, &input.fees, rewards, &input.txs, input.carry_in, false);
|
||||
let post_root = witness::post_root(&db, &input.witness);
|
||||
ShardOutput {
|
||||
chain_id: input.chain_id,
|
||||
|
|
@ -158,7 +162,7 @@ pub fn build_shards(block: &crate::fixture::BlockFixture, budget: u64, prover: A
|
|||
let rewards = (spec.index == 0).then_some((&block.rewards[..], block.proving_pool_credit, &block.payouts[..]));
|
||||
let pre = state.clone();
|
||||
state.start_log();
|
||||
let _ = execute_range(&mut state, block.chain_id, &block.env, rewards, range, spec.carry_in, false);
|
||||
let _ = execute_range(&mut state, block.chain_id, &block.env, &block.fees, rewards, range, spec.carry_in, false);
|
||||
let log = state.take_log();
|
||||
let witness = witness::generate(&pre, &log);
|
||||
let input = ShardInput {
|
||||
|
|
@ -173,6 +177,7 @@ pub fn build_shards(block: &crate::fixture::BlockFixture, budget: u64, prover: A
|
|||
carry_in: spec.carry_in,
|
||||
prover,
|
||||
witness,
|
||||
fees: block.fees,
|
||||
};
|
||||
let output = shard_statement(&input);
|
||||
assert_eq!(output.pre_root, spec.pre_root, "shard {} pre-root from the witness", spec.index);
|
||||
|
|
|
|||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -1,22 +1,22 @@
|
|||
{
|
||||
"aggregator": {
|
||||
"elf": "igneum-prove-aggregator.elf",
|
||||
"elf_bytes": 320264,
|
||||
"elf_sha256": "0x788a67ec86972e7e27e181aeece28b320a13237cdeebdb8794527c8d6f6278f7",
|
||||
"program_id": "0x135e67e742fbbcc8303676765266f25a6520ab36299820280125541051fb6c62",
|
||||
"elf_bytes": 319744,
|
||||
"elf_sha256": "0x143d9c243dd12e87e90be71f6b8cd42353e513bf8ce78903ef6f972f1bc9aa7b",
|
||||
"program_id": "0x474678f35f7545db28055d5e5bbc308231d84a5a072202087a2a8d5b09123896",
|
||||
"vk": "igneum-prove-aggregator.vk",
|
||||
"vk_sha256": "0xc208a42bd50fdd9c959ff9af55de666b8130d103763c8e8a349f5a3feee8d339"
|
||||
"vk_sha256": "0xad17bc1ae5be816554dbb13cb5b4d242678adfb8e1a4f7247ceb8b5ba9001b9f"
|
||||
},
|
||||
"format": "igneum-prove-elf-manifest-v1",
|
||||
"pinned_at": "2026-10-05T12:07:56Z",
|
||||
"pinned_at": "2026-10-05T16:20:38Z",
|
||||
"pinned_on": "Darwin MacBook-Pro.local 25.6.0 Darwin Kernel Version 25.6.0: Fri Jul 31 19:19:08 PDT 2026; root:xnu-12377.161.14~5/RELEASE_ARM64_T6050 arm64",
|
||||
"shard": {
|
||||
"elf": "igneum-prove-program.elf",
|
||||
"elf_bytes": 2825296,
|
||||
"elf_sha256": "0x65901e2dd6cc5762c5a989cffc199d4621828225fcf1513e44d002660f036a1d",
|
||||
"program_id": "0x0dfade071ffc05a50be5f7e6640fb12638bac0ea63697ec252863f55658be16a",
|
||||
"elf_bytes": 2832504,
|
||||
"elf_sha256": "0x150f4c05a2951fc56174a87089707a030b18df8fbe7e053a66459edb83053083",
|
||||
"program_id": "0x2b1a81cb413236cf063077b46ed3111628f6c41036bcf6e23ee4cbbf5679ef7a",
|
||||
"vk": "igneum-prove-program.vk",
|
||||
"vk_sha256": "0x262f5b4be7d17ec26c6aa37c438aa774a7037249202f8401d027ef73e3612e4c"
|
||||
"vk_sha256": "0x8b4da5bff86d963f4210a78e5d800a1cd00ab41b158f6962f4ac009edc249d4c"
|
||||
},
|
||||
"sp1_circuit_version": "v6.1.0",
|
||||
"sp1_crate_version": "6.8.1"
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
//! Usage: igneum-prove-export <seq.json> <block number> <out.json> [--source "text"] [--budget <pgas>]
|
||||
//! [--fees-v1-activation-daa <DAA|never>] [--fees-base prototype|v1]
|
||||
//!
|
||||
//! `seq.json` is the output of `igneum_exportSegments` (tools/evm-smoke and tools/prove-fixtures write it). The
|
||||
//! exporter rebuilds the genesis state (the DeveloperRegistry at its fixed address, nothing else), replays every
|
||||
|
|
@ -6,10 +7,18 @@
|
|||
//! `stateRoot`. Any mismatch is fatal: the port would not be the node's executor. At the requested block it
|
||||
//! snapshots the pre-state, runs the block, cuts the shard plan at `S_p` (or `--budget`, a test cut), builds
|
||||
//! and checks every shard's witness, and writes the fixture with the expected values per shard and per block.
|
||||
//!
|
||||
//! The fee schedule (5 October 2026, `fees_v1_activation_daa`): the dump's top-level `feesV1ActivationDaa` (a
|
||||
//! number, or null for never; tools/prove-fixtures/gen.mjs writes it from the node's override file) and `fees`
|
||||
//! (the override file's base set, absent = the prototype), and each segment's `daaScore` (gen.mjs reads it from
|
||||
//! `eth_getBlockByNumber`). The flags override the dump. The replay reads the schedule at every segment's DAA
|
||||
//! score, so a dump whose chain crosses the switch is replayed with both tables and the state roots prove the
|
||||
//! port's schedule is the node's on both sides. A dump without `daaScore` is accepted only when the switch is
|
||||
//! never or 0 (the DAA score does not matter then).
|
||||
|
||||
use alloy_primitives::{keccak256, Address, Bytes, B256, U256};
|
||||
use anyhow::{ensure, bail, Context, Result};
|
||||
use igneum_prove_core::config::{DEVELOPER_REGISTRY_ADDRESS, SHARD_PROVING_GAS_BUDGET};
|
||||
use igneum_prove_core::config::{FeeParams, FeeSchedule, DEVELOPER_REGISTRY_ADDRESS};
|
||||
use igneum_prove_core::shard::build_shards;
|
||||
use igneum_prove_core::{execute_block, AccountFixture, BlockFixture, Expected, Fixture, FixtureEnv, IgneumDb, IncludingBlock, Plan, ShardExpected};
|
||||
use serde_json::Value;
|
||||
|
|
@ -26,6 +35,15 @@ fn u256(v: &Value) -> Result<U256> {
|
|||
fn bytes(v: &Value) -> Result<Vec<u8>> {
|
||||
Ok(hex::decode(v.as_str().context("hex")?.trim_start_matches("0x"))?)
|
||||
}
|
||||
/// A u64 written as a JSON number, a decimal string or a 0x hex string (the eth_ RPC's quantity form).
|
||||
fn u64_of(v: &Value) -> Result<Option<u64>> {
|
||||
Ok(match v {
|
||||
Value::Null => None,
|
||||
Value::Number(n) => Some(n.as_u64().context("u64")?),
|
||||
Value::String(t) => Some(if let Some(h) = t.strip_prefix("0x") { u64::from_str_radix(h, 16)? } else { t.parse()? }),
|
||||
other => bail!("not a u64: {other}"),
|
||||
})
|
||||
}
|
||||
|
||||
/// Rebuilds the segment's including blocks from the export.
|
||||
///
|
||||
|
|
@ -92,7 +110,7 @@ fn blocks_of(seg: &Value) -> Result<Vec<IncludingBlock>> {
|
|||
Ok(out)
|
||||
}
|
||||
|
||||
fn fixture_of(export: &Value, segments: &[Value], n: usize, hashes: &[(u64, B256)], db: &IgneumDb) -> Result<BlockFixture> {
|
||||
fn fixture_of(export: &Value, segments: &[Value], n: usize, hashes: &[(u64, B256)], db: &IgneumDb, fees: FeeSchedule) -> Result<BlockFixture> {
|
||||
let seg = &segments[n];
|
||||
let chain_id = export["chainId"].as_u64().context("chainId")?;
|
||||
let parent_hash = if n == 0 { B256::ZERO } else { b256(&segments[n - 1]["hash"])? };
|
||||
|
|
@ -105,6 +123,11 @@ fn fixture_of(export: &Value, segments: &[Value], n: usize, hashes: &[(u64, B256
|
|||
prevrandao: b256(&seg["prevrandao"])?,
|
||||
base_fee_exec: seg["baseFeeExec"].as_str().context("baseFeeExec")?.parse()?,
|
||||
base_fee_proving: seg["baseFeeProving"].as_str().context("baseFeeProving")?.parse()?,
|
||||
daa_score: match u64_of(&seg["daaScore"])? {
|
||||
Some(d) => d,
|
||||
None if fees.v1_activation_daa == 0 || fees.v1_activation_daa == u64::MAX => 0,
|
||||
None => bail!("segment {}: the dump carries no daaScore and the schedule switches at DAA {}; re-export with tools/prove-fixtures/gen.mjs, which writes it", seg["number"], fees.v1_activation_daa),
|
||||
},
|
||||
};
|
||||
let rewards = seg["rewards"].as_array().context("rewards")?.iter().map(|r| Ok((addr(&r["address"])?, u256(&r["wei"])?))).collect::<Result<Vec<_>>>()?;
|
||||
let proving_pool_credit: U256 = seg["provingPoolCredit"].as_str().context("provingPoolCredit")?.parse()?;
|
||||
|
|
@ -125,6 +148,7 @@ fn fixture_of(export: &Value, segments: &[Value], n: usize, hashes: &[(u64, B256
|
|||
payouts,
|
||||
blocks: blocks_of(seg)?,
|
||||
pre_state,
|
||||
fees,
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -137,12 +161,32 @@ fn main() -> Result<()> {
|
|||
let want: u64 = args[2].parse()?;
|
||||
let out_path = &args[3];
|
||||
let source = args.iter().position(|a| a == "--source").and_then(|i| args.get(i + 1)).cloned().unwrap_or_else(|| format!("{} (igneum_exportSegments), block {}", args[1], want));
|
||||
let budget: u64 = args.iter().position(|a| a == "--budget").and_then(|i| args.get(i + 1)).map(|b| b.parse()).transpose()?.unwrap_or(SHARD_PROVING_GAS_BUDGET);
|
||||
let budget_arg: Option<u64> = args.iter().position(|a| a == "--budget").and_then(|i| args.get(i + 1)).map(|b| b.parse()).transpose()?;
|
||||
|
||||
// The sources this binary was built from (export/build.rs), so a stale build names itself in every export log.
|
||||
println!("igneum-prove-export sources {} (core/src and export/src)", env!("IGNEUM_PROVE_SOURCES"));
|
||||
|
||||
let segments = export["segments"].as_array().context("segments")?.clone();
|
||||
|
||||
// The fee schedule the node ran: the dump's fields, then the flags.
|
||||
let mut fees = FeeSchedule { base: FeeParams::PROTOTYPE, v1_activation_daa: u64::MAX };
|
||||
if !export["fees"].is_null() {
|
||||
fees.base = serde_json::from_value(export["fees"].clone()).context("the dump's fees object is not the node's FeeParams")?;
|
||||
}
|
||||
if let Some(d) = u64_of(&export["feesV1ActivationDaa"])? {
|
||||
fees.v1_activation_daa = d;
|
||||
}
|
||||
if let Some(v) = args.iter().position(|a| a == "--fees-base").and_then(|i| args.get(i + 1)) {
|
||||
fees.base = match v.as_str() {
|
||||
"prototype" => FeeParams::PROTOTYPE,
|
||||
"v1" => FeeParams::CALIBRATED_V1,
|
||||
other => bail!("--fees-base {other}: prototype or v1"),
|
||||
};
|
||||
}
|
||||
if let Some(v) = args.iter().position(|a| a == "--fees-v1-activation-daa").and_then(|i| args.get(i + 1)) {
|
||||
fees.v1_activation_daa = if v == "never" { u64::MAX } else { v.parse()? };
|
||||
}
|
||||
println!("fee schedule: {}", fees.describe());
|
||||
let registry_code = bytes(&export["registryCode"])?;
|
||||
let mut db = IgneumDb::new();
|
||||
// The node's genesis inserts the registry through revm's `AccountInfo::from_bytecode`, which gives a contract
|
||||
|
|
@ -154,7 +198,7 @@ fn main() -> Result<()> {
|
|||
let mut checked = 0usize;
|
||||
for (n, seg) in segments.iter().enumerate() {
|
||||
let number = seg["number"].as_u64().context("number")?;
|
||||
let f = fixture_of(&export, &segments, n, &hashes, &db)?;
|
||||
let f = fixture_of(&export, &segments, n, &hashes, &db, fees)?;
|
||||
let pre_root = db.state_root();
|
||||
let node_root = b256(&seg["stateRoot"])?;
|
||||
let out = execute_block(&mut db, &f);
|
||||
|
|
@ -177,6 +221,21 @@ fn main() -> Result<()> {
|
|||
node_state_root: node_root,
|
||||
};
|
||||
let txs: usize = f.blocks.iter().map(|b| b.txs.len()).sum();
|
||||
let set = fees.at(f.env.daa_score);
|
||||
let consensus_budget = set.shard_proving_gas_budget;
|
||||
let budget = budget_arg.unwrap_or(consensus_budget);
|
||||
println!(
|
||||
"block {number} at DAA score {}: fee set {} (S_p {}, B_p {}, intrinsic {} pgas, floors {} and {} wei), base fees {} and {} wei",
|
||||
f.env.daa_score,
|
||||
set.name(),
|
||||
set.shard_proving_gas_budget,
|
||||
set.block_proving_gas_limit,
|
||||
set.pgas.intrinsic_pgas_per_tx,
|
||||
set.min_execution_base_fee_wei,
|
||||
set.min_proving_base_fee_wei,
|
||||
f.env.base_fee_exec,
|
||||
f.env.base_fee_proving
|
||||
);
|
||||
println!(
|
||||
"block {number}: {txs} transactions in {} including blocks, {} executed, {} skipped, gas {}, pgas {}, {} accounts in the pre-state",
|
||||
f.blocks.len(),
|
||||
|
|
@ -196,7 +255,7 @@ fn main() -> Result<()> {
|
|||
|
||||
// The shard plan and every shard's witness, checked natively (design 5.1).
|
||||
let (_, _, shards) = build_shards(&f, budget, Address::ZERO);
|
||||
println!(" plan: {} shard(s) at S_p = {budget} pgas{}", shards.len(), if budget == SHARD_PROVING_GAS_BUDGET { "" } else { " (TEST CUT below the consensus budget)" });
|
||||
println!(" plan: {} shard(s) at S_p = {budget} pgas{}", shards.len(), if budget == consensus_budget { "" } else { " (TEST CUT below the consensus budget)" });
|
||||
let mut plan_shards = Vec::with_capacity(shards.len());
|
||||
for s in &shards {
|
||||
let (accounts, slots, leaves, hashes) = s.input.witness.stats();
|
||||
|
|
@ -222,7 +281,7 @@ fn main() -> Result<()> {
|
|||
witness: (accounts as u32, slots as u32, leaves as u32, hashes as u32, bytes),
|
||||
});
|
||||
}
|
||||
let plan = Plan { shard_budget: budget, consensus: budget == SHARD_PROVING_GAS_BUDGET, shards: plan_shards };
|
||||
let plan = Plan { shard_budget: budget, consensus: budget == consensus_budget, shards: plan_shards };
|
||||
fixture = Some(Fixture { format: igneum_prove_core::fixture::FORMAT.into(), source: source.clone(), block: f, plan, expected });
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -89,17 +89,28 @@ fn run() -> Result<()> {
|
|||
let block = &fixture.block;
|
||||
let txs: usize = block.blocks.iter().map(|b| b.txs.len()).sum();
|
||||
let prover_kind = std::env::var("SP1_PROVER").unwrap_or_else(|_| "cpu".into());
|
||||
// The fee set that meters this block: the fixture's schedule read at the block's DAA score (5 October 2026,
|
||||
// `fees_v1_activation_daa`); the plan's budget must be that set's S_p unless the fixture says test cut.
|
||||
let fee_set = block.fees.at(block.env.daa_score);
|
||||
if fixture.plan.consensus && fixture.plan.shard_budget != fee_set.shard_proving_gas_budget {
|
||||
bail!("the fixture's plan says consensus budget {} but the fee set at DAA score {} ({}) has S_p {}; regenerate with igneum-prove-export", fixture.plan.shard_budget, block.env.daa_score, fee_set.name(), fee_set.shard_proving_gas_budget);
|
||||
}
|
||||
println!(
|
||||
"igneum-prove-host sources {}: fixture {path}: chain {} block {} ({}), {txs} transactions in {} including blocks, {} accounts in the pre-state, plan {} shard(s) at S_p = {} pgas{}; SP1_PROVER={prover_kind}; prover payout {prover}; {}",
|
||||
"igneum-prove-host sources {}: fixture {path}: chain {} block {} ({}) at DAA score {}, {txs} transactions in {} including blocks, {} accounts in the pre-state, plan {} shard(s) at S_p = {} pgas{}; fee schedule {}: this block meters with {} (intrinsic {} pgas, B_p {}); SP1_PROVER={prover_kind}; prover payout {prover}; {}",
|
||||
env!("IGNEUM_PROVE_SOURCES"),
|
||||
block.chain_id,
|
||||
block.env.number,
|
||||
block.env.hash,
|
||||
block.env.daa_score,
|
||||
block.blocks.len(),
|
||||
block.pre_state.len(),
|
||||
fixture.plan.shards.len(),
|
||||
fixture.plan.shard_budget,
|
||||
if fixture.plan.consensus { "" } else { " (TEST CUT below the consensus budget)" },
|
||||
block.fees.describe(),
|
||||
fee_set.name(),
|
||||
fee_set.pgas.intrinsic_pgas_per_tx,
|
||||
fee_set.block_proving_gas_limit,
|
||||
now()
|
||||
);
|
||||
let mut results = serde_json::Map::new();
|
||||
|
|
@ -108,6 +119,9 @@ fn run() -> Result<()> {
|
|||
results.insert("prover".into(), prover_kind.clone().into());
|
||||
results.insert("shard_budget".into(), fixture.plan.shard_budget.into());
|
||||
results.insert("consensus_budget".into(), fixture.plan.consensus.into());
|
||||
results.insert("daa_score".into(), block.env.daa_score.into());
|
||||
results.insert("fee_set".into(), fee_set.name().into());
|
||||
results.insert("fees_v1_activation_daa".into(), if block.fees.v1_activation_daa == u64::MAX { serde_json::Value::Null } else { block.fees.v1_activation_daa.into() });
|
||||
results.insert("sp1_crate_version".into(), "6.8.1".into());
|
||||
results.insert("sp1_circuit_version".into(), sp1_sdk::SP1_CIRCUIT_VERSION.into());
|
||||
|
||||
|
|
@ -531,3 +545,110 @@ fn finish(results: serde_json::Map<String, serde_json::Value>, out_path: Option<
|
|||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Fixtures on both sides of the fee switch (5 October 2026, `fees_v1_activation_daa`): one pinned guest, two
|
||||
/// tables. The prototype fixtures carry no `fees` field (the devnet schedule, prototype, never); the v1 fixtures
|
||||
/// were cut from a simnet run whose override file set the switch at DAA score 800, a prototype block below it and
|
||||
/// two v1 blocks above it from ONE export, replayed from genesis across the switch (the exporter's state-root check
|
||||
/// on every segment is what shows the port's schedule is the node's on both sides).
|
||||
#[cfg(test)]
|
||||
mod fee_switch_tests {
|
||||
use igneum_prove_core::config::{FeeParams, FeeSchedule};
|
||||
use igneum_prove_core::shard::{build_shards, shard_statement};
|
||||
use igneum_prove_core::Fixture;
|
||||
|
||||
fn load(name: &str) -> Fixture {
|
||||
let path = format!("{}/../../fixtures/{name}", env!("CARGO_MANIFEST_DIR"));
|
||||
serde_json::from_str(&std::fs::read_to_string(&path).unwrap_or_else(|e| panic!("{path}: {e}"))).unwrap()
|
||||
}
|
||||
|
||||
/// The native run of a fixture reproduces its plan and its expected values under its own schedule.
|
||||
fn native_matches(f: &Fixture) {
|
||||
let prover = alloy_primitives::Address::from_slice(&[0x19; 20]);
|
||||
let (outcome, pre_root, shards) = build_shards(&f.block, f.plan.shard_budget, prover);
|
||||
assert_eq!(pre_root, f.expected.pre_state_root);
|
||||
assert_eq!(outcome.state_root, f.expected.post_state_root);
|
||||
assert_eq!(outcome.state_root, f.expected.node_state_root, "the node's root");
|
||||
assert_eq!(outcome.pgas_used, f.expected.pgas_used);
|
||||
assert_eq!(shards.len(), f.plan.shards.len());
|
||||
for (s, x) in shards.iter().zip(&f.plan.shards) {
|
||||
assert_eq!((s.output.pre_root, s.output.post_root, s.output.pgas_used, s.output.gas_used), (x.pre_root, x.post_root, x.pgas_used, x.gas_used), "shard {}", x.index);
|
||||
assert_eq!(s.output.to_bytes().len(), 328, "the statement layout is unchanged");
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn a_fixture_without_fees_is_the_prototype_side() {
|
||||
let f = load("block-338-shard1.json");
|
||||
assert_eq!(f.block.fees, FeeSchedule::DEVNET);
|
||||
assert_eq!(f.block.env.daa_score, 0);
|
||||
let set = f.block.fees.at(f.block.env.daa_score);
|
||||
assert_eq!(set, FeeParams::PROTOTYPE);
|
||||
assert_eq!(f.plan.shard_budget, 7_500_000);
|
||||
assert!(f.plan.consensus);
|
||||
native_matches(&f);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn the_prototype_block_below_the_switch() {
|
||||
let f = load("fees-switch-prototype.json");
|
||||
assert_eq!(f.block.fees.v1_activation_daa, 800);
|
||||
assert!(f.block.env.daa_score < 800, "daa {}", f.block.env.daa_score);
|
||||
assert_eq!(f.block.fees.at(f.block.env.daa_score), FeeParams::PROTOTYPE);
|
||||
assert_eq!(f.plan.shard_budget, 7_500_000);
|
||||
assert_eq!(f.block.env.base_fee_exec, 1_000_000_000, "the prototype floor");
|
||||
native_matches(&f);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn the_v1_blocks_at_and_above_the_switch() {
|
||||
for (name, shards) in [("fees-v1-shards2.json", 2usize), ("fees-v1-shards3.json", 3)] {
|
||||
let f = load(name);
|
||||
assert_eq!(f.block.fees.v1_activation_daa, 800);
|
||||
assert!(f.block.env.daa_score >= 800, "{name}: daa {}", f.block.env.daa_score);
|
||||
assert_eq!(f.block.fees.at(f.block.env.daa_score), FeeParams::CALIBRATED_V1);
|
||||
assert_eq!(f.plan.shard_budget, 30_000, "{name}");
|
||||
assert!(f.plan.consensus);
|
||||
assert_eq!(f.plan.shards.len(), shards, "{name}");
|
||||
assert_eq!(f.block.env.base_fee_exec, 100_000_000_000, "{name}: the v1 execution floor");
|
||||
assert_eq!(f.block.env.base_fee_proving, 10_000_000_000_000, "{name}: the v1 proving floor");
|
||||
// every executed transaction carries the v1 intrinsic (300) and no plain transfer costs more
|
||||
let txs: usize = f.block.blocks.iter().map(|b| b.txs.len()).sum();
|
||||
assert!(f.expected.pgas_used >= 300 * txs as u64, "{name}: pgas {} for {txs} transactions", f.expected.pgas_used);
|
||||
native_matches(&f);
|
||||
}
|
||||
}
|
||||
|
||||
/// The same shard input under the other table gives another statement: the native veto is what pins the
|
||||
/// schedule a prover claims (the statement layout does not carry it).
|
||||
#[test]
|
||||
fn moving_the_switch_changes_the_statement() {
|
||||
let f = load("fees-v1-shards2.json");
|
||||
let prover = alloy_primitives::Address::from_slice(&[0x19; 20]);
|
||||
let (_, _, shards) = build_shards(&f.block, f.plan.shard_budget, prover);
|
||||
let mut input = shards[0].input.clone();
|
||||
let v1 = shard_statement(&input);
|
||||
assert_eq!(v1.to_bytes(), shards[0].output.to_bytes());
|
||||
// the switch moved past this block: the prototype table meters the same transactions with the intrinsic
|
||||
// 200 but a modexp entry 100x v1's (1,000 + 10 per byte against 10 + 1 per 10 bytes), so this modexp shard
|
||||
// costs MORE under the prototype (28,228 against 22,172 pgas on fees-v1-shards2): another pgas total,
|
||||
// another statement either way
|
||||
input.fees = FeeSchedule { base: FeeParams::PROTOTYPE, v1_activation_daa: u64::MAX };
|
||||
let proto = shard_statement(&input);
|
||||
assert_ne!(proto.pgas_used, v1.pgas_used, "prototype {} vs v1 {}", proto.pgas_used, v1.pgas_used);
|
||||
assert!(proto.pgas_used > v1.pgas_used, "the prototype modexp entry is the larger one: prototype {} vs v1 {}", proto.pgas_used, v1.pgas_used);
|
||||
assert_ne!(proto.to_bytes(), v1.to_bytes());
|
||||
// and the other way on the prototype fixture: the switch at 0 makes it v1
|
||||
let p = load("fees-switch-prototype.json");
|
||||
let (_, _, pshards) = build_shards(&p.block, p.plan.shard_budget, prover);
|
||||
let mut pin = pshards[0].input.clone();
|
||||
let before = shard_statement(&pin);
|
||||
pin.fees = FeeSchedule { base: FeeParams::PROTOTYPE, v1_activation_daa: 0 };
|
||||
let after = shard_statement(&pin);
|
||||
// under v1 the floors rise to 100 gwei, above these transactions' fee cap, so they skip: another pgas
|
||||
// total (the v1 intrinsic per skipped copy), another post-root, another statement
|
||||
assert_ne!(after.pgas_used, before.pgas_used);
|
||||
assert_ne!(after.post_root, before.post_root, "the v1 floors change what runs and what is burned, so the post-root moves");
|
||||
assert_ne!(after.to_bytes(), before.to_bytes());
|
||||
}
|
||||
}
|
||||
|
|
|
|||
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,16 @@
|
|||
}
|
||||
],
|
||||
"log": [
|
||||
{
|
||||
"date": "2026-10-05",
|
||||
"text": "Live devnet: real transactions, the first non-empty shard proven and paid, and the exporter's block structure fixed",
|
||||
"short": "Live devnet: real transactions, the first non-empty shard proven and…"
|
||||
},
|
||||
{
|
||||
"date": "2026-10-05",
|
||||
"text": "The prover carries both fee tables and the height switch: one pinned guest on either side of DAA 210,000",
|
||||
"short": "The prover carries both fee tables and the height switch"
|
||||
},
|
||||
{
|
||||
"date": "2026-10-05",
|
||||
"text": "The program id split: why the Apple M5 Max rejected PC 2's proofs, and the verifier at 114 s",
|
||||
|
|
@ -222,33 +232,23 @@
|
|||
},
|
||||
{
|
||||
"date": "2026-10-03",
|
||||
"text": "RTX 5090 first run",
|
||||
"short": "RTX 5090 first run"
|
||||
"text": "RTX 5090, memory-hard dataset",
|
||||
"short": "RTX 5090 on the memory-hard dataset"
|
||||
},
|
||||
{
|
||||
"date": "2026-10-03",
|
||||
"text": "AMD gfx1036 , AMD OpenCL 2.1 driver 3652.0",
|
||||
"short": "AMD integrated GPU runs the hash through OpenCL"
|
||||
"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"
|
||||
"text": "RTX 5090 through NVIDIA OpenCL",
|
||||
"short": "RTX 5090 through NVIDIA OpenCL"
|
||||
},
|
||||
{
|
||||
"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": "Execution layer devnet v3: revm over the selected chain, 3-node simnet, viem smoke test",
|
||||
"short": "EVM execution layer: identical state on three nodes"
|
||||
"text": "Igneum-node devnet v0: 3-node igneum-devnet at 1 BPS with the 80/20 coinbase and vote_key_hash",
|
||||
"short": "Devnet v0: three nodes at one block per second"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -218,6 +218,7 @@ main{padding-bottom:var(--sec)}
|
|||
<div class="eyebrow">devnet v0</div>
|
||||
<h1>Live devnet</h1>
|
||||
<p>A node is read every two seconds. Every block below is real: its parents, its miner, whether it sits on the selected chain, and whether it is a locked checkpoint. A checkpoint locks when the finality rule's quorum signs it. Once the proving layer is activated, every chain block's shards show as they are planned, proven and paid.</p>
|
||||
<p>Fees: the devnet meters with its prototype table until DAA score 210,000; from there the adopted table applies (300 pgas per transaction, 30,000-pgas shards, floors of 100 gwei per gas and 10,000 gwei per pgas) and the provers' program carries both.</p>
|
||||
</div>
|
||||
|
||||
<div class="strip" aria-live="polite">
|
||||
|
|
|
|||
1
tools/prove-fixtures/.gitignore
vendored
1
tools/prove-fixtures/.gitignore
vendored
|
|
@ -1 +1,2 @@
|
|||
node_modules/
|
||||
seq*.json
|
||||
|
|
|
|||
|
|
@ -1,47 +1,40 @@
|
|||
{
|
||||
"chainId": 4463,
|
||||
"S_p": 7500000,
|
||||
"S_p": 30000,
|
||||
"calibration": [
|
||||
{
|
||||
"n": 100,
|
||||
"pgas": 354375,
|
||||
"pgas": 31675,
|
||||
"gas": 104462
|
||||
},
|
||||
{
|
||||
"n": 400,
|
||||
"pgas": 1386075,
|
||||
"gas": 263774
|
||||
"n": 200,
|
||||
"pgas": 52775,
|
||||
"gas": 157562
|
||||
}
|
||||
],
|
||||
"perIter": 3439,
|
||||
"fixed": 10475,
|
||||
"iters": 651,
|
||||
"bombAddr": "0xb4fe09ff2fc5f44fea043e2e410f9ccec1dce9a8",
|
||||
"counterAddr": "0x9424b9e3c5e35893e8094209b2e7a26d4ea93e48",
|
||||
"perIter": 211,
|
||||
"fixed": 10575,
|
||||
"iters": 1,
|
||||
"bombAddr": "0xe821a70ad4350286dcfaf7ad516af91d73a7a049",
|
||||
"counterAddr": "0x8cc91dca2219f0564b3408b61ca64faafd3c020d",
|
||||
"blocks": {
|
||||
"1": {
|
||||
"block": 338,
|
||||
"block": 351,
|
||||
"txs": 11,
|
||||
"pgas": 6751568,
|
||||
"gas": 1390773,
|
||||
"segmentPgas": 6751568,
|
||||
"segmentGas": 1390773
|
||||
"pgas": 36934,
|
||||
"gas": 355287,
|
||||
"segmentPgas": 36934,
|
||||
"segmentGas": 355287
|
||||
},
|
||||
"2": {
|
||||
"block": 341,
|
||||
"block": 354,
|
||||
"txs": 14,
|
||||
"pgas": 13499360,
|
||||
"gas": 2564838,
|
||||
"segmentPgas": 13499360,
|
||||
"segmentGas": 2564838
|
||||
},
|
||||
"4": {
|
||||
"block": 344,
|
||||
"txs": 20,
|
||||
"pgas": 26994944,
|
||||
"gas": 4947168,
|
||||
"segmentPgas": 26994944,
|
||||
"segmentGas": 4947168
|
||||
"pgas": 69292,
|
||||
"gas": 493866,
|
||||
"segmentPgas": 69292,
|
||||
"segmentGas": 493866
|
||||
}
|
||||
}
|
||||
},
|
||||
"feesV1ActivationDaa": 800
|
||||
}
|
||||
|
|
@ -2,7 +2,12 @@
|
|||
// whose proving gas fills one, two and four shards at S_p = B_p / 4 (igneum-prove-core config), each a burst of
|
||||
// equal-sized modexp calls (PgasBomb, tools/exec-attacks) plus transfers and Counter increments from many
|
||||
// senders, landed in ONE chain block so the planner's cut is the block's. Then `igneum_exportSegments` is
|
||||
// written to seq.json for igneum-prove-export. Usage: node gen.mjs [--shards 1,2,4]
|
||||
// written to seq.json for igneum-prove-export. Usage: node gen.mjs [--shards 1,2,4] [--out seq.json]
|
||||
// S_p comes from the node (`igneum_getBudgets`.provingGasLimit / 4), so the same run sizes its bursts for the
|
||||
// prototype table (7.5 M pgas) or calibrated v1 (30,000 pgas), whichever the node meters at its tip
|
||||
// (`fees_v1_activation_daa`, 5 October 2026). The dump gets each segment's `daaScore` (eth_getBlockByNumber)
|
||||
// and the top-level `feesV1ActivationDaa` from FEES_V1_ACTIVATION_DAA (the value in the node's override file;
|
||||
// unset = never), which the exporter reads to replay the switch.
|
||||
import { createPublicClient, http, parseEther, formatEther, encodeFunctionData, keccak256, toHex, stringToHex } from 'viem';
|
||||
import { privateKeyToAccount } from 'viem/accounts';
|
||||
import { readFileSync, writeFileSync } from 'node:fs';
|
||||
|
|
@ -21,7 +26,8 @@ const payee = privateKeyToAccount('0xea6c44ac03bff858b476bba40716402b03e41b8e97e
|
|||
const REGISTRY = '0x0000000000000000000000000000000000000210';
|
||||
const bomb = JSON.parse(readFileSync(new URL('../exec-attacks/contracts/PgasBomb.json', import.meta.url)));
|
||||
const counter = JSON.parse(readFileSync(new URL('../evm-smoke/counter.json', import.meta.url)));
|
||||
const S_P = 30_000_000 / 4;
|
||||
let S_P = 30_000_000 / 4; // replaced by the node's budget at start (step 1)
|
||||
const OUT = process.argv.includes('--out') ? process.argv[process.argv.indexOf('--out') + 1] : 'seq.json';
|
||||
const wanted = (process.argv.includes('--shards') ? process.argv[process.argv.indexOf('--shards') + 1] : '1,2,4').split(',').map(Number);
|
||||
|
||||
const nonces = new Map();
|
||||
|
|
@ -31,8 +37,11 @@ async function nonceOf(acc) {
|
|||
nonces.set(acc.address, n + 1);
|
||||
return n;
|
||||
}
|
||||
// The fee cap: 20 gwei, or three times the node's base fee when that is higher (under calibrated v1 the floor is 100 gwei,
|
||||
// and a transaction capped below the base fee is skipped). Set from igneum_getBudgets at start.
|
||||
let MAX_FEE_BASE = 20_000_000_000n;
|
||||
async function sign(acc, { to, value = 0n, data = '0x', gas = 21000n, tip = 1_000_000_000n }) {
|
||||
return acc.signTransaction({ type: 'eip1559', chainId: CHAIN_ID, nonce: await nonceOf(acc), to: to ?? undefined, value, data, gas, maxFeePerGas: 20_000_000_000n + tip, maxPriorityFeePerGas: tip });
|
||||
return acc.signTransaction({ type: 'eip1559', chainId: CHAIN_ID, nonce: await nonceOf(acc), to: to ?? undefined, value, data, gas, maxFeePerGas: MAX_FEE_BASE + tip, maxPriorityFeePerGas: tip });
|
||||
}
|
||||
async function send(raw) {
|
||||
try { return await rpc('eth_sendRawTransaction', [raw]); } catch (e) { throw new Error(`send failed: ${e.details || e.shortMessage || e.message}`); }
|
||||
|
|
@ -60,7 +69,7 @@ async function main() {
|
|||
for (const a of accounts) if (BigInt(await rpc('eth_getBalance', [a.address, 'latest'])) < parseEther('6')) need.push(a);
|
||||
const wanted_wei = parseEther('12') * BigInt(need.length) + parseEther('1');
|
||||
let bal = 0n;
|
||||
for (let i = 0; i < 300; i++) {
|
||||
for (let i = 0; i < 900; i++) { // up to 15 min: a private simnet pays the miner a few IGN a block
|
||||
bal = BigInt(await rpc('eth_getBalance', [miner.address, 'latest']));
|
||||
if (bal >= wanted_wei) break;
|
||||
await sleep(1000);
|
||||
|
|
@ -69,6 +78,10 @@ async function main() {
|
|||
if (bal < wanted_wei) throw new Error(`the miner has not earned ${formatEther(wanted_wei)} IGN yet`);
|
||||
const budgets = await rpc('igneum_getBudgets');
|
||||
log('budgets', JSON.stringify(budgets));
|
||||
S_P = Number(BigInt(budgets.provingGasLimit)) / 4;
|
||||
const baseFee = BigInt(budgets.baseFeePerGas ?? '0x0');
|
||||
if (baseFee * 3n > MAX_FEE_BASE) MAX_FEE_BASE = baseFee * 3n; // a 21,000-gas transfer at the v1 floors costs 0.0051 IGN: the signed budget (gas x cap) must cover it
|
||||
log('S_p from the node', S_P, 'pgas (B_p / 4); base fee', baseFee.toString(), 'wei, fee cap', MAX_FEE_BASE.toString(), 'wei plus the tip');
|
||||
|
||||
// 2. Fund the accounts. The mempool queues at most 16 nonces ahead per sender, so in rounds of 12.
|
||||
for (let i = 0; i < need.length; i += 12) {
|
||||
|
|
@ -87,20 +100,26 @@ async function main() {
|
|||
log('PgasBomb at', bombAddr, 'Counter at', counterAddr);
|
||||
|
||||
// 4. Calibrate pgas per modexp iteration from two sizes.
|
||||
// Under calibrated v1 the proving charge (pgas x 10,000 gwei) dominates the signed budget (gas x fee cap), so
|
||||
// the second point stays small and every gas limit below adds what covers that charge (design 4.1).
|
||||
const provingBaseFee = BigInt(budgets.provingBaseFeePerGas ?? '0x3b9aca00');
|
||||
const coverPgas = (pgas) => Number((BigInt(Math.ceil(pgas)) * provingBaseFee * 13n / 10n) / (MAX_FEE_BASE + 1_000_000_000n)) + 1;
|
||||
const cal = [];
|
||||
for (const n of [100, 400]) {
|
||||
const h = await send(await sign(accounts[2], { to: bombAddr, data: encodeFunctionData({ abi: bomb.abi, functionName: 'modexpLoop', args: [BigInt(n)] }), gas: 2_000_000n }));
|
||||
for (const n of [100, S_P < 1_000_000 ? 200 : 400]) {
|
||||
const h = await send(await sign(accounts[2], { to: bombAddr, data: encodeFunctionData({ abi: bomb.abi, functionName: 'modexpLoop', args: [BigInt(n)] }), gas: 2_000_000n + BigInt(coverPgas(S_P)) }));
|
||||
const r = (await waitReceipts([h])).get(h);
|
||||
cal.push({ n, pgas: pgasOf(r), gas: Number(BigInt(r.gasUsed)) });
|
||||
}
|
||||
const perIter = (cal[1].pgas - cal[0].pgas) / 300;
|
||||
const span = cal[1].n - cal[0].n;
|
||||
const perIter = (cal[1].pgas - cal[0].pgas) / span;
|
||||
const fixed = cal[0].pgas - 100 * perIter;
|
||||
const gasPerIter = (cal[1].gas - cal[0].gas) / 300;
|
||||
const gasPerIter = (cal[1].gas - cal[0].gas) / span;
|
||||
log('calibration', JSON.stringify(cal), 'pgas per iteration', perIter.toFixed(1), 'fixed', fixed.toFixed(0), 'gas per iteration', gasPerIter.toFixed(1));
|
||||
|
||||
// 5. One block per shard count: 3 bombs of 0.3 S_p per shard (any order packs three per shard), plus
|
||||
// transfers and Counter increments. Sent as one burst right after a new block, so one template takes them.
|
||||
const perBomb = 0.3 * S_P;
|
||||
// Three bombs per shard, leaving room for the eight small transactions (300 pgas each under v1).
|
||||
const perBomb = (S_P - 3_000) / 3;
|
||||
const iters = Math.max(1, Math.floor((perBomb - fixed) / perIter));
|
||||
const results = { chainId: CHAIN_ID, S_p: S_P, calibration: cal, perIter, fixed, iters, bombAddr, counterAddr, blocks: {} };
|
||||
for (const shards of wanted) {
|
||||
|
|
@ -112,11 +131,11 @@ async function main() {
|
|||
// signed budget gas_limit x max_fee must cover the pgas charge too (design 4.1), hence the wide limit.
|
||||
for (let i = 0; i < nBombs; i++) {
|
||||
const acc = accounts[3 + (i % 20)];
|
||||
raws.push(await sign(acc, { to: bombAddr, data: encodeFunctionData({ abi: bomb.abi, functionName: 'modexpLoop', args: [BigInt(iters)] }), gas: BigInt(Math.ceil(iters * gasPerIter * 1.3 + 100_000 + perBomb / 10)), tip: 2_000_000_000n - BigInt(i) * 10_000_000n }));
|
||||
raws.push(await sign(acc, { to: bombAddr, data: encodeFunctionData({ abi: bomb.abi, functionName: 'modexpLoop', args: [BigInt(iters)] }), gas: BigInt(Math.ceil(iters * gasPerIter * 1.3 + 100_000 + perBomb / 10) + coverPgas(perBomb)), tip: 2_000_000_000n - BigInt(i) * 10_000_000n }));
|
||||
}
|
||||
// Transfers between accounts and Counter increments: small pgas, real state traffic.
|
||||
for (let i = 0; i < 6; i++) raws.push(await sign(accounts[i], { to: accounts[23 - i].address, value: parseEther('0.01'), tip: 500_000_000n }));
|
||||
for (let i = 0; i < 2; i++) raws.push(await sign(accounts[20 + i], { to: counterAddr, data: encodeFunctionData({ abi: counter.abi, functionName: 'increment', args: [BigInt(i + 1)] }), gas: 120_000n, tip: 400_000_000n }));
|
||||
for (let i = 0; i < 2; i++) raws.push(await sign(accounts[20 + i], { to: counterAddr, data: encodeFunctionData({ abi: counter.abi, functionName: 'increment', args: [BigInt(i + 1)] }), gas: 120_000n + BigInt(coverPgas(2_000)), tip: 400_000_000n }));
|
||||
// Wait for the next block, then burst.
|
||||
const b0 = await blockNumber();
|
||||
while ((await blockNumber()) === b0) await sleep(50);
|
||||
|
|
@ -146,9 +165,16 @@ async function main() {
|
|||
await sleep(3000);
|
||||
const tip = await blockNumber();
|
||||
const exported = await rpc('igneum_exportSegments', ['0x0', toHex(tip)]);
|
||||
writeFileSync(new URL('./seq.json', import.meta.url), JSON.stringify(exported));
|
||||
// The fee schedule the exporter replays: each segment's DAA score and the node's switch.
|
||||
for (const seg of exported.segments) {
|
||||
const b = await rpc('eth_getBlockByNumber', [toHex(seg.number), false]);
|
||||
seg.daaScore = Number(BigInt(b.igneum?.daaScore ?? '0x0'));
|
||||
}
|
||||
exported.feesV1ActivationDaa = process.env.FEES_V1_ACTIVATION_DAA ? Number(process.env.FEES_V1_ACTIVATION_DAA) : null;
|
||||
results.feesV1ActivationDaa = exported.feesV1ActivationDaa;
|
||||
writeFileSync(new URL(`./${OUT}`, import.meta.url), JSON.stringify(exported));
|
||||
writeFileSync(new URL('./gen-results.json', import.meta.url), JSON.stringify(results, null, 1));
|
||||
log('wrote seq.json with', exported.segments.length, 'segments; blocks:', JSON.stringify(results.blocks));
|
||||
log('wrote', OUT, 'with', exported.segments.length, 'segments (daaScore', exported.segments[0].daaScore, 'to', exported.segments.at(-1).daaScore, '; switch', exported.feesV1ActivationDaa, '); blocks:', JSON.stringify(results.blocks));
|
||||
}
|
||||
|
||||
function encodeDeploy(art, args) {
|
||||
|
|
|
|||
|
|
@ -5,7 +5,9 @@
|
|||
#
|
||||
# ./net.sh start ./net.sh stop
|
||||
#
|
||||
# BIN: the devnet-v4 worktree's release binaries by default (IGNEUM_BIN overrides).
|
||||
# BIN: the devnet-v4 worktree's release binaries by default (IGNEUM_BIN overrides). IGNEUM_OVERRIDE: an override
|
||||
# params file for the node (the simnet accepts one), e.g. '{"fees_v1_activation_daa": 60}' written to a file, to
|
||||
# cut fixtures on both sides of the fee switch (5 October 2026).
|
||||
set -u
|
||||
ROOT="$(cd "$(dirname "$0")/../.." && pwd)"
|
||||
BIN="${IGNEUM_BIN:-$ROOT/vendor/igneum-node-v4/target/release}"
|
||||
|
|
@ -24,8 +26,9 @@ else MINER_ID="--vote-key-hash 0x000000000000000000000000$MINER_EVM"; fi
|
|||
case "${1:-}" in
|
||||
start)
|
||||
rm -rf "$DATA"; mkdir -p "$DATA/n1"; : > "$PIDS"
|
||||
OVERRIDE_ARG=""; [ -n "${IGNEUM_OVERRIDE:-}" ] && OVERRIDE_ARG="--override-params-file=$IGNEUM_OVERRIDE"
|
||||
"$BIN/igneumd" --simnet --utxoindex --loglevel=info --disable-upnp --enable-unsynced-mining --unsaferpc \
|
||||
--appdir="$DATA/n1" --rpclisten=0.0.0.0:29300 --listen=0.0.0.0:29301 --evm-rpclisten=127.0.0.1:29390 \
|
||||
--appdir="$DATA/n1" --rpclisten=0.0.0.0:29300 --listen=0.0.0.0:29301 --evm-rpclisten=127.0.0.1:29390 $OVERRIDE_ARG \
|
||||
> "$DATA/n1/node.log" 2>&1 &
|
||||
echo $! >> "$PIDS"
|
||||
t=0; until grep -q "GRPC Server starting on" "$DATA/n1/node.log" 2>/dev/null || [ $t -ge 60 ]; do sleep 1; t=$((t+1)); done; sleep 2
|
||||
|
|
|
|||
Loading…
Reference in a new issue