Proving fixtures: blocks of one, two and four shards at S_p from a private simnet, plus the v1 cut of the v0 blocks

tools/prove-fixtures: a one-node simnet on ports 29300+ and a generator that lands bursts of equal-sized modexp calls, transfers and Counter increments in one chain block (blocks 338, 341, 344: 0.90, 1.80 and 3.60 S_p). block-56-transfers-3shards is a test cut at 200 pgas for the Mac CPU multi-shard check.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
igneum-labs 2026-10-04 10:05:05 +00:00
parent f71af23dcb
commit b64a31c77f
10 changed files with 5092 additions and 4 deletions

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,389 @@
{
"format": "igneum-prove-fixture-v1",
"source": "tools/evm-smoke/seq.json (3 October 2026 simnet export), block 56 cut at a TEST budget of 200 pgas: three shards of one transfer each, for the Mac CPU multi-shard check",
"block": {
"chain_id": 4463,
"env": {
"number": 56,
"hash": "0xc47bacc89a3318140e66912717b958057bdbe72c337162a0667a0bbf44670a22",
"parent_hash": "0x2bcabda995747c4221658d177995a64c94bc92202b02b8ef83b8bfd9cdb5709a",
"timestamp": 1791064849,
"miner": "0x70997970c51812dc3a010c7d01b50e0d17dc79c8",
"prevrandao": "0x17919bfdc85b8b923bd674ac408b5ed0644e22fe2c7a8e19d9fc2197388270ee",
"base_fee_exec": 1000000000,
"base_fee_proving": 1000000000
},
"block_hashes": [
[
0,
"0x3c19f19d3d77bfc2f367482eb7f28aa907ca5d31470c7d7722a68f44436236d5"
],
[
1,
"0x4a86d6afa55fa5a073e43a5f5d3ac423edcfa6f7815690eb23f9a090b20395bc"
],
[
2,
"0x07b68c40a8a8eb6826442d9cca7dbd08882a0c02130ea6ee7eaf7f729e081ea3"
],
[
3,
"0xf15ad0bcceb161e14082f4163c44a8134dd587f192c8dd1737db00c6db24fa1b"
],
[
4,
"0x22212b7c5792ff6743f48caa1ba1f0587772723cb7ae1572485bb73e42242c16"
],
[
5,
"0x32968867f32f5ad1580f834fbad5cdc07ab96df4d3346b4251893a5d3bb719b6"
],
[
6,
"0xa1548b817ef1c597ad91064886d3a00b86ec5aa57889d085881329d584ed3214"
],
[
7,
"0x52f35b7d71efaa3181660b0e0689e19be5996dfd0b52bba0518dc8ab099be968"
],
[
8,
"0xcb602a65d6788ea471038522506dfbec15775183d0fb552f7d0ab03ea95315ef"
],
[
9,
"0xa7a0015c122f749591ae5c4b6fae8a035cba2e3c0f4500d6c915a61f4f534c74"
],
[
10,
"0x3efdfcdc9fac9b0df2eb6fadae9deaada5abbcc3a2436164b3b061743f4c2aa5"
],
[
11,
"0x49c9f846adc3f61685d0075efa3d05aa29fcb2dad02d9e6f415508fa2adc23f1"
],
[
12,
"0xe084f75979bb4a34958883d0b599262c7719669119c88b3ce015500473ecac91"
],
[
13,
"0x9653df5f568099056e6d33bb79364dcb4c9760383b5f4f208bb9a14db1c156c4"
],
[
14,
"0xf65af06e2edf1ac8443992bd5affbf5f244a3b2ca2b572b6a7bea5ae1b1b9e60"
],
[
15,
"0xa7b1e86b1a99ab38f127637a4fdaf25ee1c18ceb294ef136f4bbf3c53321e29a"
],
[
16,
"0xac94a12363cf3e35e43c8a7aed2982c0f4445328c3349aa5cab232ad20f24600"
],
[
17,
"0xd97973cba8dbac8b5396738bef29e467459311305de6236af3a601916bf1a299"
],
[
18,
"0x345a0f4a3ca21c93f5a6b3bb951f189952a2b784ecebad164e1160ab376f1527"
],
[
19,
"0x1907dccf859a86a20eb9513067dfe4c1177b2ce642d82fe9a5242d0e64203fa9"
],
[
20,
"0x99bdf35872ec2463997ecbb94bc6cecf680988ad699b39b5c1649ffa266f4f15"
],
[
21,
"0xc25536e978e34a83736ef5e87a5cf062500a51fde4df9100d97e04e304f91654"
],
[
22,
"0x20359d647025b3ea156c71cf0007d5a39f23c5068f0ee6435b1cb6ca335181bb"
],
[
23,
"0xdc00a977d7ab0de248df07e386a08a3f0aa783d8fca5cff812a9f6c0afa84b61"
],
[
24,
"0x0387da8a2db5a44b05b1d162b2f2e25b6a060c285e1cb0492786a4110563442a"
],
[
25,
"0xce9c2c622ef827835d61481601d6c7474049b1edf4fd50ac37dca99f3e5d3724"
],
[
26,
"0x91be3e06f9c1f04fd204b0beb565cfab959ad68e8a07bc13d441cd20857a89aa"
],
[
27,
"0xa594a87329e8851172922cbe32a66090a65643d05f288a2d5e6e05e7ed1b5ffe"
],
[
28,
"0x438e92d3336e081c0267e25cf6d43adaf4d75e2f20774cb27840e3e2962e25e8"
],
[
29,
"0xac8d447d138ea8f010fc962da698356659f6c441a5688e32701960e8b16a9cb0"
],
[
30,
"0xeb78fbb06f42d7f8d759175d047b0dc293a56a9222028b2643bfb9ffc91fe3fd"
],
[
31,
"0x2016f52e3826d3d5907d42b6d649c6dd3440d7411f457c2b116b42e615f3bbf2"
],
[
32,
"0x7af660fa94b6e49b36a4d269180257825ba18f48e7e3c30cafb416bc9ce3ab12"
],
[
33,
"0xba45eec95775faf276121cfe8d3a692669a8bbfd39150938ea9511e90cce8b80"
],
[
34,
"0x1aaf31c0fe17670291225b49f0de8fae2a98f36eadafac443727bd106f77391b"
],
[
35,
"0x6fa7a464f1db6e720e134916cdaff8ec67bcd60a2a82d1e2aa2f534a07cc73a4"
],
[
36,
"0x0cb1b93c07ed8bf63bf31d123693c6dbfaf064277d66c254c2939c1e2921d8b8"
],
[
37,
"0x667183be90efad8b5bff455105274d7658d7c9c67baf4ab79520fcd62e33f27e"
],
[
38,
"0x99443a3696a07ee284b2adc97f28ba26b9883f5e4d50f71aa34f63ded0aa5758"
],
[
39,
"0xc89aabcb55b61130db52f88d5af03695c36d42ce5f5b1952c0c2a7f3142199ce"
],
[
40,
"0x63810d97fe61474ba493d0110349c1ebd39b0d61f8c19c6e65e889dffbe1d4d5"
],
[
41,
"0xe64882be5742249b50f8c2e119d6accb5ab9fe0a154978adadc14c20b1caba6e"
],
[
42,
"0xba4d1aed4f8f7a8e40ed4b8b9cb9951d9f62649f878d5ec8f55995cdd2d0ec2d"
],
[
43,
"0x6dc5c802d8a7a93a97d0623a649bbc67e38555b7d5a0c377c9e17c9279b58de8"
],
[
44,
"0x4a27daba79ed1ab3b40a6779cbffeb3d67911757f84f4f88ff0bd27572e1f46a"
],
[
45,
"0x7ba691e30c75946d7cd64f1f01eb9f94b0008e36eba673c6451ad393718bcbab"
],
[
46,
"0x82386a81343d8dfde805e65467a7877402218706a1bcc1da51de39957e231246"
],
[
47,
"0x65280d664a84f064129bef2f8373b914e50a9217fd00b09c51cb5e0ef5f257b9"
],
[
48,
"0x63a0982dda5fa15ed9c80c605557074714623ec147d7df0a3bd7972c11064505"
],
[
49,
"0x28fbf32967958aa4cd52dc8566bc32c64ca82ef827bcd83c02b45c38497ec37a"
],
[
50,
"0xcf06be7d297655c02c6f4a80dfa4b456a9686e4646c9c69d8b3c9b7fe9e074fc"
],
[
51,
"0x112543d5da2a348f6d626eeb7d2fa45476908d413f28feb64596f4587ca6e5dd"
],
[
52,
"0x3eb5dd755cdab699c0c38e325503e0b676c200237ab2a7cbe938cb12375db7dc"
],
[
53,
"0x8c7d74fa5d4cf80d23ba0376dafe5970bd30fdc5bfc278374b265aba4f15517d"
],
[
54,
"0x17eabdf92dfb31db69542e9895cfe59091445b4dbf456a9c87f8a27efa4efac0"
],
[
55,
"0x2bcabda995747c4221658d177995a64c94bc92202b02b8ef83b8bfd9cdb5709a"
]
],
"rewards": [
[
"0x062c1140fbe5b04868ddd71c2993895d9381eec0",
"0x2331846aef26d800"
],
[
"0x70997970c51812dc3a010c7d01b50e0d17dc79c8",
"0x2331846aef26d800"
],
[
"0x70997970c51812dc3a010c7d01b50e0d17dc79c8",
"0x2331846aef26d800"
]
],
"proving_pool_credit": "0x1a65234cb54b4c00",
"blocks": [
{
"miner": "0x70997970c51812dc3a010c7d01b50e0d17dc79c8",
"blue": true,
"txs": [
"0x02f87482116f80843b9aca0084ee6b2800826324949965507d1a55bcc2695c58ba16fb37d819b0a4dc884563918244f4000080c080a00b405923e70a41d0838b38c1da30c365d1155108427959f6b5bde63267d8656aa05a55d368f8f8733b56e8a6249de42748eef8199affdf9bcf84d1fe4fd6d0286a",
"0x02f87482116f01843b9aca0084ee6b28008263249415d34aaf54267db7d7c367839aaf71a00a2c6a65884563918244f4000080c001a04e7d3f775d1ee2cf39ba90383fdfafcb420dedf6e50bb5a7e553ffc3b3213550a059d4a0f7875b5ced1f3418df3ba594aa4ad69bfa96ae672123f31a292adc8617",
"0x02f87482116f02843b9aca0084ee6b28008263249401d47ee52ebca6d0b0beac0f124acde471e0968a884563918244f4000080c080a04ee4d5c75e7066fe6825cfc51e4363a6c9b1391d9f6614751cb03e1b1346b840a03472a39140cb420fdb6136185d003154b5bc2aea956ba2cf4373d77ec14ad698"
]
}
],
"pre_state": [
{
"address": "0x0000000000000000000000000000000000000210",
"nonce": 1,
"balance": "0x0",
"code": "0x608060405234801561000f575f5ffd5b506004361061003f575f3560e01c8063aa67735414610043578063dea5c2e014610058578063fe7e05d51461009f575b5f5ffd5b6100566100513660046101e0565b6100ca565b005b610083610066366004610211565b6001600160a01b039081165f908152600160205260409020541690565b6040516001600160a01b03909116815260200160405180910390f35b6100836100ad366004610211565b6001600160a01b039081165f908152602081905260409020541690565b336001600160a01b03831614806100f957506001600160a01b038281165f908152600160205260409020541633145b6101635760405162461bcd60e51b815260206004820152603160248201527f446576656c6f70657252656769737472793a206e6f7420746865206163636f75604482015270373a1037b91034ba399031b932b0ba37b960791b606482015260840160405180910390fd5b6001600160a01b038281165f818152602081815260409182902080546001600160a01b031916948616948517905590513381527fa47563c41dab010f91a8ef9dc7ac2bcdfa0ef2af697e575048e71e6eec60dda3910160405180910390a35050565b80356001600160a01b03811681146101db575f5ffd5b919050565b5f5f604083850312156101f1575f5ffd5b6101fa836101c5565b9150610208602084016101c5565b90509250929050565b5f60208284031215610221575f5ffd5b61022a826101c5565b939250505056fea2646970667358221220cbf48f5aa6f911f83b3c2b09adf8c418f5da6fc530c3d5db9d4ba0be24c4bf5864736f6c63430008250033",
"storage": []
},
{
"address": "0x0000000000000000000000000000000000000220",
"nonce": 0,
"balance": "0x37878e392363d4000",
"code": "0x",
"storage": []
},
{
"address": "0x062c1140fbe5b04868ddd71c2993895d9381eec0",
"nonce": 0,
"balance": "0x4ac5a33ceab8a0800",
"code": "0x",
"storage": []
},
{
"address": "0x3c5f681b84cd6be1c07dd0c7c68701e9510f8359",
"nonce": 0,
"balance": "0x41f9f6c2a3e437000",
"code": "0x",
"storage": []
},
{
"address": "0x70997970c51812dc3a010c7d01b50e0d17dc79c8",
"nonce": 0,
"balance": "0x515e9f03438d0c800",
"code": "0x",
"storage": []
}
]
},
"plan": {
"shard_budget": 200,
"consensus": false,
"shards": [
{
"index": 0,
"tx_start": 0,
"tx_end": 1,
"over_budget": false,
"pre_root": "0xc9e0d33ba639d7144f8ffc6950ec21afb5933c88f61a1a1bdd6a957d5ca4025c",
"post_root": "0xd63a92a674e27bafc02b55388dab24e79a269d46a12663c06584c1ea97d3efbf",
"receipts_root": "0xf78dfb743fbd92ade140711c8bbc542b5e307f0ab7984eff35d751969fe57efa",
"link_in": "0x38046159e1bf364d16df7645adc5a18f254dd70ffab279ed30785b727b52a3d5",
"link_out": "0x73c5f1eb82c0ba6dd76d4887025a56a11bced056fe33854775d84cbecd1b4c94",
"gas_used": 21000,
"pgas_used": 200,
"executed": 1,
"skipped": 0,
"witness": [
4,
0,
5,
0,
4298
]
},
{
"index": 1,
"tx_start": 1,
"tx_end": 2,
"over_budget": false,
"pre_root": "0xd63a92a674e27bafc02b55388dab24e79a269d46a12663c06584c1ea97d3efbf",
"post_root": "0x929dfb9ab0dd152103ad36d112c63d77f2ebd8de701d3fd985c9a802f8d56f2a",
"receipts_root": "0x217a0db1c5c08d6caf281235d3a82f50e1562e705e952999afe9ff28a9493477",
"link_in": "0x73c5f1eb82c0ba6dd76d4887025a56a11bced056fe33854775d84cbecd1b4c94",
"link_out": "0x9f4aac60d43806816972635c0fbf25fd61c456789786ae5b10d8f12bd573cf46",
"gas_used": 21000,
"pgas_used": 200,
"executed": 1,
"skipped": 0,
"witness": [
2,
0,
1,
4,
3671
]
},
{
"index": 2,
"tx_start": 2,
"tx_end": 3,
"over_budget": false,
"pre_root": "0x929dfb9ab0dd152103ad36d112c63d77f2ebd8de701d3fd985c9a802f8d56f2a",
"post_root": "0x68cacfd393b00ead784a69b10d57a3e2dd57858029df107b529487a49f393b50",
"receipts_root": "0x1b3d74ad0d735d4fb25506867962805b18aaa255efad72c2250f7d32dd5902b5",
"link_in": "0x9f4aac60d43806816972635c0fbf25fd61c456789786ae5b10d8f12bd573cf46",
"link_out": "0x8def9d32e833c0f5496f335580916d2dd62a5712f45ab85b0982a049adfab94f",
"gas_used": 21000,
"pgas_used": 200,
"executed": 1,
"skipped": 0,
"witness": [
2,
0,
1,
5,
3720
]
}
]
},
"expected": {
"pre_state_root": "0xc9e0d33ba639d7144f8ffc6950ec21afb5933c88f61a1a1bdd6a957d5ca4025c",
"post_state_root": "0x68cacfd393b00ead784a69b10d57a3e2dd57858029df107b529487a49f393b50",
"receipts_root": "0x25e6b7af647c519a27cc13276a1e6abc46154b51414d174b072698df1f6c19df",
"tx_commitment": "0xfbae94c9c5a6c84aee5dd4df59d290f2786a0c38ecadb2e96254f1f9fc4e7b0e",
"gas_used": 63000,
"pgas_used": 600,
"executed": 3,
"skipped": 0,
"node_state_root": "0x68cacfd393b00ead784a69b10d57a3e2dd57858029df107b529487a49f393b50"
}
}

