igneum/docs/plans/explorer.md
igneum-labs 7eed16a29a Pre-public scrub, the text pass (7 October 2026, 19:5x UK): no founder name, personal login, earlier business or personal address in any tracked text file, and a gate check that keeps it so
The sweep (main's item 1): 199 tracked text files, 783 lines. The founder's full name, first name and possessive become "the founder" (sentence starts capitalised); the lowercase operating-system user name in WSL paths and commands becomes <user>; the second owner login becomes "the second owner login"; the three earlier businesses and the two other brands become "the other business", "the earlier entity", "the earlier business" and "another brand"; the Chrome profile rule names the igneum.network profile, not the profile's label. The standing commit login igneum-labs is not a founder term here: the fresh-repository step renames it in the history (docs/plans/history-rewrite.md, tools/repo/fresh-repo.sh).

The patterns never appear in plain text in the tree (a plaintext list would be the hit): tools/ci/founder-strings.b64 (perl regex, tab, a sample per row) is read by tools/ci/founder-strings-check.sh (every tracked text file, perl, known-failed first: the self-test plants each row's sample in a fixture and the hit must name the file), by tools/community/discord-hooks.mjs (the guard's founder and business rows; the test takes its fixtures from the samples) and by tools/repo/fresh-repo.sh (the business names of the rewrite rules). site/forbidden-strings.txt carries the same patterns as b64: lines, decoded case-insensitive by site/scrub.mjs and tools/ci/launch-gates-check.mjs (whose fixture now plants an encoded made-up name). The check runs in the gate's tree checks on every merge.

Not in this commit, by main's word: the 105 commit messages and 40 personal-identity commits that need the history rewrite (listed, not run), and the secrets found by gitleaks over the history (reported with owners).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-07 18:39:50 +00:00

15 KiB

Explorer: plan and recommendation

5 October 2026, after the founder read WhatToMine's listing requirements ("build it, and do we build our own explorer? who built etherscan?"). Branch explorer. What exists tonight: the public stats API (docs/api/public-stats.md) and the first DAG explorer pages on the site, fed by the observer. What is recommended: Blockscout for the EVM side, our own DAG and mining pages, one shared search box.

1. Who built Etherscan, and the open-source routes

Explorer What it is Licence and cost Fit for Igneum
Etherscan Built and launched in 2015 by Matthew Tan (CEO and founder); the office since January 2017 (etherscan.io/aboutus, read 5 October 2026; the page does not name the city, the founder's brief says Kuala Lumpur). Since 2020 it sells "Explorer as a Service", a white-label instance for other chains, 40 clients by 2025 (same page) Closed source, a private company; a chain pays for an instance. Price not published; not asked Not for us: closed, paid, and it would show nothing of the DAG, the finality or the proving layer
Blockscout Open-source EVM explorer: blocks, transactions, accounts, verified contracts, token pages, an API in Etherscan's shape. Elixir (Phoenix) backend, PostgreSQL, a separate frontend; "several hundred chains and rollups" use it (README, read 5 October 2026) "Blockscout Software Licence" (the README badge; the licence text was not read line by line, so what it permits for a hosted instance is unverified) The EVM side for free: contracts, transactions, logs, tokens, an API developers already know
Otterscan "open-source, fast, local, laptop-friendly Ethereum block explorer": a React app over an Erigon archive node, using Erigon's custom ots_ JSON-RPC methods (github.com/otterscan/otterscan, read 5 October 2026) MIT (the app); the ots_ API lives inside Erigon under its licence Not for us: it needs Erigon's RPC extensions, which the Igneum node does not have, and it has no contract verification

2. What Blockscout gives us for free, and what it costs to run

Blockscout indexes through standard JSON-RPC. Its documented requirements (docs.blockscout.com, read 5 October 2026):

Item Blockscout's figure Igneum node today (vendor/igneum-node 0.3.6 fork, igneum/exec/src/rpc.rs, 938 lines)
Software Erlang/OTP 26, Elixir 1.15.x, Postgres 14+, Node.js 18.x.x (docs: setup/requirements/requirements) n/a
Hardware, the docs' base line "16 core, 32 thread", "128GB" RAM; the AWS example is one m5a.xlarge (4 vCPU, 16 GB) application server with 8 GB EBS and one db.t3.large RDS Postgres 14+ with 500 GB "depending on chain size" (docs: setup/requirements/resource-requirements) A devnet at 0 EVM transactions per block needs nothing like the base line; the AWS example is the honest size for a small chain
Database Ethereum mainnet 21,000 GiB, Sepolia 5,200 GiB, Ethereum Classic 555 GiB, Gnosis Chiado 470 GiB (docs: setup/requirements/database-storage-requirements, figures dated 23 December 2024) Unmeasured for Igneum. At one chain block per second with empty blocks the row count is 86,400 blocks a day; the byte size per block is the thing to measure in the first week
RPC it needs from every client eth_blockNumber, eth_call, eth_getBalance, eth_getCode, eth_getBlockByHash, eth_getBlockByNumber, eth_getTransactionByHash, eth_getTransactionByBlockHashAndIndex, eth_getTransactionByBlockNumberAndIndex, eth_getTransactionReceipt, eth_getUncleByBlockHashAndIndex, eth_getLogs (docs: setup/requirements/node-tracing-json-rpc-requirements) The fork answers eth_blockNumber, eth_call, eth_getBalance, eth_getCode, eth_getBlockByHash, eth_getBlockByNumber, eth_getTransactionByHash, eth_getTransactionByBlockNumberAndIndex, eth_getTransactionReceipt, eth_getLogs (the match arms of rpc.rs). MISSING: eth_getTransactionByBlockHashAndIndex, eth_getUncleByBlockHashAndIndex (design 8.2 says uncles are "always empty": the method still has to exist). Also absent from the fork but in the design table: eth_getStorageAt is present; eth_getProof, eth_feeHistory present; web3_clientVersion, net_version, net_peerCount, net_listening, eth_syncing, eth_mining, eth_protocolVersion, eth_accounts, eth_getBlockReceipts, eth_getBlockTransactionCountByNumber, eth_maxPriorityFeePerGas, eth_gasPrice, eth_estimateGas, eth_sendRawTransaction present
Pending transactions txpool_content (geth, erigon) or parity_pendingTransactions Neither exists in the fork. Blockscout runs without it (the pending view stays empty)
Internal transactions and block rewards debug_traceBlockByNumber and debug_traceTransaction with callTracer (geth variant), or trace_replayBlockTransactions and trace_block (erigon, nethermind) None of the four exist in the fork. Design 8.2 lists them as "Supported, revm inspectors"; rpc.rs has no debug_ or trace_ method today. Without them Blockscout shows no internal transactions and no block-reward rows, and the indexer's trace fetcher must be switched off (INDEXER_DISABLE_INTERNAL_TRANSACTIONS_FETCHER, Blockscout's env; unverified against the current version)

Cost of one instance on Hetzner (the price list the seeds are on, docs/plans/seed-nodes.md: cx23 2 vCPU 4 GB at USD 6.49 net a month; larger types not priced here): Blockscout's own AWS example is 4 vCPU 16 GB plus a 2 vCPU 8 GB database. The matching Hetzner shape is one box in the 8 GB to 16 GB class plus Postgres on the same box for a devnet, a second box for the database when the chain carries real traffic. Price it from the Hetzner API when the box is ordered; the figure here is approximate: USD 15 to 40 a month for the single box, under USD 80 for two. Plus an Igneum node on the same box or next to it (Blockscout wants a local, unlimited RPC; the public rpc.testnet.igneum.network is rate limited to 20 req/s, docs/plans/testnet-go.md).

What it costs in work, in hours not weeks: the two missing eth_ methods (small, same shape as their by-number siblings); a decision on tracing (the debug_ namespace with revm inspectors, design 8.2, is the larger piece and is not needed to run Blockscout without internal transactions); Blockscout's env file and a Docker compose on the box; the chain's entry in its config (chain id 4463 devnet, 4462 testnet, 4461 mainnet, design 8.1); contract verification through Sourcify or Blockscout's own verifier microservice.

3. What Igneum needs that must be ours

Blockscout shows a chain: numbered blocks, one parent, transactions, accounts. Igneum's execution layer is such a chain (RPC "blocks" are chain blocks, design 8.2), so Blockscout is right for it. Everything the consensus layer adds is invisible to it:

Need Where it comes from State tonight
The DAG: every block, its parents, blue or red, pending, the selected chain, the mergeset of each chain block the observer's blockAdded feed (live_blocks, detail.mergeset) /explorer table and /block/<hash> built; the live DAG picture stays on /live
Blue score and DAA score per block, the miner's vote key, the engine tag the block header and coinbase built
Miners: payout address (the coinbase's IGNA tag) and the coinbase address, blocks mined, what they earned, balance observer columns evm_miner, miner_address; eth_getBalance through EXPLORER_EVM_RPC /address/<addr> built; balance shows when the deployment has an EVM RPC (none public for the devnet; rpc.testnet.igneum.network for the testnet)
The lottery program per epoch (which generated program is live, the epoch seed, the VDF) the node reports epochSeed per shard plan (igneum_getShardPlan); the program id and the epoch boundary are not in any RPC the observer reads not built; needs an RPC for the current program id and epoch (open)
Finality: checkpoints every 30 blue score, locks at two thirds of all 30-day weight, certificates, voter tables, the in-browser verifier live_checkpoints, live_certificates, /api/checkpoint, site/verify the block page shows a block's checkpoint state and certificate; a checkpoints list page is not built
Proof records and shards: the plan per chain block, who proved what, lag, payout live_proofs, igneum_getProofRecords the block page shows the shards and the records a block carries; a provers page (per prover: shards, lag, income) is not built
Pool payouts a public pool does not exist (section 5) not built
The switches: difficulty_v2_activation_daa, proving_v0_activation_daa, fees_v1_activation_daa, finality_v3_activation_daa (/tmp/igneum-devnet/override-v3.json on the devnet: 33,000, 84,100, 210,000, 135,200) the params file; igneum_getProvingStatus.activationDaa; no RPC lists them all not built; a "network parameters" card on /explorer reading a params RPC is the clean way

4. Recommendation

Confirmed from the code and the RPC surface: Blockscout for contracts, transactions and accounts; our own DAG, mining, finality and proving pages on the site, fed by the observer; one search box that routes a transaction or contract to Blockscout and a block hash, a chain block number or a miner to our pages. Two things qualify it:

  1. Blockscout cannot run against the fork as it is: eth_getTransactionByBlockHashAndIndex and eth_getUncleByBlockHashAndIndex are missing (an hour), and there is no tracing (debug_traceTransaction), so internal transactions stay off until the revm inspectors of design 8.2 exist. The execution engineer owns both.
  2. One box of our own and Postgres on it, next to a node with an unlimited local RPC. Not before the public testnet has transactions worth looking at; the devnet's blocks are empty and our pages already show them.

The search box: site/lib/explorer.mjs classify() already routes 64-hex to a block (the API falls through to a transaction hash in the last 24 hours), 0x40 and bech32 to an address, digits to a chain block number. When Blockscout is up, a 64-hex that is not a DAG block and a 0x40 that is a contract go to it instead of a 404.

5. What was built tonight

Item Where
/api/stats, /api/supply site/api/stats.mjs, site/api/supply.mjs, site/api/_neon.mjs; the emission rule in site/lib/emission.mjs; docs/api/public-stats.md with example responses
/api/explorer site/api/explorer.mjs: latest blocks, one block, height, address, search
Pages site/explorer.html, site/block.html, site/address.html; site/vercel.json rewrites /block/:id and /address/:addr; the footer carries an Explorer link (the nav is unchanged: its eight items are measured to fit at 941 px, a ninth is a layout decision for the site owner)
Observer tools/observer/observer.mjs: per-block explorer columns and detail, number from the shard plan, rpc_load, hourly supply_check
Preview node tools/site-serve.mjs (clean URLs, the rewrites, the API functions in-process; LIVE_TABLE_PREFIX, EXPLORER_EVM_RPC, PORT)
Tests site/lib/explorer.test.mjs (router, formatters), site/lib/emission.test.mjs (the node's own test values from igneum.rs, a devnet coinbase, the floor sum against a loop), site/api/public-stats.test.mjs (every documented field from a fixture); CI runs them, and on master tools/ci/public-api-check.mjs https://igneum.network
Screenshots docs/plans/explorer/explorer.png, block.png, address.png (local preview against a test observer, 5 October 2026)

Observer load, measured

Two copies of the observer ran side by side against the observer node (ws://127.0.0.1:28640, EVM RPC http://127.0.0.1:26790) with test table prefixes, 19:21 to 19:28 UTC on 5 October 2026: master's code with only a call counter added, and this branch. Calls per wall-clock minute, as each process counted them:

Minute (UTC) Before, wRPC After, wRPC Before, EVM After, EVM
19:21 to 19:22 (partial, 50 s) 283 282 776 785
19:22 211 211 2,119 2,145
19:23 252 253 2,487 2,493
19:24 232 232 2,487 2,492
19:25 266 266 2,491 2,497
19:26 210 210 2,485 2,481

Ratio after to before: 1.00 on both. The explorer reads everything from the notification the observer already receives; the only new work is one SQL update per shard-plan batch. The EVM figure is the proving feed's record polling (80 blocks per 2 s tick while proving is active, master behaviour); the observer that is live tonight points at http://127.0.0.1:26800 (the app's node, down), so its EVM load is zero and its proving feed reads "unreachable". The observer node answers the proving RPCs on 26790 (eth_chainId 0x116f, igneum_getProvingStatus active); pointing IGNEUM_EVM_RPC there when the observer is next restarted is a one-line change to the launch environment, not to the code.

Supply check, measured

The first sample after start: "21 blocks, payload subsidy = rule 21/21, outputs = merged subsidies 20/20 (1 without a verdict)". The rule in site/lib/emission.mjs reproduces the node's own test values (igneum.rs: 3,168,808,781 at DAA 2,592,000; 1,584,404,390 at the first halving; 0 at the 32nd) and the devnet coinbase of block 2622db76 (payload subsidy 454,486,399 at DAA 125,064; outputs 363,588,240 + 90,897,059 = 454,485,299 = E(125,063), what its merged parent declared: utxo_validation.rs:176 pays a merged block the subsidy its own payload carries).

6. A public pool with a stats API (separate item, not built)

The app carries a pool mode in the Hive package: the Flight Sheet's Pool URL is grpc://<your node>:26610 for solo mining or local to run the bundled node on the rig (packaging/hive/README.md); "there is no pool". A public pool needs, in order: the pool protocol of docs/spec/09-pool-protocol.md implemented (templates, shares, the member's own vote key and votes relayed, vardiff, the stats message: member hashrate, workers, refusals, shares, pool members, hashrate, blocks_24h, declared_share); a pool server on its own box with a node; a payout scheme (the spec leaves PPLNS windows and PPS fees to the pool); a stats API in the shape WhatToMine and MiningPoolStats read (pool hashrate, miners, workers, blocks found with heights and times, fee, minimum payout, luck); and a page on the site. None of this is in the repo; the stats API of this branch is the network side of what those sites ask for.

7. Unverified

  • Vercel's cleanUrls with a rewrite destination of /block and /address (the clean names of block.html and address.html): checked locally through tools/site-serve.mjs, not on a Vercel preview, because nothing was pushed.
  • /api/stats and /api/supply on the live tables: the live observer has not been restarted on this code, so the live live_blocks has no number, tx_count or detail columns yet; the handlers answer with nulls there until the restart (the schema adds itself on start, ALTER TABLE ... ADD COLUMN IF NOT EXISTS). The examples in docs/api/public-stats.md come from the test observer's tables.
  • Blockscout's licence terms for a hosted instance, and the exact env flag that disables its trace fetcher.
  • The database size per Igneum block in Blockscout, and the Hetzner price of the box: approximate above, measure and price when ordered.
  • EXPLORER_EVM_RPC on Vercel: no public devnet EVM RPC exists, so balances show "no EVM RPC configured" on the devnet deployment; the testnet's https://rpc.testnet.igneum.network is the value for the testnet.