View file

@ -1,6 +1,6 @@
{
"format": "igneum-prove-fixture-v0",
"source": "tools/evm-smoke/seq.json, the igneum_exportSegments export of the 3-node simnet run of 3 October 2026 (execution-layer commit fb33069), replayed from genesis through igneum-prove-core; block 56 holds the three funding transfers",
"format": "igneum-prove-fixture-v1",
"source": "tools/evm-smoke/seq.json (3 October 2026 simnet export), block 56: the three funding transfers",
"block": {
"chain_id": 4463,
"env": {
@ -303,10 +303,39 @@
}
]
},
"plan": {
"shard_budget": 7500000,
"consensus": true,
"shards": [
{
"index": 0,
"tx_start": 0,
"tx_end": 3,
"over_budget": false,
"pre_root": "0xc9e0d33ba639d7144f8ffc6950ec21afb5933c88f61a1a1bdd6a957d5ca4025c",
"post_root": "0x68cacfd393b00ead784a69b10d57a3e2dd57858029df107b529487a49f393b50",
"receipts_root": "0x25e6b7af647c519a27cc13276a1e6abc46154b51414d174b072698df1f6c19df",
"link_in": "0x38046159e1bf364d16df7645adc5a18f254dd70ffab279ed30785b727b52a3d5",
"link_out": "0x8def9d32e833c0f5496f335580916d2dd62a5712f45ab85b0982a049adfab94f",
"gas_used": 63000,
"pgas_used": 600,
"executed": 3,
"skipped": 0,
"witness": [
6,
0,
5,
0,
4738
]
}
]
},
"expected": {
"pre_state_root": "0xc9e0d33ba639d7144f8ffc6950ec21afb5933c88f61a1a1bdd6a957d5ca4025c",
"post_state_root": "0x68cacfd393b00ead784a69b10d57a3e2dd57858029df107b529487a49f393b50",
"receipts_root": "0x25e6b7af647c519a27cc13276a1e6abc46154b51414d174b072698df1f6c19df",
"tx_commitment": "0xfbae94c9c5a6c84aee5dd4df59d290f2786a0c38ecadb2e96254f1f9fc4e7b0e",
"gas_used": 63000,
"pgas_used": 600,
"executed": 3,

View file

@ -1,6 +1,6 @@
{
"format": "igneum-prove-fixture-v0",
"source": "tools/evm-smoke/seq.json, the igneum_exportSegments export of the 3-node simnet run of 3 October 2026 (execution-layer commit fb33069), replayed from genesis through igneum-prove-core; block 78 holds the increment(5) call on the Counter contract",
"format": "igneum-prove-fixture-v1",
"source": "tools/evm-smoke/seq.json, the igneum_exportSegments export of the 3-node simnet run of 3 October 2026 (execution-layer commit fb33069), replayed from genesis through igneum-prove-core at b7fca5a0; block 78 holds the increment(5) call on the Counter contract",
"block": {
"chain_id": 4463,
"env": {
@ -430,10 +430,39 @@
}
]
},
"plan": {
"shard_budget": 7500000,
"consensus": true,
"shards": [
{
"index": 0,
"tx_start": 0,
"tx_end": 2,
"over_budget": false,
"pre_root": "0x4e1a7b269c47c71e358118eed382ac4664194b44e85b43dc4ccdc3869dab75bd",
"post_root": "0x5b18b3a58f6c1d21b22caad4a1dbd9ee8a6394a02db2220255e556a9d4f90878",
"receipts_root": "0x9efcc914e2358eb95f50b110aeb57ba17341cb89f831a4f0e322d6aeef2e8e9c",
"link_in": "0x38046159e1bf364d16df7645adc5a18f254dd70ffab279ed30785b727b52a3d5",
"link_out": "0xc4c3d444f20dc46d276d1e68e5c6d19da9577b3474fd7fcd8bb2cf36a41ed6f2",
"gas_used": 45354,
"pgas_used": 1488,
"executed": 1,
"skipped": 1,
"witness": [
6,
2,
10,
2,
8116
]
}
]
},
"expected": {
"pre_state_root": "0x4e1a7b269c47c71e358118eed382ac4664194b44e85b43dc4ccdc3869dab75bd",
"post_state_root": "0x5b18b3a58f6c1d21b22caad4a1dbd9ee8a6394a02db2220255e556a9d4f90878",
"receipts_root": "0x9efcc914e2358eb95f50b110aeb57ba17341cb89f831a4f0e322d6aeef2e8e9c",
"tx_commitment": "0x610f9af32c5a42c4674f071e3c24d5935d877e2830f611e130c132ce64aaef6c",
"gas_used": 45354,
"pgas_used": 1488,
"executed": 1,

View file

@ -0,0 +1,160 @@
// Generates the devnet v4 proving fixtures on the private simnet of net.sh (eth JSON-RPC 29390): three blocks
// 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]
import { createPublicClient, http, parseEther, formatEther, encodeFunctionData, keccak256, toHex, stringToHex } from 'viem';
import { privateKeyToAccount } from 'viem/accounts';
import { readFileSync, writeFileSync } from 'node:fs';
const CHAIN_ID = 4463;
const RPC_URL = process.env.IGNEUM_RPC ?? 'http://127.0.0.1:29390';
const client = createPublicClient({ transport: http(RPC_URL, { timeout: 30_000, retryCount: 0 }) });
const rpc = (method, params = []) => client.request({ method, params });
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
const log = (...a) => console.log(new Date().toISOString().slice(11, 19), ...a);
// The simnet miner (tools/prove-fixtures/net.sh names its address); throwaway keys, never used elsewhere.
const miner = privateKeyToAccount('0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d');
const accounts = Array.from({ length: 24 }, (_, i) => privateKeyToAccount(keccak256(stringToHex(`igneum-prove-fixtures-${i}`))));
const payee = privateKeyToAccount('0xea6c44ac03bff858b476bba40716402b03e41b8e97e276d1baec7c37d42484a0');
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;
const wanted = (process.argv.includes('--shards') ? process.argv[process.argv.indexOf('--shards') + 1] : '1,2,4').split(',').map(Number);
const nonces = new Map();
async function nonceOf(acc) {
if (!nonces.has(acc.address)) nonces.set(acc.address, Number(await rpc('eth_getTransactionCount', [acc.address, 'latest'])));
const n = nonces.get(acc.address);
nonces.set(acc.address, n + 1);
return n;
}
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 });
}
async function send(raw) {
try { return await rpc('eth_sendRawTransaction', [raw]); } catch (e) { throw new Error(`send failed: ${e.details || e.shortMessage || e.message}`); }
}
async function waitReceipts(hashes, timeoutMs = 60_000) {
const out = new Map();
const start = Date.now();
while (out.size < hashes.length && Date.now() - start < timeoutMs) {
for (const h of hashes) {
if (out.has(h)) continue;
const r = await rpc('eth_getTransactionReceipt', [h]);
if (r) out.set(h, r);
}
if (out.size < hashes.length) await sleep(300);
}
if (out.size < hashes.length) throw new Error(`only ${out.size} of ${hashes.length} receipts after ${timeoutMs} ms`);
return out;
}
const pgasOf = (r) => Number(BigInt(r.igneum?.pgasUsed ?? r.pgasUsed ?? '0x0'));
async function blockNumber() { return Number(await rpc('eth_blockNumber')); }
async function main() {
// 1. The miner's rewards fund everything: 12 IGN per account that does not hold 6 yet.
const need = [];
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++) {
bal = BigInt(await rpc('eth_getBalance', [miner.address, 'latest']));
if (bal >= wanted_wei) break;
await sleep(1000);
}
log('miner', miner.address, 'balance', formatEther(bal), 'IGN at block', await blockNumber(), 'accounts to fund', need.length);
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));
// 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) {
const fund = [];
for (const a of need.slice(i, i + 12)) fund.push(await send(await sign(miner, { to: a.address, value: parseEther('12') })));
await waitReceipts(fund);
}
log('funded', need.length, 'accounts');
// 3. Deploy PgasBomb and Counter (registry payee: the Counter's constructor registers it).
const dBomb = await send(await sign(accounts[0], { to: null, data: bomb.bytecode, gas: 600_000n }));
const dCounter = await send(await sign(accounts[1], { to: null, data: encodeDeploy(counter, [REGISTRY, payee.address]), gas: 900_000n }));
const dr = await waitReceipts([dBomb, dCounter]);
const bombAddr = dr.get(dBomb).contractAddress, counterAddr = dr.get(dCounter).contractAddress;
if (dr.get(dBomb).status !== '0x1' || dr.get(dCounter).status !== '0x1') throw new Error('deployment failed');
log('PgasBomb at', bombAddr, 'Counter at', counterAddr);
// 4. Calibrate pgas per modexp iteration from two sizes.
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 }));
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 fixed = cal[0].pgas - 100 * perIter;
const gasPerIter = (cal[1].gas - cal[0].gas) / 300;
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;
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) {
const nBombs = 3 * shards;
let landed = null;
for (let attempt = 1; attempt <= 4 && !landed; attempt++) {
const raws = [];
// Bombs first, each from its own sender, with falling tips so a fee-ordered template keeps the order. The
// 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 }));
}
// 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 }));
// Wait for the next block, then burst.
const b0 = await blockNumber();
while ((await blockNumber()) === b0) await sleep(50);
const t0 = Date.now();
const hashes = [];
for (const raw of raws) hashes.push(await send(raw));
log(`shards ${shards}, attempt ${attempt}: sent ${hashes.length} transactions in ${Date.now() - t0} ms`);
const rs = await waitReceipts(hashes, 90_000);
const blocks = new Map();
for (const h of hashes) { const b = Number(BigInt(rs.get(h).blockNumber)); blocks.set(b, (blocks.get(b) ?? 0) + 1); }
const pgas = hashes.reduce((s, h) => s + pgasOf(rs.get(h)), 0);
const gas = hashes.reduce((s, h) => s + Number(BigInt(rs.get(h).gasUsed)), 0);
const statuses = hashes.map((h) => rs.get(h).status);
log(` landed in blocks ${JSON.stringify([...blocks])}, pgas ${pgas}, gas ${gas}, statuses ${[...new Set(statuses)]}`);
if (blocks.size === 1 && statuses.every((s) => s === '0x1')) {
const [block] = blocks.keys();
const seg = await rpc('igneum_getSegment', [toHex(block)]);
landed = { block, txs: hashes.length, pgas, gas, segmentPgas: Number(BigInt(seg.pgasUsed)), segmentGas: Number(BigInt(seg.gasUsed ?? '0x0')) };
log(` block ${block}: segment pgas ${landed.segmentPgas} (${(landed.segmentPgas / S_P).toFixed(2)} x S_p)`);
}
}
if (!landed) throw new Error(`could not land the ${shards}-shard batch in one block`);
results.blocks[shards] = landed;
}
// 6. Export every segment for the exporter.
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));
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));
}
function encodeDeploy(art, args) {
// Constructor (address, address): ABI-encode the two addresses after the bytecode.
const enc = args.map((a) => a.toLowerCase().replace('0x', '').padStart(64, '0')).join('');
return art.bytecode + enc;
}
main().catch((e) => { console.error(e); process.exit(1); });

47
tools/prove-fixtures/net.sh Executable file
View file

@ -0,0 +1,47 @@
#!/usr/bin/env bash
# A throwaway one-node igneumd simnet (PoW skipped) with one stub miner, for cutting proving fixtures.
# Ports 29300 (gRPC), 29301 (p2p), 29390 (eth JSON-RPC); data under /tmp/igneum-prove-fixtures. The live
# devnet (26610, 26611, 26640, 26641, 28640) and the other agents' ports are never touched.
#
# ./net.sh start ./net.sh stop
#
# BIN: the devnet-v4 worktree's release binaries by default (IGNEUM_BIN overrides).
set -u
ROOT="$(cd "$(dirname "$0")/../.." && pwd)"
BIN="${IGNEUM_BIN:-$ROOT/vendor/igneum-node-v4/target/release}"
DATA=/tmp/igneum-prove-fixtures
PIDS="$DATA/pids"
DURATION="${DURATION:-3600}"
HOLD_MS="${HOLD_MS:-2500}"
# The miner's EVM payout address: the address of the generator's miner key (tools/prove-fixtures/gen.mjs).
MINER_EVM=70997970c51812dc3a010c7d01b50e0d17dc79c8
# devnet-v4 miners name the payout address with --evm-address; the execution-layer branch's miner derives it
# from the low 20 bytes of --vote-key-hash. IGNEUM_MINER_ID overrides either.
if [ -n "${IGNEUM_MINER_ID:-}" ]; then MINER_ID="$IGNEUM_MINER_ID"
elif "$BIN/igneum-miner" 2>&1 | grep -q -- '--evm-address'; then MINER_ID="--evm-address $MINER_EVM"
else MINER_ID="--vote-key-hash 0x000000000000000000000000$MINER_EVM"; fi
case "${1:-}" in
start)
rm -rf "$DATA"; mkdir -p "$DATA/n1"; : > "$PIDS"
"$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 \
> "$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
"$BIN/igneum-miner" mine grpc://127.0.0.1:29300 1 "$DURATION" fixtures \
--engine stub --hold-ms "$HOLD_MS" --network simnet $MINER_ID \
> "$DATA/miner.log" 2>&1 &
echo $! >> "$PIDS"
echo "started node (eth RPC 29390) and one stub miner (hold $HOLD_MS ms); data $DATA"
;;
stop)
if [ -f "$PIDS" ]; then
while read -r p; do [ -n "$p" ] && kill "$p" 2>/dev/null; done < "$PIDS"
sleep 1
while read -r p; do [ -n "$p" ] && kill -9 "$p" 2>/dev/null; done < "$PIDS"
fi
echo "stopped"
;;
*) echo "usage: $0 start | stop"; exit 2 ;;
esac

219
tools/prove-fixtures/package-lock.json generated Normal file
View file

@ -0,0 +1,219 @@
{
"name": "igneum-prove-fixtures",
"version": "0.1.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "igneum-prove-fixtures",
"version": "0.1.0",
"dependencies": {
"viem": "^2.21.0"
}
},
"node_modules/@adraffy/ens-normalize": {
"version": "1.11.1",
"resolved": "https://registry.npmjs.org/@adraffy/ens-normalize/-/ens-normalize-1.11.1.tgz",
"integrity": "sha512-nhCBV3quEgesuf7c7KYfperqSS14T8bYuvJ8PcLJp6znkZpFc0AuW4qBtr8eKVyPPe/8RSr7sglCWPU5eaxwKQ==",
"license": "MIT"
},
"node_modules/@noble/ciphers": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/@noble/ciphers/-/ciphers-1.3.0.tgz",
"integrity": "sha512-2I0gnIVPtfnMw9ee9h1dJG7tp81+8Ob3OJb3Mv37rx5L40/b0i7djjCVvGOVqc9AEIQyvyu1i6ypKdFw8R8gQw==",
"license": "MIT",
"engines": {
"node": "^14.21.3 || >=16"
},
"funding": {
"url": "https://paulmillr.com/funding/"
}
},
"node_modules/@noble/curves": {
"version": "1.9.1",
"resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.9.1.tgz",
"integrity": "sha512-k11yZxZg+t+gWvBbIswW0yoJlu8cHOC7dhunwOzoWH/mXGBiYyR4YY6hAEK/3EUs4UpB8la1RfdRpeGsFHkWsA==",
"license": "MIT",
"dependencies": {
"@noble/hashes": "1.8.0"
},
"engines": {
"node": "^14.21.3 || >=16"
},
"funding": {
"url": "https://paulmillr.com/funding/"
}
},
"node_modules/@noble/hashes": {
"version": "1.8.0",
"resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.8.0.tgz",
"integrity": "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==",
"license": "MIT",
"engines": {
"node": "^14.21.3 || >=16"
},
"funding": {
"url": "https://paulmillr.com/funding/"
}
},
"node_modules/@scure/base": {
"version": "1.2.6",
"resolved": "https://registry.npmjs.org/@scure/base/-/base-1.2.6.tgz",
"integrity": "sha512-g/nm5FgUa//MCj1gV09zTJTaM6KBAHqLN907YVQqf7zC49+DcO4B1so4ZX07Ef10Twr6nuqYEH9GEggFXA4Fmg==",
"license": "MIT",
"funding": {
"url": "https://paulmillr.com/funding/"
}
},
"node_modules/@scure/bip32": {
"version": "1.7.0",
"resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-1.7.0.tgz",
"integrity": "sha512-E4FFX/N3f4B80AKWp5dP6ow+flD1LQZo/w8UnLGYZO674jS6YnYeepycOOksv+vLPSpgN35wgKgy+ybfTb2SMw==",
"license": "MIT",
"dependencies": {
"@noble/curves": "~1.9.0",
"@noble/hashes": "~1.8.0",
"@scure/base": "~1.2.5"
},
"funding": {
"url": "https://paulmillr.com/funding/"
}
},
"node_modules/@scure/bip39": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-1.6.0.tgz",
"integrity": "sha512-+lF0BbLiJNwVlev4eKelw1WWLaiKXw7sSl8T6FvBlWkdX+94aGJ4o8XjUdlyhTCjd8c+B3KT3JfS8P0bLRNU6A==",
"license": "MIT",
"dependencies": {
"@noble/hashes": "~1.8.0",
"@scure/base": "~1.2.5"
},
"funding": {
"url": "https://paulmillr.com/funding/"
}
},
"node_modules/abitype": {
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/abitype/-/abitype-1.2.3.tgz",
"integrity": "sha512-Ofer5QUnuUdTFsBRwARMoWKOH1ND5ehwYhJ3OJ/BQO+StkwQjHw0XyVh4vDttzHB7QOFhPHa/o413PJ82gU/Tg==",
"license": "MIT",
"funding": {
"url": "https://github.com/sponsors/wevm"
},
"peerDependencies": {
"typescript": ">=5.0.4",
"zod": "^3.22.0 || ^4.0.0"
},
"peerDependenciesMeta": {
"typescript": {
"optional": true
},
"zod": {
"optional": true
}
}
},
"node_modules/eventemitter3": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz",
"integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==",
"license": "MIT"
},
"node_modules/isows": {
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/isows/-/isows-1.0.7.tgz",
"integrity": "sha512-I1fSfDCZL5P0v33sVqeTDSpcstAg/N+wF5HS033mogOVIp4B+oHC7oOCsA3axAbBSGTJ8QubbNmnIRN/h8U7hg==",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/wevm"
}
],
"license": "MIT",
"peerDependencies": {
"ws": "*"
}
},
"node_modules/ox": {
"version": "0.14.45",
"resolved": "https://registry.npmjs.org/ox/-/ox-0.14.45.tgz",
"integrity": "sha512-jpsQ+p0JZh9mKCxxzxz0d5qFHZZg2/O9xW18IpEC/dNXXPVqmDJ0c//9RMz0CILkbSGPA42+cbU0fC/ghwJ03w==",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/wevm"
}
],
"license": "MIT",
"dependencies": {
"@adraffy/ens-normalize": "^1.11.0",
"@noble/ciphers": "^1.3.0",
"@noble/curves": "1.9.1",
"@noble/hashes": "^1.8.0",
"@scure/bip32": "^1.7.0",
"@scure/bip39": "^1.6.0",
"abitype": "^1.2.3",
"eventemitter3": "5.0.1"
},
"peerDependencies": {
"typescript": ">=5.4.0"
},
"peerDependenciesMeta": {
"typescript": {
"optional": true
}
}
},
"node_modules/viem": {
"version": "2.57.2",
"resolved": "https://registry.npmjs.org/viem/-/viem-2.57.2.tgz",
"integrity": "sha512-ZbPvu+5fvRsbFh+OymDz0GyEySsSco8GWrEAiHM4ckhEY1vJTPy0tcLVkn0cs70dPiUOjLxkQBnfVyt9YkJ7cA==",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/wevm"
}
],
"license": "MIT",
"dependencies": {
"@noble/curves": "1.9.1",
"@noble/hashes": "1.8.0",
"@scure/bip32": "1.7.0",
"@scure/bip39": "1.6.0",
"abitype": "1.2.3",
"isows": "1.0.7",
"ox": "0.14.45",
"ws": "8.21.0"
},
"peerDependencies": {
"typescript": ">=5.0.4"
},
"peerDependenciesMeta": {
"typescript": {
"optional": true
}
}
},
"node_modules/ws": {
"version": "8.21.0",
"resolved": "https://registry.npmjs.org/ws/-/ws-8.21.0.tgz",
"integrity": "sha512-Vsp28b7DRcimFQvrqu2Wek3z1iYxDCWqHYB8Qsnk/S4RfaCQzPGPyBNuVjJV3cd6UiKtUtp6sNM77gWvzcCH+g==",
"license": "MIT",
"engines": {
"node": ">=10.0.0"
},
"peerDependencies": {
"bufferutil": "^4.0.1",
"utf-8-validate": ">=5.0.2"
},
"peerDependenciesMeta": {
"bufferutil": {
"optional": true
},
"utf-8-validate": {
"optional": true
}
}
}
}
}

View file

@ -0,0 +1,13 @@
{
"name": "igneum-prove-fixtures",
"version": "0.1.0",
"private": true,
"type": "module",
"description": "Generates the devnet v4 proving fixtures: blocks that fill one, two and four shards at S_p, on a private simnet node (ports 29300+)",
"scripts": {
"gen": "node gen.mjs"
},
"dependencies": {
"viem": "^2.21.0"
}
}