Merge remote-tracking branch 'build/master' into class-v5
# Conflicts: # docs/ledger-public.md # infra/fast-time/override-60x.json # site/ledger.html
This commit is contained in:
commit
31ca4c4f2b
152 changed files with 24676 additions and 427 deletions
26
.forgejo/issue_template/grant.md
Normal file
26
.forgejo/issue_template/grant.md
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
---
|
||||
name: Grant application
|
||||
about: Apply for an Igneum grant: tooling, a reference app, infrastructure or research, paid in IGN on delivery
|
||||
title: "Grant: "
|
||||
labels: grant
|
||||
---
|
||||
|
||||
<!-- Read igneum.network/grants first. A short application is fine; the definition of done is the part that matters. -->
|
||||
|
||||
## What you will build
|
||||
|
||||
<!-- One paragraph. Name the tier: tooling, reference app, infrastructure, research. -->
|
||||
|
||||
## What done looks like
|
||||
|
||||
<!-- What runs where on the public testnet, and what a reviewer can click or call to see it working. -->
|
||||
|
||||
## Your public work
|
||||
|
||||
<!-- A repository, a package, a paper, a deployed thing. Links. -->
|
||||
|
||||
## How to reach you
|
||||
|
||||
<!-- An email, a Discord handle, or this issue. -->
|
||||
|
||||
<!-- Devnet and testnet coins have no value. No amount, price or date is promised. Not legal advice. -->
|
||||
18
contracts/bridge/foundry.toml
Normal file
18
contracts/bridge/foundry.toml
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
[profile.default]
|
||||
src = "src"
|
||||
test = "test"
|
||||
script = "script"
|
||||
out = "out"
|
||||
libs = []
|
||||
solc_version = "0.8.28"
|
||||
# The verifier calls the BLS12-381 precompiles of EIP-2537 (live on Sepolia and mainnet since Pectra), so the test EVM
|
||||
# runs the Osaka rules, the fork Sepolia is on (EIP-7883 modexp pricing counts here).
|
||||
evm_version = "osaka"
|
||||
optimizer = true
|
||||
optimizer_runs = 200
|
||||
via_ir = true
|
||||
fs_permissions = [{ access = "read", path = "./test/vectors" }, { access = "read-write", path = "./deploy-out.json" }]
|
||||
auto_detect_remappings = false
|
||||
|
||||
[rpc_endpoints]
|
||||
sepolia = "https://ethereum-sepolia-rpc.publicnode.com"
|
||||
46
contracts/bridge/script/Deploy.s.sol
Normal file
46
contracts/bridge/script/Deploy.s.sol
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.24;
|
||||
|
||||
import {Vm, VM_ADDRESS} from "../test/Vm.sol";
|
||||
import {IgneumCertificateVerifier} from "../src/IgneumCertificateVerifier.sol";
|
||||
|
||||
/// Deploys the verifier on Sepolia from BRIDGE_DEPLOYER_KEY (environment, never printed), installs the voter table
|
||||
/// from the vectors file named in BRIDGE_TABLE_JSON (a gen.mjs output: keys, weights, index, chain_id) and, when the
|
||||
/// file carries a certificate (bitmap, signature), submits it, so the contract records one checkpoint final from the start.
|
||||
///
|
||||
/// BRIDGE_TABLE_JSON=test/vectors/chain.json forge script script/Deploy.s.sol:Deploy --rpc-url sepolia --broadcast --sig "run()"
|
||||
contract Deploy {
|
||||
Vm constant vm = Vm(VM_ADDRESS);
|
||||
|
||||
function run() external {
|
||||
uint256 key = vm.envUint("BRIDGE_DEPLOYER_KEY");
|
||||
string memory j = vm.readFile(vm.envOr("BRIDGE_TABLE_JSON", "test/vectors/chain.json"));
|
||||
bytes[] memory keys = vm.parseJsonBytesArray(j, ".keys");
|
||||
uint256[] memory w = vm.parseJsonUintArray(j, ".weights");
|
||||
bytes memory packed;
|
||||
uint64[] memory weights = new uint64[](w.length);
|
||||
for (uint256 i = 0; i < keys.length; i++) {
|
||||
packed = abi.encodePacked(packed, keys[i]);
|
||||
weights[i] = uint64(w[i]);
|
||||
}
|
||||
uint64 index = uint64(vm.parseJsonUint(j, ".index"));
|
||||
|
||||
vm.startBroadcast(key);
|
||||
IgneumCertificateVerifier v = new IgneumCertificateVerifier(vm.parseJsonString(j, ".chain_id"));
|
||||
v.installTable(index, packed, weights);
|
||||
bool hasCert = vm.keyExistsJson(j, ".bitmap");
|
||||
if (hasCert) {
|
||||
v.submitCertificate(index, vm.parseJsonBytes32(j, ".checkpoint"), vm.parseJsonBytes(j, ".bitmap"), vm.parseJsonBytes(j, ".signature"));
|
||||
}
|
||||
vm.stopBroadcast();
|
||||
|
||||
vm.writeFile(
|
||||
"deploy-out.json",
|
||||
string.concat(
|
||||
"{\n \"IgneumCertificateVerifier\": \"", vm.toString(address(v)), "\",\n \"chain_id\": \"", vm.parseJsonString(j, ".chain_id"),
|
||||
"\",\n \"table_index\": ", vm.toString(uint256(index)), ",\n \"voters\": ", vm.toString(keys.length), ",\n \"table_id\": \"",
|
||||
vm.toString(v.tableId()), "\",\n \"final_checkpoint\": \"", hasCert ? vm.toString(vm.parseJsonBytes32(j, ".checkpoint")) : "none yet", "\"\n}\n"
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
22
contracts/bridge/script/Send.s.sol
Normal file
22
contracts/bridge/script/Send.s.sol
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.24;
|
||||
|
||||
import {Vm, VM_ADDRESS} from "../test/Vm.sol";
|
||||
|
||||
/// Sends SEND_WEI of the chain's coin from the key in BRIDGE_DEPLOYER_KEY to SEND_TO (Sepolia test ETH between the
|
||||
/// lanes' throwaway deployers). The key is read from the environment and never printed.
|
||||
///
|
||||
/// SEND_TO=0x.. SEND_WEI=20000000000000000 forge script script/Send.s.sol:Send --rpc-url sepolia --broadcast --sig "run()"
|
||||
contract Send {
|
||||
Vm constant vm = Vm(VM_ADDRESS);
|
||||
|
||||
function run() external {
|
||||
uint256 key = vm.envUint("BRIDGE_DEPLOYER_KEY");
|
||||
address to = vm.envAddress("SEND_TO");
|
||||
uint256 wei_ = vm.envUint("SEND_WEI");
|
||||
vm.startBroadcast(key);
|
||||
(bool ok,) = to.call{value: wei_}("");
|
||||
require(ok, "send failed");
|
||||
vm.stopBroadcast();
|
||||
}
|
||||
}
|
||||
113
contracts/bridge/src/BLS12381.sol
Normal file
113
contracts/bridge/src/BLS12381.sol
Normal file
|
|
@ -0,0 +1,113 @@
|
|||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.24;
|
||||
|
||||
/// BLS12-381 through the EIP-2537 precompiles (Ethereum mainnet and Sepolia since Pectra): the hash-to-curve of
|
||||
/// RFC 9380 (BLS12381G2_XMD:SHA-256_SSWU_RO_) with the caller's domain separation tag, public-key aggregation in G1
|
||||
/// and the two-pairing check of a "minimal public key" signature (keys in G1, signatures in G2), the scheme of
|
||||
/// Igneum's finality votes (consensus/core/src/finality.rs, blst "min_pk").
|
||||
///
|
||||
/// Encodings are the precompiles' own: a field element is 64 bytes (16 zero bytes then the 48-byte big-endian
|
||||
/// value), a G1 point 128 bytes (x, y), a G2 point 256 bytes (x.c0, x.c1, y.c0, y.c1). Compressed chain forms
|
||||
/// (48-byte keys, 96-byte signatures) are decompressed off chain by the submitter; the pairing precompile refuses
|
||||
/// a point off the curve or outside the prime-order subgroup, so a wrong decompression fails the check.
|
||||
library BLS12381 {
|
||||
address internal constant G1ADD = address(0x0b);
|
||||
address internal constant G2ADD = address(0x0d);
|
||||
address internal constant PAIRING = address(0x0f);
|
||||
address internal constant MAP_FP2_TO_G2 = address(0x11);
|
||||
address internal constant MODEXP = address(0x05);
|
||||
|
||||
uint256 internal constant G1_LEN = 128;
|
||||
uint256 internal constant G2_LEN = 256;
|
||||
|
||||
/// The field modulus p, big-endian, 48 bytes (the modexp precompile's modulus).
|
||||
bytes internal constant P = hex"1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaab";
|
||||
|
||||
/// The G1 generator with its y negated (p - y), in the 128-byte encoding, for the pairing check
|
||||
/// e(pk, H(m)) * e(-G1, sig) == 1.
|
||||
bytes internal constant NEG_G1 =
|
||||
hex"0000000000000000000000000000000017f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb"
|
||||
hex"00000000000000000000000000000000114d1d6855d545a8aa7d76c8cf2e21f267816aef1db507c96655b9d5caac42364e6f38ba0ecb751bad54dcd6b939c2ca";
|
||||
|
||||
error PrecompileFailed(address which);
|
||||
error BadLength(string what);
|
||||
|
||||
// ---- hash to curve ----
|
||||
|
||||
/// expand_message_xmd with SHA-256 (RFC 9380 section 5.3.1) to `len` bytes; len at most 255 * 32.
|
||||
function expandMessageXmd(bytes memory msg_, bytes memory dst, uint256 len) internal pure returns (bytes memory out) {
|
||||
require(dst.length <= 255, "BLS: DST too long");
|
||||
uint256 ell = (len + 31) / 32;
|
||||
require(ell <= 255 && len > 0, "BLS: bad length");
|
||||
bytes memory dstPrime = abi.encodePacked(dst, uint8(dst.length));
|
||||
bytes32 b0 = sha256(abi.encodePacked(new bytes(64), msg_, uint16(len), uint8(0), dstPrime));
|
||||
bytes32 bi = sha256(abi.encodePacked(b0, uint8(1), dstPrime));
|
||||
out = new bytes(ell * 32);
|
||||
assembly {
|
||||
mstore(add(out, 32), bi)
|
||||
}
|
||||
for (uint256 i = 2; i <= ell; i++) {
|
||||
bi = sha256(abi.encodePacked(b0 ^ bi, uint8(i), dstPrime));
|
||||
assembly {
|
||||
mstore(add(add(out, 32), mul(sub(i, 1), 32)), bi)
|
||||
}
|
||||
}
|
||||
assembly {
|
||||
mstore(out, len)
|
||||
}
|
||||
}
|
||||
|
||||
/// A 64-byte big-endian integer reduced mod p and returned in the precompiles' 64-byte field encoding.
|
||||
function reduce64(bytes memory chunk, uint256 offset) internal view returns (bytes memory fe) {
|
||||
require(chunk.length >= offset + 64, "BLS: chunk");
|
||||
bytes memory base = new bytes(64);
|
||||
for (uint256 i = 0; i < 64; i++) {
|
||||
base[i] = chunk[offset + i];
|
||||
}
|
||||
// modexp(base^1 mod p): lengths 64, 1, 48
|
||||
bytes memory input = abi.encodePacked(uint256(64), uint256(1), uint256(48), base, uint8(1), P);
|
||||
(bool ok, bytes memory r) = MODEXP.staticcall(input);
|
||||
if (!ok || r.length != 48) revert PrecompileFailed(MODEXP);
|
||||
fe = abi.encodePacked(bytes16(0), r);
|
||||
}
|
||||
|
||||
/// hash_to_curve for G2: two field elements of Fp2 from a 256-byte expansion, each mapped by the precompile
|
||||
/// (which clears the cofactor), then added.
|
||||
function hashToG2(bytes memory msg_, bytes memory dst) internal view returns (bytes memory point) {
|
||||
bytes memory u = expandMessageXmd(msg_, dst, 256);
|
||||
bytes memory q0 = mapFp2ToG2(abi.encodePacked(reduce64(u, 0), reduce64(u, 64)));
|
||||
bytes memory q1 = mapFp2ToG2(abi.encodePacked(reduce64(u, 128), reduce64(u, 192)));
|
||||
point = g2Add(q0, q1);
|
||||
}
|
||||
|
||||
function mapFp2ToG2(bytes memory fp2) internal view returns (bytes memory point) {
|
||||
if (fp2.length != 128) revert BadLength("fp2");
|
||||
(bool ok, bytes memory r) = MAP_FP2_TO_G2.staticcall(fp2);
|
||||
if (!ok || r.length != G2_LEN) revert PrecompileFailed(MAP_FP2_TO_G2);
|
||||
point = r;
|
||||
}
|
||||
|
||||
// ---- group operations ----
|
||||
|
||||
function g1Add(bytes memory a, bytes memory b) internal view returns (bytes memory c) {
|
||||
if (a.length != G1_LEN || b.length != G1_LEN) revert BadLength("g1");
|
||||
(bool ok, bytes memory r) = G1ADD.staticcall(abi.encodePacked(a, b));
|
||||
if (!ok || r.length != G1_LEN) revert PrecompileFailed(G1ADD);
|
||||
c = r;
|
||||
}
|
||||
|
||||
function g2Add(bytes memory a, bytes memory b) internal view returns (bytes memory c) {
|
||||
if (a.length != G2_LEN || b.length != G2_LEN) revert BadLength("g2");
|
||||
(bool ok, bytes memory r) = G2ADD.staticcall(abi.encodePacked(a, b));
|
||||
if (!ok || r.length != G2_LEN) revert PrecompileFailed(G2ADD);
|
||||
c = r;
|
||||
}
|
||||
|
||||
/// e(pk, hm) * e(-G1, sig) == 1, which holds exactly when sig = sk * hm for pk = sk * G1.
|
||||
function verifyMinPk(bytes memory pk, bytes memory hm, bytes memory sig) internal view returns (bool) {
|
||||
if (pk.length != G1_LEN || hm.length != G2_LEN || sig.length != G2_LEN) revert BadLength("pairing");
|
||||
(bool ok, bytes memory r) = PAIRING.staticcall(abi.encodePacked(pk, hm, NEG_G1, sig));
|
||||
if (!ok || r.length != 32) return false;
|
||||
return abi.decode(r, (uint256)) == 1;
|
||||
}
|
||||
}
|
||||
155
contracts/bridge/src/IgneumCertificateVerifier.sol
Normal file
155
contracts/bridge/src/IgneumCertificateVerifier.sol
Normal file
|
|
@ -0,0 +1,155 @@
|
|||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.24;
|
||||
|
||||
import {BLS12381} from "./BLS12381.sol";
|
||||
import {MerklePatricia} from "./MerklePatricia.sol";
|
||||
|
||||
interface IIgneumCertificateVerifier {
|
||||
function chainId() external view returns (string memory);
|
||||
function tableId() external view returns (bytes32);
|
||||
function verifyCertificate(uint64 index, bytes32 checkpoint, bytes calldata bitmap, bytes calldata signature)
|
||||
external
|
||||
view
|
||||
returns (bool ok, uint256 signedWeight, uint256 totalWeight);
|
||||
function submitCertificate(uint64 index, bytes32 checkpoint, bytes calldata bitmap, bytes calldata signature) external;
|
||||
function finalCheckpoint(uint64 index) external view returns (bytes32);
|
||||
function isFinal(bytes32 checkpoint) external view returns (bool);
|
||||
function verifyAccount(bytes32 stateRoot, address account, bytes[] calldata proof)
|
||||
external
|
||||
pure
|
||||
returns (bool exists, uint256 nonce, uint256 balance, bytes32 storageRoot, bytes32 codeHash);
|
||||
}
|
||||
|
||||
/// The Igneum light-client bridge primitive on Ethereum: verifies a Devnet 3 finality certificate (the aggregate
|
||||
/// BLS signature of the canonical voter list over the vote message, under the 2/3-of-total-weight rule) against an
|
||||
/// installed voter table, records the checkpoint hashes it proved final, and verifies an Ethereum-shape account
|
||||
/// proof against a state root. What it proves and what it does not: docs/bridge/light-client-bridge.md.
|
||||
///
|
||||
/// Devnet 3, test tokens, no value.
|
||||
contract IgneumCertificateVerifier is IIgneumCertificateVerifier {
|
||||
using MerklePatricia for bytes32;
|
||||
|
||||
string public constant VOTE_PREFIX = "igneum-vote-v1/";
|
||||
bytes public constant DST_VOTE = "IGNEUM_VOTE_V1_BLS12381G2_XMD:SHA-256_SSWU_RO_NUL_";
|
||||
|
||||
string private _chainId;
|
||||
address public owner;
|
||||
|
||||
/// The canonical voter list at the installed checkpoint index: 128-byte G1 keys in the node's canonical order
|
||||
/// (sorted by key hash, every key above dust and not stripped) and their weights (blue blocks in the window).
|
||||
bytes[] private _keys;
|
||||
uint64[] private _weights;
|
||||
uint256 public totalWeight;
|
||||
uint64 public tableIndex;
|
||||
bytes32 public override tableId;
|
||||
|
||||
mapping(uint64 => bytes32) public override finalCheckpoint;
|
||||
mapping(bytes32 => bool) public override isFinal;
|
||||
|
||||
event TableInstalled(uint64 indexed atIndex, uint256 voters, uint256 totalWeight, bytes32 tableId);
|
||||
event CheckpointFinal(uint64 indexed index, bytes32 checkpoint, uint256 signedWeight, uint256 totalWeight, uint256 signers);
|
||||
|
||||
error NotOwner();
|
||||
error NoTable();
|
||||
error BadCertificate(string why);
|
||||
|
||||
constructor(string memory chainId_) {
|
||||
_chainId = chainId_;
|
||||
owner = msg.sender;
|
||||
}
|
||||
|
||||
function chainId() external view override returns (string memory) {
|
||||
return _chainId;
|
||||
}
|
||||
|
||||
function voterCount() external view returns (uint256) {
|
||||
return _keys.length;
|
||||
}
|
||||
|
||||
function voter(uint256 i) external view returns (bytes memory key, uint64 weight) {
|
||||
return (_keys[i], _weights[i]);
|
||||
}
|
||||
|
||||
/// Installs the voter table read from a Devnet 3 node (igneum_getFinalityWeights at `atIndex`): `keys` is the
|
||||
/// concatenation of 128-byte uncompressed G1 keys in canonical order, `weights` their weights. The table is a
|
||||
/// trusted input of this first version (see the doc); only the installer may replace it.
|
||||
function installTable(uint64 atIndex, bytes calldata keys, uint64[] calldata weights) external {
|
||||
if (msg.sender != owner) revert NotOwner();
|
||||
if (keys.length != weights.length * BLS12381.G1_LEN || weights.length == 0) revert BadCertificate("table shape");
|
||||
delete _keys;
|
||||
delete _weights;
|
||||
uint256 total;
|
||||
for (uint256 i = 0; i < weights.length; i++) {
|
||||
_keys.push(keys[i * BLS12381.G1_LEN:(i + 1) * BLS12381.G1_LEN]);
|
||||
_weights.push(weights[i]);
|
||||
total += weights[i];
|
||||
}
|
||||
totalWeight = total;
|
||||
tableIndex = atIndex;
|
||||
tableId = keccak256(abi.encodePacked(atIndex, keys, abi.encodePacked(weights)));
|
||||
emit TableInstalled(atIndex, weights.length, total, tableId);
|
||||
}
|
||||
|
||||
/// The bytes every voter signs for (index, checkpoint): "igneum-vote-v1/" chain_id 0x00 index_le64 checkpoint.
|
||||
function voteMessage(uint64 index, bytes32 checkpoint) public view returns (bytes memory) {
|
||||
return abi.encodePacked(VOTE_PREFIX, _chainId, bytes1(0), le64(index), checkpoint);
|
||||
}
|
||||
|
||||
function verifyCertificate(uint64 index, bytes32 checkpoint, bytes calldata bitmap, bytes calldata signature)
|
||||
public
|
||||
view
|
||||
override
|
||||
returns (bool ok, uint256 signedWeight, uint256 totalWeight_)
|
||||
{
|
||||
uint256 n = _keys.length;
|
||||
if (n == 0) revert NoTable();
|
||||
if (bitmap.length != (n + 7) / 8) revert BadCertificate("bitmap length");
|
||||
if (signature.length != BLS12381.G2_LEN) revert BadCertificate("signature length");
|
||||
bytes memory agg;
|
||||
uint256 signers;
|
||||
for (uint256 p = 0; p < n; p++) {
|
||||
if (uint8(bitmap[p >> 3]) & uint8(1 << (p & 7)) == 0) continue;
|
||||
signedWeight += _weights[p];
|
||||
signers++;
|
||||
agg = agg.length == 0 ? _keys[p] : BLS12381.g1Add(agg, _keys[p]);
|
||||
}
|
||||
totalWeight_ = totalWeight;
|
||||
if (signers == 0) return (false, 0, totalWeight_);
|
||||
// the rule decided 4 October 2026: signed weight at least two thirds of the whole window's weight
|
||||
if (3 * signedWeight < 2 * totalWeight_) return (false, signedWeight, totalWeight_);
|
||||
bytes memory hm = BLS12381.hashToG2(voteMessage(index, checkpoint), DST_VOTE);
|
||||
ok = BLS12381.verifyMinPk(agg, hm, signature);
|
||||
}
|
||||
|
||||
function submitCertificate(uint64 index, bytes32 checkpoint, bytes calldata bitmap, bytes calldata signature) external override {
|
||||
(bool ok, uint256 signed, uint256 total) = verifyCertificate(index, checkpoint, bitmap, signature);
|
||||
if (!ok) revert BadCertificate("certificate does not verify");
|
||||
bytes32 known = finalCheckpoint[index];
|
||||
if (known != bytes32(0) && known != checkpoint) revert BadCertificate("a different checkpoint is final at this index");
|
||||
finalCheckpoint[index] = checkpoint;
|
||||
isFinal[checkpoint] = true;
|
||||
uint256 signers;
|
||||
for (uint256 p = 0; p < _keys.length; p++) {
|
||||
if (uint8(bitmap[p >> 3]) & uint8(1 << (p & 7)) != 0) signers++;
|
||||
}
|
||||
emit CheckpointFinal(index, checkpoint, signed, total, signers);
|
||||
}
|
||||
|
||||
function verifyAccount(bytes32 stateRoot, address account, bytes[] calldata proof)
|
||||
external
|
||||
pure
|
||||
override
|
||||
returns (bool exists, uint256 nonce, uint256 balance, bytes32 storageRoot, bytes32 codeHash)
|
||||
{
|
||||
MerklePatricia.Account memory a = MerklePatricia.verifyAccount(stateRoot, account, proof);
|
||||
return (a.exists, a.nonce, a.balance, a.storageRoot, a.codeHash);
|
||||
}
|
||||
|
||||
function le64(uint64 v) internal pure returns (bytes8 out) {
|
||||
uint64 r;
|
||||
for (uint256 i = 0; i < 8; i++) {
|
||||
r = (r << 8) | ((v >> (8 * i)) & 0xff);
|
||||
}
|
||||
out = bytes8(r);
|
||||
}
|
||||
}
|
||||
214
contracts/bridge/src/MerklePatricia.sol
Normal file
214
contracts/bridge/src/MerklePatricia.sol
Normal file
|
|
@ -0,0 +1,214 @@
|
|||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.24;
|
||||
|
||||
/// An Ethereum account proof (the eth_getProof shape) checked against a state root: the keccak-keyed Merkle
|
||||
/// Patricia trie of reth's layout, which Igneum's executor uses for its stateRoot (igneum/exec/src/state.rs,
|
||||
/// alloy_trie::root::state_root over keccak256(address) keys and RLP(nonce, balance, storageRoot, codeHash)
|
||||
/// values). A proof is the list of RLP nodes from the root to the account's leaf, or to the branch or leaf that
|
||||
/// shows the account absent.
|
||||
library MerklePatricia {
|
||||
struct Account {
|
||||
bool exists;
|
||||
uint256 nonce;
|
||||
uint256 balance;
|
||||
bytes32 storageRoot;
|
||||
bytes32 codeHash;
|
||||
}
|
||||
|
||||
error BadProof(string why);
|
||||
|
||||
/// Verifies `proof` for `account` under `stateRoot`; reverts when a node does not hash to its reference or
|
||||
/// the path is malformed, returns exists=false when the trie shows no such account.
|
||||
function verifyAccount(bytes32 stateRoot, address account, bytes[] memory proof) internal pure returns (Account memory out) {
|
||||
bytes memory value = verifyPath(stateRoot, abi.encodePacked(keccak256(abi.encodePacked(account))), proof);
|
||||
if (value.length == 0) return out;
|
||||
(uint256 off, uint256 len, bool isList) = decode(value, 0);
|
||||
if (!isList) revert BadProof("account value is not a list");
|
||||
uint256 end = off + len;
|
||||
uint256 p = off;
|
||||
(uint256 o1, uint256 l1,) = decode(value, p);
|
||||
out.nonce = toUint(value, o1, l1);
|
||||
p = o1 + l1;
|
||||
(uint256 o2, uint256 l2,) = decode(value, p);
|
||||
out.balance = toUint(value, o2, l2);
|
||||
p = o2 + l2;
|
||||
(uint256 o3, uint256 l3,) = decode(value, p);
|
||||
if (l3 != 32) revert BadProof("storage root length");
|
||||
out.storageRoot = toBytes32(value, o3);
|
||||
p = o3 + l3;
|
||||
(uint256 o4, uint256 l4,) = decode(value, p);
|
||||
if (l4 != 32) revert BadProof("code hash length");
|
||||
out.codeHash = toBytes32(value, o4);
|
||||
if (o4 + l4 != end) revert BadProof("account value has extra fields");
|
||||
out.exists = true;
|
||||
}
|
||||
|
||||
/// Walks the proof for `key` (32 bytes, hashed already) from `root`; returns the value found, or empty bytes
|
||||
/// when the trie proves the key absent.
|
||||
function verifyPath(bytes32 root, bytes memory key, bytes[] memory proof) internal pure returns (bytes memory value) {
|
||||
bytes memory nibbles = toNibbles(key);
|
||||
uint256 pos = 0;
|
||||
bytes32 want = root;
|
||||
bytes memory embedded;
|
||||
for (uint256 i = 0; i < proof.length; i++) {
|
||||
bytes memory node = proof[i];
|
||||
if (embedded.length != 0) {
|
||||
if (keccak256(node) != keccak256(embedded)) revert BadProof("embedded node mismatch");
|
||||
embedded = "";
|
||||
} else if (keccak256(node) != want) {
|
||||
revert BadProof("node hash mismatch");
|
||||
}
|
||||
(uint256 off, uint256 len, bool isList) = decode(node, 0);
|
||||
if (!isList) revert BadProof("node is not a list");
|
||||
uint256 count = itemCount(node, off, len);
|
||||
if (count == 17) {
|
||||
if (pos == nibbles.length) {
|
||||
// the branch's own value slot
|
||||
(uint256 vo, uint256 vl,) = itemAt(node, off, 16);
|
||||
return slice(node, vo, vl);
|
||||
}
|
||||
uint8 nib = uint8(nibbles[pos]);
|
||||
(uint256 co, uint256 cl, bool clist) = itemAt(node, off, nib);
|
||||
if (cl == 0 && !clist) return ""; // empty slot: the key is absent
|
||||
pos++;
|
||||
if (clist) {
|
||||
embedded = slice(node, co - headerLen(node, co, cl, true), cl + headerLen(node, co, cl, true));
|
||||
} else {
|
||||
if (cl != 32) revert BadProof("child reference length");
|
||||
want = toBytes32(node, co);
|
||||
}
|
||||
} else if (count == 2) {
|
||||
(uint256 po, uint256 pl,) = itemAt(node, off, 0);
|
||||
(bytes memory path, bool isLeaf) = decodePath(slice(node, po, pl));
|
||||
if (!matches(nibbles, pos, path)) return ""; // diverging path: the key is absent
|
||||
pos += path.length;
|
||||
(uint256 vo, uint256 vl, bool vlist) = itemAt(node, off, 1);
|
||||
if (isLeaf) {
|
||||
if (pos != nibbles.length) revert BadProof("leaf before the key's end");
|
||||
return slice(node, vo, vl);
|
||||
}
|
||||
if (vlist) {
|
||||
embedded = slice(node, vo - headerLen(node, vo, vl, true), vl + headerLen(node, vo, vl, true));
|
||||
} else {
|
||||
if (vl != 32) revert BadProof("extension reference length");
|
||||
want = toBytes32(node, vo);
|
||||
}
|
||||
} else {
|
||||
revert BadProof("node arity");
|
||||
}
|
||||
}
|
||||
revert BadProof("proof ends before the key");
|
||||
}
|
||||
|
||||
// ---- paths ----
|
||||
|
||||
function toNibbles(bytes memory key) internal pure returns (bytes memory n) {
|
||||
n = new bytes(key.length * 2);
|
||||
for (uint256 i = 0; i < key.length; i++) {
|
||||
n[2 * i] = bytes1(uint8(key[i]) >> 4);
|
||||
n[2 * i + 1] = bytes1(uint8(key[i]) & 0x0f);
|
||||
}
|
||||
}
|
||||
|
||||
/// Hex-prefix decoding of a leaf or extension path.
|
||||
function decodePath(bytes memory hp) internal pure returns (bytes memory path, bool isLeaf) {
|
||||
if (hp.length == 0) revert BadProof("empty path");
|
||||
uint8 flag = uint8(hp[0]) >> 4;
|
||||
isLeaf = flag >= 2;
|
||||
bool odd = flag % 2 == 1;
|
||||
uint256 n = (hp.length - 1) * 2 + (odd ? 1 : 0);
|
||||
path = new bytes(n);
|
||||
uint256 w = 0;
|
||||
if (odd) path[w++] = bytes1(uint8(hp[0]) & 0x0f);
|
||||
for (uint256 i = 1; i < hp.length; i++) {
|
||||
path[w++] = bytes1(uint8(hp[i]) >> 4);
|
||||
path[w++] = bytes1(uint8(hp[i]) & 0x0f);
|
||||
}
|
||||
}
|
||||
|
||||
function matches(bytes memory nibbles, uint256 pos, bytes memory path) internal pure returns (bool) {
|
||||
if (pos + path.length > nibbles.length) return false;
|
||||
for (uint256 i = 0; i < path.length; i++) {
|
||||
if (nibbles[pos + i] != path[i]) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// ---- RLP ----
|
||||
|
||||
/// The item at `p`: the offset of its payload, the payload length and whether it is a list.
|
||||
function decode(bytes memory b, uint256 p) internal pure returns (uint256 off, uint256 len, bool isList) {
|
||||
if (p >= b.length) revert BadProof("rlp out of range");
|
||||
uint8 first = uint8(b[p]);
|
||||
if (first < 0x80) return (p, 1, false);
|
||||
if (first < 0xb8) return (p + 1, first - 0x80, false);
|
||||
if (first < 0xc0) {
|
||||
uint256 n = first - 0xb7;
|
||||
return (p + 1 + n, readLen(b, p + 1, n), false);
|
||||
}
|
||||
if (first < 0xf8) return (p + 1, first - 0xc0, true);
|
||||
uint256 m = first - 0xf7;
|
||||
return (p + 1 + m, readLen(b, p + 1, m), true);
|
||||
}
|
||||
|
||||
function headerLen(bytes memory b, uint256 off, uint256 len, bool isList) private pure returns (uint256) {
|
||||
// the header length of an item whose payload starts at off: single bytes under 0x80 have none
|
||||
if (!isList && len == 1 && uint8(b[off]) < 0x80) return 0;
|
||||
if (len < 56) return 1;
|
||||
uint256 n = 0;
|
||||
uint256 l = len;
|
||||
while (l > 0) {
|
||||
n++;
|
||||
l >>= 8;
|
||||
}
|
||||
return 1 + n;
|
||||
}
|
||||
|
||||
function readLen(bytes memory b, uint256 p, uint256 n) private pure returns (uint256 len) {
|
||||
if (n == 0 || n > 32 || p + n > b.length) revert BadProof("rlp length");
|
||||
for (uint256 i = 0; i < n; i++) {
|
||||
len = (len << 8) | uint8(b[p + i]);
|
||||
}
|
||||
}
|
||||
|
||||
function itemCount(bytes memory b, uint256 off, uint256 len) private pure returns (uint256 n) {
|
||||
uint256 p = off;
|
||||
uint256 end = off + len;
|
||||
while (p < end) {
|
||||
(uint256 o, uint256 l,) = decode(b, p);
|
||||
p = o + l;
|
||||
n++;
|
||||
}
|
||||
if (p != end) revert BadProof("rlp list overrun");
|
||||
}
|
||||
|
||||
function itemAt(bytes memory b, uint256 off, uint256 index) private pure returns (uint256 o, uint256 l, bool isList) {
|
||||
uint256 p = off;
|
||||
for (uint256 i = 0; ; i++) {
|
||||
(o, l, isList) = decode(b, p);
|
||||
if (i == index) return (o, l, isList);
|
||||
p = o + l;
|
||||
}
|
||||
}
|
||||
|
||||
function toUint(bytes memory b, uint256 off, uint256 len) private pure returns (uint256 v) {
|
||||
if (len > 32) revert BadProof("integer too long");
|
||||
for (uint256 i = 0; i < len; i++) {
|
||||
v = (v << 8) | uint8(b[off + i]);
|
||||
}
|
||||
}
|
||||
|
||||
function toBytes32(bytes memory b, uint256 off) private pure returns (bytes32 v) {
|
||||
assembly {
|
||||
v := mload(add(add(b, 32), off))
|
||||
}
|
||||
}
|
||||
|
||||
function slice(bytes memory b, uint256 off, uint256 len) private pure returns (bytes memory out) {
|
||||
if (off + len > b.length) revert BadProof("slice out of range");
|
||||
out = new bytes(len);
|
||||
for (uint256 i = 0; i < len; i++) {
|
||||
out[i] = b[off + i];
|
||||
}
|
||||
}
|
||||
}
|
||||
144
contracts/bridge/test/Verifier.t.sol
Normal file
144
contracts/bridge/test/Verifier.t.sol
Normal file
|
|
@ -0,0 +1,144 @@
|
|||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.24;
|
||||
|
||||
import {Vm, VM_ADDRESS} from "./Vm.sol";
|
||||
import {IgneumCertificateVerifier} from "../src/IgneumCertificateVerifier.sol";
|
||||
import {BLS12381} from "../src/BLS12381.sol";
|
||||
|
||||
/// The verifier on Foundry's Prague EVM (the EIP-2537 precompiles): the synthetic vectors made by
|
||||
/// test/vectors/gen.mjs (five keys, a certificate by four of them, a small account trie) and, when present, a real
|
||||
/// certificate from the chain (test/vectors/chain.json, as /api/checkpoint serves it, decompressed by gen.mjs).
|
||||
contract VerifierTest {
|
||||
Vm constant vm = Vm(VM_ADDRESS);
|
||||
|
||||
string json;
|
||||
IgneumCertificateVerifier v;
|
||||
|
||||
function setUp() public {
|
||||
json = vm.readFile("test/vectors/synthetic.json");
|
||||
v = new IgneumCertificateVerifier(vm.parseJsonString(json, ".chain_id"));
|
||||
_install(v, json);
|
||||
}
|
||||
|
||||
function _install(IgneumCertificateVerifier target, string memory j) internal {
|
||||
bytes[] memory keys = vm.parseJsonBytesArray(j, ".keys");
|
||||
uint256[] memory w = vm.parseJsonUintArray(j, ".weights");
|
||||
bytes memory packed;
|
||||
uint64[] memory weights = new uint64[](w.length);
|
||||
for (uint256 i = 0; i < keys.length; i++) {
|
||||
packed = abi.encodePacked(packed, keys[i]);
|
||||
weights[i] = uint64(w[i]);
|
||||
}
|
||||
target.installTable(uint64(vm.parseJsonUint(j, ".index")), packed, weights);
|
||||
}
|
||||
|
||||
function test_vote_message_matches_the_node() public view {
|
||||
bytes memory want = vm.parseJsonBytes(json, ".vote_message");
|
||||
bytes memory got = v.voteMessage(uint64(vm.parseJsonUint(json, ".index")), vm.parseJsonBytes32(json, ".checkpoint"));
|
||||
require(keccak256(want) == keccak256(got), "vote message");
|
||||
}
|
||||
|
||||
function test_expand_message_xmd_known_answer() public view {
|
||||
// RFC 9380 appendix K.1 (expand_message_xmd with SHA-256, DST "QUUX-V01-CS02-with-expander-SHA256-128"): the
|
||||
// empty message at 32 bytes is the appendix's own first answer; the "abc" at 128 bytes answer comes from noble
|
||||
bytes memory dst = bytes(vm.parseJsonString(json, ".xmd_dst"));
|
||||
bytes memory out = BLS12381.expandMessageXmd("", dst, 32);
|
||||
require(keccak256(out) == keccak256(hex"68a985b87eb6b46952128911f2a4412bbc302a9d759667f87f7a21d803f07235"), "xmd 32 (RFC)");
|
||||
require(keccak256(out) == keccak256(vm.parseJsonBytes(json, ".xmd_empty_32")), "xmd 32 (noble)");
|
||||
bytes memory out2 = BLS12381.expandMessageXmd("abc", dst, 128);
|
||||
require(keccak256(out2) == keccak256(vm.parseJsonBytes(json, ".xmd_abc_128")), "xmd 128 (noble)");
|
||||
}
|
||||
|
||||
function test_certificate_verifies() public view {
|
||||
(bool ok, uint256 signed, uint256 total) = v.verifyCertificate(
|
||||
uint64(vm.parseJsonUint(json, ".index")), vm.parseJsonBytes32(json, ".checkpoint"), vm.parseJsonBytes(json, ".bitmap"), vm.parseJsonBytes(json, ".signature")
|
||||
);
|
||||
require(ok, "certificate");
|
||||
require(signed == vm.parseJsonUint(json, ".signed_weight") && total == vm.parseJsonUint(json, ".total_weight"), "weights");
|
||||
}
|
||||
|
||||
function test_certificate_under_two_thirds_is_refused() public view {
|
||||
(bool ok, uint256 signed,) = v.verifyCertificate(
|
||||
uint64(vm.parseJsonUint(json, ".index")), vm.parseJsonBytes32(json, ".checkpoint"), vm.parseJsonBytes(json, ".weak_bitmap"), vm.parseJsonBytes(json, ".weak_signature")
|
||||
);
|
||||
require(!ok && signed * 3 < vm.parseJsonUint(json, ".total_weight") * 2, "weak certificate accepted");
|
||||
}
|
||||
|
||||
function test_wrong_checkpoint_or_index_fails() public view {
|
||||
bytes32 cp = vm.parseJsonBytes32(json, ".checkpoint");
|
||||
uint64 index = uint64(vm.parseJsonUint(json, ".index"));
|
||||
bytes memory bm = vm.parseJsonBytes(json, ".bitmap");
|
||||
bytes memory sig = vm.parseJsonBytes(json, ".signature");
|
||||
(bool ok1,,) = v.verifyCertificate(index, cp ^ bytes32(uint256(1)), bm, sig);
|
||||
(bool ok2,,) = v.verifyCertificate(index + 1, cp, bm, sig);
|
||||
require(!ok1 && !ok2, "forged certificate accepted");
|
||||
// the right signers' weight with a bitmap naming a different signer set does not match the signature
|
||||
bytes memory other = vm.parseJsonBytes(json, ".weak_bitmap");
|
||||
other[0] = bytes1(uint8(other[0]) | 0x1f);
|
||||
(bool ok3,,) = v.verifyCertificate(index, cp, other, sig);
|
||||
require(!ok3, "wrong signer set accepted");
|
||||
}
|
||||
|
||||
function test_submit_records_the_checkpoint() public {
|
||||
bytes32 cp = vm.parseJsonBytes32(json, ".checkpoint");
|
||||
uint64 index = uint64(vm.parseJsonUint(json, ".index"));
|
||||
v.submitCertificate(index, cp, vm.parseJsonBytes(json, ".bitmap"), vm.parseJsonBytes(json, ".signature"));
|
||||
require(v.isFinal(cp) && v.finalCheckpoint(index) == cp, "not recorded");
|
||||
vm.expectRevert(abi.encodeWithSelector(IgneumCertificateVerifier.BadCertificate.selector, "certificate does not verify"));
|
||||
v.submitCertificate(index, cp, vm.parseJsonBytes(json, ".weak_bitmap"), vm.parseJsonBytes(json, ".weak_signature"));
|
||||
}
|
||||
|
||||
function test_account_proof_present_and_absent() public view {
|
||||
bytes32 root = vm.parseJsonBytes32(json, ".state_root");
|
||||
(bool exists, uint256 nonce, uint256 balance, bytes32 sroot, bytes32 chash) =
|
||||
v.verifyAccount(root, vm.parseJsonAddress(json, ".account"), vm.parseJsonBytesArray(json, ".account_proof"));
|
||||
require(exists, "account absent");
|
||||
require(nonce == vm.parseJsonUint(json, ".account_nonce") && balance == vm.parseJsonUint(json, ".account_balance"), "account fields");
|
||||
require(sroot == vm.parseJsonBytes32(json, ".account_storage_root") && chash == vm.parseJsonBytes32(json, ".account_code_hash"), "account roots");
|
||||
(bool exists2,,,,) = v.verifyAccount(root, vm.parseJsonAddress(json, ".absent_account"), vm.parseJsonBytesArray(json, ".absent_proof"));
|
||||
require(!exists2, "absent account present");
|
||||
}
|
||||
|
||||
function test_account_proof_against_a_wrong_root_reverts() public {
|
||||
bytes32 root = vm.parseJsonBytes32(json, ".state_root") ^ bytes32(uint256(1));
|
||||
bytes[] memory proof = vm.parseJsonBytesArray(json, ".account_proof");
|
||||
address a = vm.parseJsonAddress(json, ".account");
|
||||
vm.expectRevert(abi.encodeWithSelector(bytes4(keccak256("BadProof(string)")), "node hash mismatch"));
|
||||
v.verifyAccount(root, a, proof);
|
||||
}
|
||||
|
||||
/// A certificate the chain actually carried (test/vectors/chain.json; skipped when the file is absent).
|
||||
function test_chain_certificate_verifies() public {
|
||||
string memory j;
|
||||
try vm.readFile("test/vectors/chain.json") returns (string memory s) {
|
||||
j = s;
|
||||
} catch {
|
||||
return;
|
||||
}
|
||||
IgneumCertificateVerifier c = new IgneumCertificateVerifier(vm.parseJsonString(j, ".chain_id"));
|
||||
_install(c, j);
|
||||
(bool ok, uint256 signed, uint256 total) = c.verifyCertificate(
|
||||
uint64(vm.parseJsonUint(j, ".index")), vm.parseJsonBytes32(j, ".checkpoint"), vm.parseJsonBytes(j, ".bitmap"), vm.parseJsonBytes(j, ".signature")
|
||||
);
|
||||
require(signed == vm.parseJsonUint(j, ".signed_weight") && total == vm.parseJsonUint(j, ".total_weight"), "chain weights");
|
||||
require(ok, "the chain's certificate does not verify");
|
||||
}
|
||||
|
||||
/// One Devnet 3 account under a real Devnet 3 state root (test/vectors/dn3-account.json from a node's eth_getProof;
|
||||
/// skipped when the file is absent). The root is the chain's own; the link from a certified checkpoint to that root
|
||||
/// is the gap the doc names.
|
||||
function test_devnet3_account_balance_proven() public {
|
||||
string memory j;
|
||||
try vm.readFile("test/vectors/dn3-account.json") returns (string memory s) {
|
||||
j = s;
|
||||
} catch {
|
||||
return;
|
||||
}
|
||||
(bool exists, uint256 nonce, uint256 balance, bytes32 sroot, bytes32 chash) = v.verifyAccount(
|
||||
vm.parseJsonBytes32(j, ".state_root"), vm.parseJsonAddress(j, ".account"), vm.parseJsonBytesArray(j, ".account_proof")
|
||||
);
|
||||
require(exists, "the Devnet 3 account is absent under its root");
|
||||
require(nonce == vm.parseJsonUint(j, ".account_nonce") && balance == vm.parseJsonUint(j, ".account_balance"), "Devnet 3 account fields");
|
||||
require(sroot == vm.parseJsonBytes32(j, ".account_storage_root") && chash == vm.parseJsonBytes32(j, ".account_code_hash"), "Devnet 3 account roots");
|
||||
}
|
||||
}
|
||||
34
contracts/bridge/test/Vm.sol
Normal file
34
contracts/bridge/test/Vm.sol
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.24;
|
||||
|
||||
/// The Foundry cheatcodes this project uses, declared here so the tree needs no remote dependency.
|
||||
interface Vm {
|
||||
function startBroadcast(uint256 privateKey) external;
|
||||
function stopBroadcast() external;
|
||||
function envUint(string calldata name) external view returns (uint256);
|
||||
function envAddress(string calldata name) external view returns (address);
|
||||
function envOr(string calldata name, string calldata defaultValue) external view returns (string memory);
|
||||
function toString(address value) external pure returns (string memory);
|
||||
function toString(uint256 value) external pure returns (string memory);
|
||||
function toString(bytes32 value) external pure returns (string memory);
|
||||
function toString(bytes calldata value) external pure returns (string memory);
|
||||
function readFile(string calldata path) external view returns (string memory);
|
||||
function writeFile(string calldata path, string calldata data) external;
|
||||
function parseJsonBytes(string calldata json, string calldata key) external pure returns (bytes memory);
|
||||
function parseJsonBytes32(string calldata json, string calldata key) external pure returns (bytes32);
|
||||
function parseJsonUint(string calldata json, string calldata key) external pure returns (uint256);
|
||||
function parseJsonString(string calldata json, string calldata key) external pure returns (string memory);
|
||||
function parseJsonBytesArray(string calldata json, string calldata key) external pure returns (bytes[] memory);
|
||||
function parseJsonUintArray(string calldata json, string calldata key) external pure returns (uint256[] memory);
|
||||
function parseJsonAddress(string calldata json, string calldata key) external pure returns (address);
|
||||
function keyExistsJson(string calldata json, string calldata key) external view returns (bool);
|
||||
function deal(address who, uint256 newBalance) external;
|
||||
function prank(address msgSender) external;
|
||||
function startPrank(address msgSender) external;
|
||||
function stopPrank() external;
|
||||
function warp(uint256 newTimestamp) external;
|
||||
function expectRevert(bytes calldata revertData) external;
|
||||
function addr(uint256 privateKey) external pure returns (address);
|
||||
}
|
||||
|
||||
address constant VM_ADDRESS = address(uint160(uint256(keccak256("hevm cheat code"))));
|
||||
9
contracts/bridge/test/vectors/.gitignore
vendored
Normal file
9
contracts/bridge/test/vectors/.gitignore
vendored
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
node_modules
|
||||
synthetic.json
|
||||
chain.json
|
||||
checkpoint-live.json
|
||||
checkpoint-dn3.json
|
||||
weights-dn3.json
|
||||
checkpoints-dn3.json
|
||||
dn3-table.json
|
||||
dn3-account.json
|
||||
116
contracts/bridge/test/vectors/gen.mjs
Normal file
116
contracts/bridge/test/vectors/gen.mjs
Normal file
|
|
@ -0,0 +1,116 @@
|
|||
// Test vectors for the Igneum certificate verifier. Two sources:
|
||||
// node gen.mjs synthetic > synthetic.json five vote keys made here (noble BLS12-381), a certificate signed by four
|
||||
// of them over the Devnet 3 vote message, a small account trie with proofs
|
||||
// node gen.mjs table <weights.json> > dn3-table.json the voter table alone from a node's igneum_getFinalityWeights answer
|
||||
// (voters in the canonical order: sorted by key hash; weight = blocks)
|
||||
// node gen.mjs account <getProof.json> <stateRoot> <blockNumber> > dn3-account.json an eth_getProof answer from a Devnet 3
|
||||
// node (the reference-apps lane's reader) as the suite's real-root account vector
|
||||
// node gen.mjs chain <checkpoint.json> > dn3.json a real certificate as igneum.network/api/checkpoint?source=dn3 serves it:
|
||||
// the voter table and the aggregate signature decompressed to the
|
||||
// precompiles' encodings (the verifier checks the same bytes the node signed)
|
||||
// Encodings: field element 64 bytes (16 zero bytes then 48), G1 128 bytes, G2 256 bytes (x.c0, x.c1, y.c0, y.c1).
|
||||
// The DST and the vote message follow consensus/core/src/finality.rs and site/verify/core.js.
|
||||
import { bls12_381 } from '@noble/curves/bls12-381';
|
||||
import { expand_message_xmd } from '@noble/curves/abstract/hash-to-curve';
|
||||
import { sha256 } from '@noble/hashes/sha256';
|
||||
import { readFileSync } from 'node:fs';
|
||||
import { createRequire } from 'node:module';
|
||||
const require = createRequire(import.meta.url);
|
||||
|
||||
const DST = 'IGNEUM_VOTE_V1_BLS12381G2_XMD:SHA-256_SSWU_RO_NUL_';
|
||||
const CHAIN_ID = 'igneum-devnet-3';
|
||||
const te = new TextEncoder();
|
||||
const hex = b => '0x' + Array.from(b, x => x.toString(16).padStart(2, '0')).join('');
|
||||
const unhex = h => Uint8Array.from(Buffer.from(h.replace(/^0x/, ''), 'hex'));
|
||||
const be = (n, len) => { const out = new Uint8Array(len); let v = BigInt(n); for (let i = len - 1; i >= 0; i--) { out[i] = Number(v & 0xffn); v >>= 8n; } return out; };
|
||||
const fe = n => { const out = new Uint8Array(64); out.set(be(n, 48), 16); return out; };
|
||||
const concat = parts => { const n = parts.reduce((a, p) => a + p.length, 0); const out = new Uint8Array(n); let o = 0; for (const p of parts) { out.set(p, o); o += p.length; } return out; };
|
||||
const u64le = n => { const out = new Uint8Array(8); let v = BigInt(n); for (let i = 0; i < 8; i++) { out[i] = Number(v & 0xffn); v >>= 8n; } return out; };
|
||||
|
||||
const G1 = bls12_381.G1.ProjectivePoint, G2 = bls12_381.G2.ProjectivePoint;
|
||||
function g1Enc(p) { const a = p.toAffine(); return concat([fe(a.x), fe(a.y)]); }
|
||||
function g2Enc(p) { const a = p.toAffine(); return concat([fe(a.x.c0), fe(a.x.c1), fe(a.y.c0), fe(a.y.c1)]); }
|
||||
function voteMessage(index, checkpointHex) { return concat([te.encode('igneum-vote-v1/' + CHAIN_ID), new Uint8Array([0]), u64le(index), unhex(checkpointHex)]); }
|
||||
function bitmapOf(positions, n) { const bm = new Uint8Array(Math.ceil(n / 8)); for (const p of positions) bm[p >> 3] |= 1 << (p & 7); return bm; }
|
||||
|
||||
async function synthetic() {
|
||||
const sks = [1, 2, 3, 4, 5].map(i => { const s = new Uint8Array(32); s[31] = i; s[0] = 0x11 * i; return bls12_381.utils.randomPrivateKey ? bls12_381.G1.normPrivateKeyToScalar(s) : s; });
|
||||
const keys = sks.map(sk => G1.BASE.multiply(sk));
|
||||
const weights = [100, 250, 400, 300, 150];
|
||||
const index = 1234, checkpoint = '0x' + 'ab'.repeat(32);
|
||||
const msg = voteMessage(index, checkpoint);
|
||||
const hm = bls12_381.G2.hashToCurve(msg, { DST });
|
||||
const signers = [0, 1, 2, 3]; // 1,050 of 1,200: above two thirds
|
||||
const weakSigners = [0, 2, 4]; // 650 of 1,200: under two thirds
|
||||
const sign = who => who.map(i => hm.multiply(sks[i])).reduce((a, b) => a.add(b));
|
||||
const sig = sign(signers), weak = sign(weakSigners);
|
||||
// the account trie: three accounts, proofs for one present and one absent
|
||||
const { Trie } = require('@ethereumjs/trie');
|
||||
const { RLP } = require('@ethereumjs/rlp');
|
||||
const { keccak256 } = require('ethereum-cryptography/keccak');
|
||||
const trie = new Trie({ useKeyHashing: true });
|
||||
const accounts = [
|
||||
{ address: '0x07dd4dbca5c1a66755af28bacca1d901a2d209aa', nonce: 7n, balance: 999174011168718479514n, storageRoot: '0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421', codeHash: '0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470' },
|
||||
{ address: '0x9a6fa842c4e58a87aef1f3ad15233d99283002b7', nonce: 1n, balance: 0n, storageRoot: '0x' + '11'.repeat(32), codeHash: '0x' + '22'.repeat(32) },
|
||||
{ address: '0x53fe98022c2ac26d5d721457fb1c374b4d56144b', nonce: 3n, balance: 2580n * 10n ** 18n, storageRoot: '0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421', codeHash: '0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470' },
|
||||
];
|
||||
for (const a of accounts) {
|
||||
const v = RLP.encode([a.nonce === 0n ? new Uint8Array() : be(a.nonce, Math.ceil(a.nonce.toString(2).length / 8)), a.balance === 0n ? new Uint8Array() : be(a.balance, Math.ceil(a.balance.toString(2).length / 8)), unhex(a.storageRoot), unhex(a.codeHash)]);
|
||||
await trie.put(unhex(a.address), v);
|
||||
}
|
||||
const root = hex(trie.root());
|
||||
const proofFor = async addr => (await trie.createProof(unhex(addr))).map(hex);
|
||||
const absent = '0x000000000000000000000000000000000000dead';
|
||||
return {
|
||||
chain_id: CHAIN_ID, dst: DST, index, checkpoint,
|
||||
keys: keys.map(k => hex(g1Enc(k))), weights, total_weight: weights.reduce((a, b) => a + b, 0),
|
||||
bitmap: hex(bitmapOf(signers, keys.length)), signature: hex(g2Enc(sig)), signed_weight: signers.reduce((a, i) => a + weights[i], 0),
|
||||
weak_bitmap: hex(bitmapOf(weakSigners, keys.length)), weak_signature: hex(g2Enc(weak)),
|
||||
vote_message: hex(msg),
|
||||
// RFC 9380 expand_message_xmd(SHA-256) answers, computed by noble, for the Solidity port's own check
|
||||
xmd_dst: 'QUUX-V01-CS02-with-expander-SHA256-128',
|
||||
xmd_abc_128: hex(expand_message_xmd(te.encode('abc'), te.encode('QUUX-V01-CS02-with-expander-SHA256-128'), 128, sha256)),
|
||||
xmd_empty_32: hex(expand_message_xmd(new Uint8Array(), te.encode('QUUX-V01-CS02-with-expander-SHA256-128'), 32, sha256)),
|
||||
state_root: root,
|
||||
account: accounts[0].address, account_nonce: accounts[0].nonce.toString(), account_balance: accounts[0].balance.toString(),
|
||||
account_storage_root: accounts[0].storageRoot, account_code_hash: accounts[0].codeHash,
|
||||
account_proof: await proofFor(accounts[0].address),
|
||||
absent_account: absent, absent_proof: await proofFor(absent),
|
||||
};
|
||||
}
|
||||
|
||||
function chain(file) {
|
||||
const d = JSON.parse(readFileSync(file, 'utf8'));
|
||||
const voters = d.voters.map(v => ({ key: hex(g1Enc(G1.fromHex(v.pubkey_hex.replace(/^0x/, '')))), weight: Math.round(Number(v.weight)) }));
|
||||
const sig = G2.fromHex(d.certificate.aggregate_signature_hex.replace(/^0x/, ''));
|
||||
const positions = []; const bm = unhex(d.certificate.bitmap_hex);
|
||||
for (let p = 0; p < voters.length; p++) if (bm[p >> 3] & (1 << (p & 7))) positions.push(p);
|
||||
return {
|
||||
source: d.source, chain_id: d.chain_id, dst: DST, index: d.index, checkpoint: '0x' + d.hash,
|
||||
keys: voters.map(v => v.key), weights: voters.map(v => v.weight), total_weight: voters.reduce((a, v) => a + v.weight, 0),
|
||||
bitmap: '0x' + d.certificate.bitmap_hex, signature: hex(g2Enc(sig)), signed_weight: positions.reduce((a, p) => a + voters[p].weight, 0),
|
||||
signers: positions.length, voters_at_index: d.voters_at_index, stored_at: d.stored_at,
|
||||
};
|
||||
}
|
||||
|
||||
function table(file) {
|
||||
const d = JSON.parse(readFileSync(file, 'utf8'));
|
||||
const r = d.result || d;
|
||||
const voters = r.keys.filter(k => k.voter === true || k.voter === 'True').map(k => ({ keyHash: String(k.keyHash).replace(/^0x/, ''), key: hex(g1Enc(G1.fromHex(String(k.pubkey).replace(/^0x/, '')))), weight: Number(BigInt(k.blocks)) }));
|
||||
voters.sort((a, b) => (a.keyHash < b.keyHash ? -1 : a.keyHash > b.keyHash ? 1 : 0));
|
||||
const total = voters.reduce((a, v) => a + v.weight, 0);
|
||||
return { chain_id: process.env.IGNEUM_CHAIN_ID || CHAIN_ID, dst: DST, index: Number(BigInt(r.checkpointIndex)), checkpoint_at_index: '0x' + String(r.checkpointHash).replace(/^0x/, ''), keys: voters.map(v => v.key), weights: voters.map(v => v.weight), total_weight: total, total_weight_node: Number(BigInt(r.totalWeight)), voters: voters.length };
|
||||
}
|
||||
|
||||
function account(file, stateRoot, blockNumber) {
|
||||
const d = JSON.parse(readFileSync(file, 'utf8'));
|
||||
const r = d.result || d;
|
||||
return { chain_id: CHAIN_ID, state_root: stateRoot, block_number: Number(blockNumber), account: r.address, account_nonce: BigInt(r.nonce).toString(), account_balance: BigInt(r.balance).toString(), account_storage_root: r.storageHash, account_code_hash: r.codeHash, account_proof: r.accountProof };
|
||||
}
|
||||
|
||||
const mode = process.argv[2];
|
||||
if (mode === 'synthetic') synthetic().then(v => console.log(JSON.stringify(v, null, 1)));
|
||||
else if (mode === 'chain') console.log(JSON.stringify(chain(process.argv[3]), null, 1));
|
||||
else if (mode === 'table') console.log(JSON.stringify(table(process.argv[3]), null, 1));
|
||||
else if (mode === 'account') console.log(JSON.stringify(account(process.argv[3], process.argv[4], process.argv[5]), null, 1));
|
||||
else { console.error('usage: gen.mjs synthetic | table <weights.json> | account <getProof.json> <stateRoot> <blockNumber> | chain <checkpoint.json>'); process.exit(2); }
|
||||
19
contracts/dex/foundry.toml
Normal file
19
contracts/dex/foundry.toml
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
[profile.default]
|
||||
src = "src"
|
||||
test = "test"
|
||||
script = "script"
|
||||
out = "out"
|
||||
libs = []
|
||||
solc_version = "0.8.28"
|
||||
# Devnet 3's executor runs the EVM through revm; Paris keeps the bytecode off PUSH0 and transient storage so it runs
|
||||
# on any post-Merge configuration of it (8 October 2026).
|
||||
evm_version = "paris"
|
||||
optimizer = true
|
||||
optimizer_runs = 200
|
||||
fs_permissions = [{ access = "read-write", path = "./deploy-out.json" }]
|
||||
# no remote dependencies: the tests and the script declare the cheatcode interface they use (test/Vm.sol); solc 0.8.28 is fetched once by forge
|
||||
auto_detect_remappings = false
|
||||
|
||||
[rpc_endpoints]
|
||||
# the Devnet 3 EVM reaches the build box through a tunnel on this port (never the Mac); see docs/contracts/devnet-3.json
|
||||
devnet3 = "http://127.0.0.1:36790"
|
||||
58
contracts/dex/script/Deploy.s.sol
Normal file
58
contracts/dex/script/Deploy.s.sol
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.24;
|
||||
|
||||
import {Vm, VM_ADDRESS} from "../test/Vm.sol";
|
||||
import {WIGN} from "../src/WIGN.sol";
|
||||
import {TestToken} from "../src/TestToken.sol";
|
||||
import {IgneumFactory} from "../src/IgneumPair.sol";
|
||||
import {IgneumRouter} from "../src/IgneumRouter.sol";
|
||||
|
||||
/// Deploys the AMM on Devnet 3 from the key in DEX_DEPLOYER_KEY (read from the environment, never printed), seeds
|
||||
/// three pools from the faucet and 200 IGN, and writes the addresses to deploy-out.json for docs/contracts.
|
||||
///
|
||||
/// forge script script/Deploy.s.sol:Deploy --rpc-url devnet3 --broadcast --sig "run()"
|
||||
///
|
||||
/// Devnet 3, test tokens, no value.
|
||||
contract Deploy {
|
||||
Vm constant vm = Vm(VM_ADDRESS);
|
||||
|
||||
function run() external {
|
||||
uint256 key = vm.envUint("DEX_DEPLOYER_KEY");
|
||||
address deployer = vm.addr(key);
|
||||
vm.startBroadcast(key);
|
||||
|
||||
WIGN wign = new WIGN();
|
||||
TestToken tta = new TestToken("Test Token A", "TTA");
|
||||
TestToken ttb = new TestToken("Test Token B", "TTB");
|
||||
IgneumFactory factory = new IgneumFactory();
|
||||
IgneumRouter router = new IgneumRouter(address(factory), address(wign));
|
||||
|
||||
tta.drip();
|
||||
ttb.drip();
|
||||
tta.approve(address(router), type(uint256).max);
|
||||
ttb.approve(address(router), type(uint256).max);
|
||||
uint256 deadline = block.timestamp + 1 hours;
|
||||
router.addLiquidityIGN{value: 100 ether}(address(tta), 500 ether, 0, 0, deployer, deadline);
|
||||
router.addLiquidityIGN{value: 100 ether}(address(ttb), 500 ether, 0, 0, deployer, deadline);
|
||||
router.addLiquidity(address(tta), address(ttb), 500 ether, 500 ether, 0, 0, deployer, deadline);
|
||||
|
||||
vm.stopBroadcast();
|
||||
|
||||
string memory json = "{\n";
|
||||
json = _line(json, "WIGN", address(wign), ",");
|
||||
json = _line(json, "TTA", address(tta), ",");
|
||||
json = _line(json, "TTB", address(ttb), ",");
|
||||
json = _line(json, "IgneumFactory", address(factory), ",");
|
||||
json = _line(json, "IgneumRouter", address(router), ",");
|
||||
json = _line(json, "pair_TTA_WIGN", factory.getPair(address(tta), address(wign)), ",");
|
||||
json = _line(json, "pair_TTB_WIGN", factory.getPair(address(ttb), address(wign)), ",");
|
||||
json = _line(json, "pair_TTA_TTB", factory.getPair(address(tta), address(ttb)), ",");
|
||||
json = _line(json, "deployer", deployer, "");
|
||||
json = string.concat(json, "}\n");
|
||||
vm.writeFile("deploy-out.json", json);
|
||||
}
|
||||
|
||||
function _line(string memory json, string memory key, address value, string memory comma) private pure returns (string memory) {
|
||||
return string.concat(json, " \"", key, "\": \"", vm.toString(value), "\"", comma, "\n");
|
||||
}
|
||||
}
|
||||
37
contracts/dex/script/Seed.s.sol
Normal file
37
contracts/dex/script/Seed.s.sol
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.24;
|
||||
|
||||
import {Vm, VM_ADDRESS} from "../test/Vm.sol";
|
||||
import {TestToken} from "../src/TestToken.sol";
|
||||
import {IgneumRouter} from "../src/IgneumRouter.sol";
|
||||
|
||||
/// Seeds the three pools of an already deployed AMM (the addresses from the environment): a drip of each test
|
||||
/// token, approvals, 100 IGN beside 500 TTA, 100 IGN beside 500 TTB, 500 TTA beside 500 TTB. Run with
|
||||
/// --skip-simulation so every gas limit comes from the node's own eth_estimateGas: Devnet 3 charges the proving
|
||||
/// dimension inside the execution gas, so Foundry's local estimate runs out (8 October 2026, drip() at 133,603 gas:
|
||||
/// out of gas; the node's estimate 685,513).
|
||||
///
|
||||
/// DEX_TTA=0x.. DEX_TTB=0x.. DEX_ROUTER=0x.. forge script script/Seed.s.sol:Seed --rpc-url devnet3 --broadcast --slow --skip-simulation --sig "run()"
|
||||
///
|
||||
/// Devnet 3, test tokens, no value.
|
||||
contract Seed {
|
||||
Vm constant vm = Vm(VM_ADDRESS);
|
||||
|
||||
function run() external {
|
||||
uint256 key = vm.envUint("DEX_DEPLOYER_KEY");
|
||||
address deployer = vm.addr(key);
|
||||
TestToken tta = TestToken(vm.envAddress("DEX_TTA"));
|
||||
TestToken ttb = TestToken(vm.envAddress("DEX_TTB"));
|
||||
IgneumRouter router = IgneumRouter(payable(vm.envAddress("DEX_ROUTER")));
|
||||
vm.startBroadcast(key);
|
||||
if (tta.dripWait(deployer) == 0 && tta.balanceOf(deployer) < 1_000 ether) tta.drip();
|
||||
if (ttb.dripWait(deployer) == 0 && ttb.balanceOf(deployer) < 1_000 ether) ttb.drip();
|
||||
tta.approve(address(router), type(uint256).max);
|
||||
ttb.approve(address(router), type(uint256).max);
|
||||
uint256 deadline = block.timestamp + 1 hours;
|
||||
router.addLiquidityIGN{value: 100 ether}(address(tta), 500 ether, 0, 0, deployer, deadline);
|
||||
router.addLiquidityIGN{value: 100 ether}(address(ttb), 500 ether, 0, 0, deployer, deadline);
|
||||
router.addLiquidity(address(tta), address(ttb), 500 ether, 500 ether, 0, 0, deployer, deadline);
|
||||
vm.stopBroadcast();
|
||||
}
|
||||
}
|
||||
59
contracts/dex/src/ERC20.sol
Normal file
59
contracts/dex/src/ERC20.sol
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.24;
|
||||
|
||||
/// A plain ERC-20 with EIP-2612-free approvals, shared by the pair's liquidity token, the wrapped coin and the test
|
||||
/// tokens. Devnet 3, test tokens, no value.
|
||||
contract ERC20 {
|
||||
string public name;
|
||||
string public symbol;
|
||||
uint8 public constant decimals = 18;
|
||||
uint256 public totalSupply;
|
||||
mapping(address => uint256) public balanceOf;
|
||||
mapping(address => mapping(address => uint256)) public allowance;
|
||||
|
||||
event Transfer(address indexed from, address indexed to, uint256 value);
|
||||
event Approval(address indexed owner, address indexed spender, uint256 value);
|
||||
|
||||
constructor(string memory name_, string memory symbol_) {
|
||||
name = name_;
|
||||
symbol = symbol_;
|
||||
}
|
||||
|
||||
function _mint(address to, uint256 value) internal {
|
||||
totalSupply += value;
|
||||
balanceOf[to] += value;
|
||||
emit Transfer(address(0), to, value);
|
||||
}
|
||||
|
||||
function _burn(address from, uint256 value) internal {
|
||||
balanceOf[from] -= value;
|
||||
totalSupply -= value;
|
||||
emit Transfer(from, address(0), value);
|
||||
}
|
||||
|
||||
function _transfer(address from, address to, uint256 value) internal {
|
||||
balanceOf[from] -= value;
|
||||
balanceOf[to] += value;
|
||||
emit Transfer(from, to, value);
|
||||
}
|
||||
|
||||
function approve(address spender, uint256 value) external returns (bool) {
|
||||
allowance[msg.sender][spender] = value;
|
||||
emit Approval(msg.sender, spender, value);
|
||||
return true;
|
||||
}
|
||||
|
||||
function transfer(address to, uint256 value) external returns (bool) {
|
||||
_transfer(msg.sender, to, value);
|
||||
return true;
|
||||
}
|
||||
|
||||
function transferFrom(address from, address to, uint256 value) external returns (bool) {
|
||||
uint256 allowed = allowance[from][msg.sender];
|
||||
if (allowed != type(uint256).max) {
|
||||
allowance[from][msg.sender] = allowed - value;
|
||||
}
|
||||
_transfer(from, to, value);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
174
contracts/dex/src/IgneumPair.sol
Normal file
174
contracts/dex/src/IgneumPair.sol
Normal file
|
|
@ -0,0 +1,174 @@
|
|||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.24;
|
||||
|
||||
import {ERC20} from "./ERC20.sol";
|
||||
|
||||
interface IERC20Minimal {
|
||||
function balanceOf(address) external view returns (uint256);
|
||||
function transfer(address, uint256) external returns (bool);
|
||||
}
|
||||
|
||||
/// A constant-product pool in the Uniswap v2 shape: reserves of two tokens, a 0.3 percent fee kept in the pool,
|
||||
/// liquidity tokens for the depositors, MINIMUM_LIQUIDITY locked at the first mint. No protocol fee, no price
|
||||
/// accumulators, no flash callback. Devnet 3, test tokens, no value.
|
||||
contract IgneumPair is ERC20("Igneum LP", "IGN-LP") {
|
||||
uint256 public constant MINIMUM_LIQUIDITY = 10 ** 3;
|
||||
|
||||
address public immutable factory;
|
||||
address public token0;
|
||||
address public token1;
|
||||
|
||||
uint112 private reserve0;
|
||||
uint112 private reserve1;
|
||||
uint32 private blockTimestampLast;
|
||||
|
||||
uint256 private unlocked = 1;
|
||||
|
||||
event Mint(address indexed sender, uint256 amount0, uint256 amount1);
|
||||
event Burn(address indexed sender, uint256 amount0, uint256 amount1, address indexed to);
|
||||
event Swap(address indexed sender, uint256 amount0In, uint256 amount1In, uint256 amount0Out, uint256 amount1Out, address indexed to);
|
||||
event Sync(uint112 reserve0, uint112 reserve1);
|
||||
|
||||
modifier lock() {
|
||||
require(unlocked == 1, "Pair: locked");
|
||||
unlocked = 0;
|
||||
_;
|
||||
unlocked = 1;
|
||||
}
|
||||
|
||||
constructor() {
|
||||
factory = msg.sender;
|
||||
}
|
||||
|
||||
function initialize(address token0_, address token1_) external {
|
||||
require(msg.sender == factory, "Pair: forbidden");
|
||||
token0 = token0_;
|
||||
token1 = token1_;
|
||||
}
|
||||
|
||||
function getReserves() public view returns (uint112, uint112, uint32) {
|
||||
return (reserve0, reserve1, blockTimestampLast);
|
||||
}
|
||||
|
||||
function _safeTransfer(address token, address to, uint256 value) private {
|
||||
(bool ok, bytes memory data) = token.call(abi.encodeWithSelector(IERC20Minimal.transfer.selector, to, value));
|
||||
require(ok && (data.length == 0 || abi.decode(data, (bool))), "Pair: transfer failed");
|
||||
}
|
||||
|
||||
function _update(uint256 balance0, uint256 balance1) private {
|
||||
require(balance0 <= type(uint112).max && balance1 <= type(uint112).max, "Pair: overflow");
|
||||
reserve0 = uint112(balance0);
|
||||
reserve1 = uint112(balance1);
|
||||
blockTimestampLast = uint32(block.timestamp);
|
||||
emit Sync(reserve0, reserve1);
|
||||
}
|
||||
|
||||
function _sqrt(uint256 y) private pure returns (uint256 z) {
|
||||
if (y > 3) {
|
||||
z = y;
|
||||
uint256 x = y / 2 + 1;
|
||||
while (x < z) {
|
||||
z = x;
|
||||
x = (y / x + x) / 2;
|
||||
}
|
||||
} else if (y != 0) {
|
||||
z = 1;
|
||||
}
|
||||
}
|
||||
|
||||
function _min(uint256 x, uint256 y) private pure returns (uint256) {
|
||||
return x < y ? x : y;
|
||||
}
|
||||
|
||||
/// Mints liquidity for the tokens sent to the pair since the last sync. Called by the router.
|
||||
function mint(address to) external lock returns (uint256 liquidity) {
|
||||
(uint112 r0, uint112 r1,) = getReserves();
|
||||
uint256 balance0 = IERC20Minimal(token0).balanceOf(address(this));
|
||||
uint256 balance1 = IERC20Minimal(token1).balanceOf(address(this));
|
||||
uint256 amount0 = balance0 - r0;
|
||||
uint256 amount1 = balance1 - r1;
|
||||
if (totalSupply == 0) {
|
||||
liquidity = _sqrt(amount0 * amount1) - MINIMUM_LIQUIDITY;
|
||||
_mint(address(0xdead), MINIMUM_LIQUIDITY);
|
||||
} else {
|
||||
liquidity = _min(amount0 * totalSupply / r0, amount1 * totalSupply / r1);
|
||||
}
|
||||
require(liquidity > 0, "Pair: insufficient liquidity minted");
|
||||
_mint(to, liquidity);
|
||||
_update(balance0, balance1);
|
||||
emit Mint(msg.sender, amount0, amount1);
|
||||
}
|
||||
|
||||
/// Burns the liquidity tokens sent to the pair and pays both tokens out pro rata. Called by the router.
|
||||
function burn(address to) external lock returns (uint256 amount0, uint256 amount1) {
|
||||
uint256 balance0 = IERC20Minimal(token0).balanceOf(address(this));
|
||||
uint256 balance1 = IERC20Minimal(token1).balanceOf(address(this));
|
||||
uint256 liquidity = balanceOf[address(this)];
|
||||
amount0 = liquidity * balance0 / totalSupply;
|
||||
amount1 = liquidity * balance1 / totalSupply;
|
||||
require(amount0 > 0 && amount1 > 0, "Pair: insufficient liquidity burned");
|
||||
_burn(address(this), liquidity);
|
||||
_safeTransfer(token0, to, amount0);
|
||||
_safeTransfer(token1, to, amount1);
|
||||
_update(IERC20Minimal(token0).balanceOf(address(this)), IERC20Minimal(token1).balanceOf(address(this)));
|
||||
emit Burn(msg.sender, amount0, amount1, to);
|
||||
}
|
||||
|
||||
/// Pays out up to the amounts asked and checks the fee-adjusted product did not fall. The input must already
|
||||
/// sit in the pair (the router sends it first).
|
||||
function swap(uint256 amount0Out, uint256 amount1Out, address to) external lock {
|
||||
require(amount0Out > 0 || amount1Out > 0, "Pair: insufficient output amount");
|
||||
(uint112 r0, uint112 r1,) = getReserves();
|
||||
require(amount0Out < r0 && amount1Out < r1, "Pair: insufficient liquidity");
|
||||
require(to != token0 && to != token1, "Pair: invalid to");
|
||||
if (amount0Out > 0) _safeTransfer(token0, to, amount0Out);
|
||||
if (amount1Out > 0) _safeTransfer(token1, to, amount1Out);
|
||||
uint256 balance0 = IERC20Minimal(token0).balanceOf(address(this));
|
||||
uint256 balance1 = IERC20Minimal(token1).balanceOf(address(this));
|
||||
uint256 amount0In = balance0 > r0 - amount0Out ? balance0 - (r0 - amount0Out) : 0;
|
||||
uint256 amount1In = balance1 > r1 - amount1Out ? balance1 - (r1 - amount1Out) : 0;
|
||||
require(amount0In > 0 || amount1In > 0, "Pair: insufficient input amount");
|
||||
uint256 adjusted0 = balance0 * 1000 - amount0In * 3;
|
||||
uint256 adjusted1 = balance1 * 1000 - amount1In * 3;
|
||||
require(adjusted0 * adjusted1 >= uint256(r0) * uint256(r1) * 1000 ** 2, "Pair: K");
|
||||
_update(balance0, balance1);
|
||||
emit Swap(msg.sender, amount0In, amount1In, amount0Out, amount1Out, to);
|
||||
}
|
||||
|
||||
/// Sends any balance above the reserves to `to`.
|
||||
function skim(address to) external lock {
|
||||
_safeTransfer(token0, to, IERC20Minimal(token0).balanceOf(address(this)) - reserve0);
|
||||
_safeTransfer(token1, to, IERC20Minimal(token1).balanceOf(address(this)) - reserve1);
|
||||
}
|
||||
|
||||
/// Sets the reserves to the balances.
|
||||
function sync() external lock {
|
||||
_update(IERC20Minimal(token0).balanceOf(address(this)), IERC20Minimal(token1).balanceOf(address(this)));
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates one pair per unordered token pair and remembers it.
|
||||
contract IgneumFactory {
|
||||
mapping(address => mapping(address => address)) public getPair;
|
||||
address[] public allPairs;
|
||||
|
||||
event PairCreated(address indexed token0, address indexed token1, address pair, uint256 count);
|
||||
|
||||
function allPairsLength() external view returns (uint256) {
|
||||
return allPairs.length;
|
||||
}
|
||||
|
||||
function createPair(address tokenA, address tokenB) external returns (address pair) {
|
||||
require(tokenA != tokenB, "Factory: identical addresses");
|
||||
(address token0, address token1) = tokenA < tokenB ? (tokenA, tokenB) : (tokenB, tokenA);
|
||||
require(token0 != address(0), "Factory: zero address");
|
||||
require(getPair[token0][token1] == address(0), "Factory: pair exists");
|
||||
bytes32 salt = keccak256(abi.encodePacked(token0, token1));
|
||||
pair = address(new IgneumPair{salt: salt}());
|
||||
IgneumPair(pair).initialize(token0, token1);
|
||||
getPair[token0][token1] = pair;
|
||||
getPair[token1][token0] = pair;
|
||||
allPairs.push(pair);
|
||||
emit PairCreated(token0, token1, pair, allPairs.length);
|
||||
}
|
||||
}
|
||||
253
contracts/dex/src/IgneumRouter.sol
Normal file
253
contracts/dex/src/IgneumRouter.sol
Normal file
|
|
@ -0,0 +1,253 @@
|
|||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.24;
|
||||
|
||||
import {IgneumFactory, IgneumPair} from "./IgneumPair.sol";
|
||||
|
||||
interface IERC20Router {
|
||||
function balanceOf(address) external view returns (uint256);
|
||||
function transfer(address, uint256) external returns (bool);
|
||||
function transferFrom(address, address, uint256) external returns (bool);
|
||||
}
|
||||
|
||||
interface IWIGN is IERC20Router {
|
||||
function deposit() external payable;
|
||||
function withdraw(uint256) external;
|
||||
}
|
||||
|
||||
/// The router in the Uniswap v2 shape: adds and removes liquidity, swaps along a path of pairs, quotes. Pairs are
|
||||
/// looked up on the factory, never derived from an init-code hash. Devnet 3, test tokens, no value.
|
||||
contract IgneumRouter {
|
||||
IgneumFactory public immutable factory;
|
||||
address public immutable WIGN;
|
||||
|
||||
modifier ensure(uint256 deadline) {
|
||||
require(deadline >= block.timestamp, "Router: expired");
|
||||
_;
|
||||
}
|
||||
|
||||
constructor(address factory_, address wign_) {
|
||||
factory = IgneumFactory(factory_);
|
||||
WIGN = wign_;
|
||||
}
|
||||
|
||||
receive() external payable {
|
||||
require(msg.sender == WIGN, "Router: only WIGN");
|
||||
}
|
||||
|
||||
// ---- pure maths ----
|
||||
|
||||
function sortTokens(address tokenA, address tokenB) public pure returns (address token0, address token1) {
|
||||
require(tokenA != tokenB, "Router: identical addresses");
|
||||
(token0, token1) = tokenA < tokenB ? (tokenA, tokenB) : (tokenB, tokenA);
|
||||
require(token0 != address(0), "Router: zero address");
|
||||
}
|
||||
|
||||
function quote(uint256 amountA, uint256 reserveA, uint256 reserveB) public pure returns (uint256 amountB) {
|
||||
require(amountA > 0, "Router: insufficient amount");
|
||||
require(reserveA > 0 && reserveB > 0, "Router: insufficient liquidity");
|
||||
amountB = amountA * reserveB / reserveA;
|
||||
}
|
||||
|
||||
function getAmountOut(uint256 amountIn, uint256 reserveIn, uint256 reserveOut) public pure returns (uint256 amountOut) {
|
||||
require(amountIn > 0, "Router: insufficient input amount");
|
||||
require(reserveIn > 0 && reserveOut > 0, "Router: insufficient liquidity");
|
||||
uint256 amountInWithFee = amountIn * 997;
|
||||
amountOut = amountInWithFee * reserveOut / (reserveIn * 1000 + amountInWithFee);
|
||||
}
|
||||
|
||||
function getAmountIn(uint256 amountOut, uint256 reserveIn, uint256 reserveOut) public pure returns (uint256 amountIn) {
|
||||
require(amountOut > 0, "Router: insufficient output amount");
|
||||
require(reserveIn > 0 && reserveOut > 0, "Router: insufficient liquidity");
|
||||
amountIn = (reserveIn * amountOut * 1000) / ((reserveOut - amountOut) * 997) + 1;
|
||||
}
|
||||
|
||||
// ---- views ----
|
||||
|
||||
function pairFor(address tokenA, address tokenB) public view returns (address pair) {
|
||||
pair = factory.getPair(tokenA, tokenB);
|
||||
require(pair != address(0), "Router: no pair");
|
||||
}
|
||||
|
||||
function getReserves(address tokenA, address tokenB) public view returns (uint256 reserveA, uint256 reserveB) {
|
||||
(address token0,) = sortTokens(tokenA, tokenB);
|
||||
(uint112 r0, uint112 r1,) = IgneumPair(pairFor(tokenA, tokenB)).getReserves();
|
||||
(reserveA, reserveB) = tokenA == token0 ? (r0, r1) : (r1, r0);
|
||||
}
|
||||
|
||||
function getAmountsOut(uint256 amountIn, address[] memory path) public view returns (uint256[] memory amounts) {
|
||||
require(path.length >= 2, "Router: invalid path");
|
||||
amounts = new uint256[](path.length);
|
||||
amounts[0] = amountIn;
|
||||
for (uint256 i; i < path.length - 1; i++) {
|
||||
(uint256 reserveIn, uint256 reserveOut) = getReserves(path[i], path[i + 1]);
|
||||
amounts[i + 1] = getAmountOut(amounts[i], reserveIn, reserveOut);
|
||||
}
|
||||
}
|
||||
|
||||
function getAmountsIn(uint256 amountOut, address[] memory path) public view returns (uint256[] memory amounts) {
|
||||
require(path.length >= 2, "Router: invalid path");
|
||||
amounts = new uint256[](path.length);
|
||||
amounts[amounts.length - 1] = amountOut;
|
||||
for (uint256 i = path.length - 1; i > 0; i--) {
|
||||
(uint256 reserveIn, uint256 reserveOut) = getReserves(path[i - 1], path[i]);
|
||||
amounts[i - 1] = getAmountIn(amounts[i], reserveIn, reserveOut);
|
||||
}
|
||||
}
|
||||
|
||||
// ---- liquidity ----
|
||||
|
||||
function _addLiquidity(address tokenA, address tokenB, uint256 amountADesired, uint256 amountBDesired, uint256 amountAMin, uint256 amountBMin)
|
||||
private
|
||||
returns (uint256 amountA, uint256 amountB)
|
||||
{
|
||||
if (factory.getPair(tokenA, tokenB) == address(0)) {
|
||||
factory.createPair(tokenA, tokenB);
|
||||
}
|
||||
(uint256 reserveA, uint256 reserveB) = getReserves(tokenA, tokenB);
|
||||
if (reserveA == 0 && reserveB == 0) {
|
||||
(amountA, amountB) = (amountADesired, amountBDesired);
|
||||
} else {
|
||||
uint256 amountBOptimal = quote(amountADesired, reserveA, reserveB);
|
||||
if (amountBOptimal <= amountBDesired) {
|
||||
require(amountBOptimal >= amountBMin, "Router: insufficient B amount");
|
||||
(amountA, amountB) = (amountADesired, amountBOptimal);
|
||||
} else {
|
||||
uint256 amountAOptimal = quote(amountBDesired, reserveB, reserveA);
|
||||
require(amountAOptimal <= amountADesired && amountAOptimal >= amountAMin, "Router: insufficient A amount");
|
||||
(amountA, amountB) = (amountAOptimal, amountBDesired);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function addLiquidity(
|
||||
address tokenA,
|
||||
address tokenB,
|
||||
uint256 amountADesired,
|
||||
uint256 amountBDesired,
|
||||
uint256 amountAMin,
|
||||
uint256 amountBMin,
|
||||
address to,
|
||||
uint256 deadline
|
||||
) external ensure(deadline) returns (uint256 amountA, uint256 amountB, uint256 liquidity) {
|
||||
(amountA, amountB) = _addLiquidity(tokenA, tokenB, amountADesired, amountBDesired, amountAMin, amountBMin);
|
||||
address pair = pairFor(tokenA, tokenB);
|
||||
_pull(tokenA, msg.sender, pair, amountA);
|
||||
_pull(tokenB, msg.sender, pair, amountB);
|
||||
liquidity = IgneumPair(pair).mint(to);
|
||||
}
|
||||
|
||||
function addLiquidityIGN(address token, uint256 amountTokenDesired, uint256 amountTokenMin, uint256 amountIGNMin, address to, uint256 deadline)
|
||||
external
|
||||
payable
|
||||
ensure(deadline)
|
||||
returns (uint256 amountToken, uint256 amountIGN, uint256 liquidity)
|
||||
{
|
||||
(amountToken, amountIGN) = _addLiquidity(token, WIGN, amountTokenDesired, msg.value, amountTokenMin, amountIGNMin);
|
||||
address pair = pairFor(token, WIGN);
|
||||
_pull(token, msg.sender, pair, amountToken);
|
||||
IWIGN(WIGN).deposit{value: amountIGN}();
|
||||
require(IWIGN(WIGN).transfer(pair, amountIGN), "Router: WIGN transfer failed");
|
||||
liquidity = IgneumPair(pair).mint(to);
|
||||
if (msg.value > amountIGN) _sendIGN(msg.sender, msg.value - amountIGN);
|
||||
}
|
||||
|
||||
function removeLiquidity(address tokenA, address tokenB, uint256 liquidity, uint256 amountAMin, uint256 amountBMin, address to, uint256 deadline)
|
||||
public
|
||||
ensure(deadline)
|
||||
returns (uint256 amountA, uint256 amountB)
|
||||
{
|
||||
address pair = pairFor(tokenA, tokenB);
|
||||
_pull(pair, msg.sender, pair, liquidity);
|
||||
(uint256 amount0, uint256 amount1) = IgneumPair(pair).burn(to);
|
||||
(address token0,) = sortTokens(tokenA, tokenB);
|
||||
(amountA, amountB) = tokenA == token0 ? (amount0, amount1) : (amount1, amount0);
|
||||
require(amountA >= amountAMin, "Router: insufficient A amount");
|
||||
require(amountB >= amountBMin, "Router: insufficient B amount");
|
||||
}
|
||||
|
||||
function removeLiquidityIGN(address token, uint256 liquidity, uint256 amountTokenMin, uint256 amountIGNMin, address to, uint256 deadline)
|
||||
external
|
||||
ensure(deadline)
|
||||
returns (uint256 amountToken, uint256 amountIGN)
|
||||
{
|
||||
(amountToken, amountIGN) = removeLiquidity(token, WIGN, liquidity, amountTokenMin, amountIGNMin, address(this), deadline);
|
||||
require(IERC20Router(token).transfer(to, amountToken), "Router: token transfer failed");
|
||||
IWIGN(WIGN).withdraw(amountIGN);
|
||||
_sendIGN(to, amountIGN);
|
||||
}
|
||||
|
||||
// ---- swaps ----
|
||||
|
||||
function _swap(uint256[] memory amounts, address[] memory path, address to_) private {
|
||||
for (uint256 i; i < path.length - 1; i++) {
|
||||
(address input, address output) = (path[i], path[i + 1]);
|
||||
(address token0,) = sortTokens(input, output);
|
||||
uint256 amountOut = amounts[i + 1];
|
||||
(uint256 amount0Out, uint256 amount1Out) = input == token0 ? (uint256(0), amountOut) : (amountOut, uint256(0));
|
||||
address to = i < path.length - 2 ? pairFor(output, path[i + 2]) : to_;
|
||||
IgneumPair(pairFor(input, output)).swap(amount0Out, amount1Out, to);
|
||||
}
|
||||
}
|
||||
|
||||
function swapExactTokensForTokens(uint256 amountIn, uint256 amountOutMin, address[] calldata path, address to, uint256 deadline)
|
||||
external
|
||||
ensure(deadline)
|
||||
returns (uint256[] memory amounts)
|
||||
{
|
||||
amounts = getAmountsOut(amountIn, path);
|
||||
require(amounts[amounts.length - 1] >= amountOutMin, "Router: insufficient output amount");
|
||||
_pull(path[0], msg.sender, pairFor(path[0], path[1]), amounts[0]);
|
||||
_swap(amounts, path, to);
|
||||
}
|
||||
|
||||
function swapTokensForExactTokens(uint256 amountOut, uint256 amountInMax, address[] calldata path, address to, uint256 deadline)
|
||||
external
|
||||
ensure(deadline)
|
||||
returns (uint256[] memory amounts)
|
||||
{
|
||||
amounts = getAmountsIn(amountOut, path);
|
||||
require(amounts[0] <= amountInMax, "Router: excessive input amount");
|
||||
_pull(path[0], msg.sender, pairFor(path[0], path[1]), amounts[0]);
|
||||
_swap(amounts, path, to);
|
||||
}
|
||||
|
||||
function swapExactIGNForTokens(uint256 amountOutMin, address[] calldata path, address to, uint256 deadline)
|
||||
external
|
||||
payable
|
||||
ensure(deadline)
|
||||
returns (uint256[] memory amounts)
|
||||
{
|
||||
require(path[0] == WIGN, "Router: invalid path");
|
||||
amounts = getAmountsOut(msg.value, path);
|
||||
require(amounts[amounts.length - 1] >= amountOutMin, "Router: insufficient output amount");
|
||||
IWIGN(WIGN).deposit{value: amounts[0]}();
|
||||
require(IWIGN(WIGN).transfer(pairFor(path[0], path[1]), amounts[0]), "Router: WIGN transfer failed");
|
||||
_swap(amounts, path, to);
|
||||
}
|
||||
|
||||
function swapExactTokensForIGN(uint256 amountIn, uint256 amountOutMin, address[] calldata path, address to, uint256 deadline)
|
||||
external
|
||||
ensure(deadline)
|
||||
returns (uint256[] memory amounts)
|
||||
{
|
||||
require(path[path.length - 1] == WIGN, "Router: invalid path");
|
||||
amounts = getAmountsOut(amountIn, path);
|
||||
require(amounts[amounts.length - 1] >= amountOutMin, "Router: insufficient output amount");
|
||||
_pull(path[0], msg.sender, pairFor(path[0], path[1]), amounts[0]);
|
||||
_swap(amounts, path, address(this));
|
||||
IWIGN(WIGN).withdraw(amounts[amounts.length - 1]);
|
||||
_sendIGN(to, amounts[amounts.length - 1]);
|
||||
}
|
||||
|
||||
// ---- transfers ----
|
||||
|
||||
function _pull(address token, address from, address to, uint256 value) private {
|
||||
(bool ok, bytes memory data) = token.call(abi.encodeWithSelector(IERC20Router.transferFrom.selector, from, to, value));
|
||||
require(ok && (data.length == 0 || abi.decode(data, (bool))), "Router: transferFrom failed");
|
||||
}
|
||||
|
||||
function _sendIGN(address to, uint256 value) private {
|
||||
(bool ok,) = to.call{value: value}("");
|
||||
require(ok, "Router: IGN send failed");
|
||||
}
|
||||
}
|
||||
32
contracts/dex/src/TestToken.sol
Normal file
32
contracts/dex/src/TestToken.sol
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.24;
|
||||
|
||||
import {ERC20} from "./ERC20.sol";
|
||||
|
||||
/// A test token with its own faucet: anyone takes DRIP tokens once an hour. Devnet 3, test tokens, no value.
|
||||
contract TestToken is ERC20 {
|
||||
uint256 public constant DRIP = 1_000 ether;
|
||||
uint256 public constant DRIP_INTERVAL = 1 hours;
|
||||
mapping(address => uint256) public lastDrip;
|
||||
|
||||
event Drip(address indexed to, uint256 value);
|
||||
|
||||
constructor(string memory name_, string memory symbol_) ERC20(name_, symbol_) {}
|
||||
|
||||
/// Mints DRIP tokens to the caller; refused inside DRIP_INTERVAL of the caller's last drip.
|
||||
function drip() external {
|
||||
uint256 last = lastDrip[msg.sender];
|
||||
require(last == 0 || block.timestamp >= last + DRIP_INTERVAL, "TestToken: one drip an hour");
|
||||
lastDrip[msg.sender] = block.timestamp;
|
||||
_mint(msg.sender, DRIP);
|
||||
emit Drip(msg.sender, DRIP);
|
||||
}
|
||||
|
||||
/// Seconds until the caller may drip again (0 when it may).
|
||||
function dripWait(address who) external view returns (uint256) {
|
||||
uint256 last = lastDrip[who];
|
||||
if (last == 0) return 0;
|
||||
uint256 next = last + DRIP_INTERVAL;
|
||||
return block.timestamp >= next ? 0 : next - block.timestamp;
|
||||
}
|
||||
}
|
||||
27
contracts/dex/src/WIGN.sol
Normal file
27
contracts/dex/src/WIGN.sol
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.24;
|
||||
|
||||
import {ERC20} from "./ERC20.sol";
|
||||
|
||||
/// Wrapped IGN, the WETH9 shape: one WIGN per IGN held by this contract, minted on deposit and burned on withdraw.
|
||||
/// Devnet 3, test tokens, no value.
|
||||
contract WIGN is ERC20("Wrapped IGN", "WIGN") {
|
||||
event Deposit(address indexed to, uint256 value);
|
||||
event Withdrawal(address indexed from, uint256 value);
|
||||
|
||||
receive() external payable {
|
||||
deposit();
|
||||
}
|
||||
|
||||
function deposit() public payable {
|
||||
_mint(msg.sender, msg.value);
|
||||
emit Deposit(msg.sender, msg.value);
|
||||
}
|
||||
|
||||
function withdraw(uint256 value) external {
|
||||
_burn(msg.sender, value);
|
||||
emit Withdrawal(msg.sender, value);
|
||||
(bool ok,) = msg.sender.call{value: value}("");
|
||||
require(ok, "WIGN: send failed");
|
||||
}
|
||||
}
|
||||
137
contracts/dex/test/Dex.t.sol
Normal file
137
contracts/dex/test/Dex.t.sol
Normal file
|
|
@ -0,0 +1,137 @@
|
|||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.24;
|
||||
|
||||
import {Vm, VM_ADDRESS} from "./Vm.sol";
|
||||
import {WIGN} from "../src/WIGN.sol";
|
||||
import {TestToken} from "../src/TestToken.sol";
|
||||
import {IgneumFactory, IgneumPair} from "../src/IgneumPair.sol";
|
||||
import {IgneumRouter} from "../src/IgneumRouter.sol";
|
||||
|
||||
/// The AMM end to end on Foundry's EVM: pair creation, liquidity in and out, token and IGN swaps, the faucet's
|
||||
/// hour, the k check. Every number is a test number: Devnet 3, test tokens, no value.
|
||||
contract DexTest {
|
||||
Vm constant vm = Vm(VM_ADDRESS);
|
||||
|
||||
WIGN wign;
|
||||
TestToken tta;
|
||||
TestToken ttb;
|
||||
IgneumFactory factory;
|
||||
IgneumRouter router;
|
||||
address alice = address(0xA11CE);
|
||||
address bob = address(0xB0B);
|
||||
|
||||
receive() external payable {}
|
||||
|
||||
function setUp() public {
|
||||
wign = new WIGN();
|
||||
tta = new TestToken("Test Token A", "TTA");
|
||||
ttb = new TestToken("Test Token B", "TTB");
|
||||
factory = new IgneumFactory();
|
||||
router = new IgneumRouter(address(factory), address(wign));
|
||||
vm.deal(alice, 1_000 ether);
|
||||
vm.deal(bob, 1_000 ether);
|
||||
}
|
||||
|
||||
function _drip(address who) internal {
|
||||
vm.startPrank(who);
|
||||
tta.drip();
|
||||
ttb.drip();
|
||||
tta.approve(address(router), type(uint256).max);
|
||||
ttb.approve(address(router), type(uint256).max);
|
||||
vm.stopPrank();
|
||||
}
|
||||
|
||||
function _seed() internal returns (address pairAB, address pairAW) {
|
||||
_drip(alice);
|
||||
vm.startPrank(alice);
|
||||
router.addLiquidity(address(tta), address(ttb), 500 ether, 500 ether, 0, 0, alice, block.timestamp + 60);
|
||||
router.addLiquidityIGN{value: 100 ether}(address(tta), 500 ether, 0, 0, alice, block.timestamp + 60);
|
||||
vm.stopPrank();
|
||||
pairAB = factory.getPair(address(tta), address(ttb));
|
||||
pairAW = factory.getPair(address(tta), address(wign));
|
||||
}
|
||||
|
||||
function test_faucet_drips_once_an_hour() public {
|
||||
vm.prank(bob);
|
||||
tta.drip();
|
||||
require(tta.balanceOf(bob) == 1_000 ether, "drip amount");
|
||||
vm.prank(bob);
|
||||
vm.expectRevert(bytes("TestToken: one drip an hour"));
|
||||
tta.drip();
|
||||
vm.warp(block.timestamp + 1 hours);
|
||||
vm.prank(bob);
|
||||
tta.drip();
|
||||
require(tta.balanceOf(bob) == 2_000 ether, "second drip");
|
||||
}
|
||||
|
||||
function test_add_liquidity_creates_pairs_and_mints() public {
|
||||
(address pairAB, address pairAW) = _seed();
|
||||
require(pairAB != address(0) && pairAW != address(0) && pairAB != pairAW, "pairs");
|
||||
require(factory.allPairsLength() == 2, "two pairs");
|
||||
(uint256 rA, uint256 rB) = router.getReserves(address(tta), address(ttb));
|
||||
require(rA == 500 ether && rB == 500 ether, "AB reserves");
|
||||
(uint256 rT, uint256 rW) = router.getReserves(address(tta), address(wign));
|
||||
require(rT == 500 ether && rW == 100 ether, "AW reserves");
|
||||
require(IgneumPair(pairAB).balanceOf(alice) == 500 ether - 1000, "LP minus the locked minimum");
|
||||
require(IgneumPair(pairAB).balanceOf(address(0xdead)) == 1000, "locked minimum");
|
||||
require(wign.balanceOf(pairAW) == 100 ether, "WIGN held by the pair");
|
||||
}
|
||||
|
||||
function test_swap_exact_tokens_for_tokens_keeps_k() public {
|
||||
(address pairAB,) = _seed();
|
||||
_drip(bob);
|
||||
address[] memory path = new address[](2);
|
||||
path[0] = address(tta);
|
||||
path[1] = address(ttb);
|
||||
uint256[] memory quoted = router.getAmountsOut(10 ether, path);
|
||||
// 10 in at 0.3 percent on 500/500: 10*997*500 / (500*1000 + 10*997) tokens
|
||||
require(quoted[1] == 9775084808910328058, "quote");
|
||||
(uint112 r0b, uint112 r1b,) = IgneumPair(pairAB).getReserves();
|
||||
vm.prank(bob);
|
||||
uint256[] memory amounts = router.swapExactTokensForTokens(10 ether, quoted[1], path, bob, block.timestamp + 60);
|
||||
require(amounts[1] == quoted[1], "swap matches the quote");
|
||||
require(ttb.balanceOf(bob) == 1_000 ether + quoted[1], "bob received");
|
||||
(uint112 r0a, uint112 r1a,) = IgneumPair(pairAB).getReserves();
|
||||
require(uint256(r0a) * uint256(r1a) >= uint256(r0b) * uint256(r1b), "k did not fall");
|
||||
}
|
||||
|
||||
function test_swap_ign_both_ways() public {
|
||||
_seed();
|
||||
address[] memory path = new address[](2);
|
||||
path[0] = address(wign);
|
||||
path[1] = address(tta);
|
||||
uint256 before = tta.balanceOf(bob);
|
||||
vm.prank(bob);
|
||||
uint256[] memory amounts = router.swapExactIGNForTokens{value: 1 ether}(0, path, bob, block.timestamp + 60);
|
||||
require(tta.balanceOf(bob) == before + amounts[1] && amounts[1] > 4.9 ether && amounts[1] < 5 ether, "IGN to TTA");
|
||||
path[0] = address(tta);
|
||||
path[1] = address(wign);
|
||||
uint256 ignBefore = bob.balance;
|
||||
vm.startPrank(bob);
|
||||
tta.approve(address(router), type(uint256).max);
|
||||
uint256[] memory back = router.swapExactTokensForIGN(amounts[1], 0, path, bob, block.timestamp + 60);
|
||||
vm.stopPrank();
|
||||
require(bob.balance == ignBefore + back[1] && back[1] < 1 ether && back[1] > 0.99 ether, "TTA to IGN");
|
||||
}
|
||||
|
||||
function test_remove_liquidity_returns_both_tokens() public {
|
||||
(address pairAB,) = _seed();
|
||||
uint256 lp = IgneumPair(pairAB).balanceOf(alice);
|
||||
vm.startPrank(alice);
|
||||
IgneumPair(pairAB).approve(address(router), lp);
|
||||
(uint256 a, uint256 b) = router.removeLiquidity(address(tta), address(ttb), lp, 0, 0, alice, block.timestamp + 60);
|
||||
vm.stopPrank();
|
||||
require(a == 500 ether - 1000 && b == 500 ether - 1000, "pro rata minus the locked share");
|
||||
require(IgneumPair(pairAB).balanceOf(alice) == 0, "LP burned");
|
||||
}
|
||||
|
||||
function test_expired_deadline_is_refused() public {
|
||||
_seed();
|
||||
address[] memory path = new address[](2);
|
||||
path[0] = address(tta);
|
||||
path[1] = address(ttb);
|
||||
vm.prank(alice);
|
||||
vm.expectRevert(bytes("Router: expired"));
|
||||
router.swapExactTokensForTokens(1 ether, 0, path, alice, block.timestamp - 1);
|
||||
}
|
||||
}
|
||||
23
contracts/dex/test/Vm.sol
Normal file
23
contracts/dex/test/Vm.sol
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.24;
|
||||
|
||||
/// The Foundry cheatcodes this project uses, declared here so the tree needs no remote dependency.
|
||||
interface Vm {
|
||||
function startBroadcast(uint256 privateKey) external;
|
||||
function stopBroadcast() external;
|
||||
function envUint(string calldata name) external view returns (uint256);
|
||||
function envAddress(string calldata name) external view returns (address);
|
||||
function envOr(string calldata name, string calldata defaultValue) external view returns (string memory);
|
||||
function toString(address value) external pure returns (string memory);
|
||||
function toString(uint256 value) external pure returns (string memory);
|
||||
function writeFile(string calldata path, string calldata data) external;
|
||||
function deal(address who, uint256 newBalance) external;
|
||||
function prank(address msgSender) external;
|
||||
function startPrank(address msgSender) external;
|
||||
function stopPrank() external;
|
||||
function warp(uint256 newTimestamp) external;
|
||||
function expectRevert(bytes calldata revertData) external;
|
||||
function addr(uint256 privateKey) external pure returns (address);
|
||||
}
|
||||
|
||||
address constant VM_ADDRESS = address(uint160(uint256(keccak256("hevm cheat code"))));
|
||||
|
|
@ -18,7 +18,7 @@ v5 list at 3.0 percent); F2 PASS, effort-bounded; F3 PASS; F4 PASS against class
|
|||
FIXED-AND-PASSED (the F2 hour skipped by decision); F6 PASS (the worst of 10^5 programs 8.708 ms on the half-core
|
||||
proxy; O-1.14 closed on an i7-9700K); F7 PASS on all three sub-rows (the era VDF in the node, 0 of 6 re-rolls); F8
|
||||
FIXED-AND-PASSED in class v4 sub-version 3 at 017e7037 (AP-F8-1, AP-F8-2, AP-F8-3 ours and closed; the four-seed
|
||||
unattributed tail named); F9 PASS on (a) and (c), (b) closed by the same fix; F10 PASS. Frozen generator: class v4
|
||||
tail attributed to per-site bucket concentration, 8 October 2026); F9 PASS on (a) and (c), (b) closed by the same fix; F10 PASS. Frozen generator: class v4
|
||||
sub-version 3, igneum-pow 017e70376489251e18564c0abce7e466e606c8b3, devnet epoch-0 id a785001687d8688a. The
|
||||
freeze tag `cryptanalysis-target-1` is the coordinator's cut on this record; the era VDF precondition is met (F7 a). Main checks every number
|
||||
against the log before quoting it to the founder.
|
||||
|
|
@ -34,7 +34,7 @@ against the log before quoting it to the founder.
|
|||
| F5 | Chip-model sweep + AWS F2 FPGA hour | evidence row 17 holds across the sweep; FPGA row under 27 M reads/s/W | sweep: 2.1x at k=1 GDDR7 reproduces, 3.2x at k=0.5, 4.1x at k=0.3 (matches ledger M32); FPGA row 2.3 to 2.9 G/s, 10 to 20 M reads/s/W (literature). FINDING: the k=0.33 figure is framed as the X9's measured core (M32) and a "measured class" (ladder branch §5a); the X9 was withdrawn before launch and never benchmarked. F2 hour SKIPPED: no AWS account | FIXED-AND-PASSED (sweep PASS; AP-F5-1 fixed and re-gated 7 Oct 2026: chip section re-run 2.1x at k=1 unchanged, identity grep 0 hits, site lane concurred); F2 hour SKIPPED-BY-DECISION (the founder, 7 Oct 2026, 09:5x UK; plan 4.2 row F5 is the sweep only at 3714c2a0; the FPGA row stays the JEDEC-ceiling model row labelled unmeasured) |
|
||||
| F6 | Verifier worst case over 10^5 programs + O-1.14 laptop run | worst program under 10 ms cold on the half-core proxy and the laptop | 100,000 programs ranked, 50,000 timed cold one-core (worst 6.194 ms), the worst 200 re-timed and the worst 1,000 timed on the half-core proxy under the per-core lease (core 40 at 3,799.9 MHz): worst 8.708 ms (`attack-f6/87142`), 1.29 ms under the gate, every half-core reading under 9 ms; dr736 fails as it must (15.49). O-1.14 CLOSED on an i7-9700K (v4 6.334 ms cold max, dr736 10.04 fails). Ladder ceiling from the worst program on the half-core proxy: N about 300,000, so rung 2 admissible, rung 3 not. Record `docs/analysis/attack-pass/f6-verifier.md` | PASS |
|
||||
| F7 | Era-draw bias harness + 2^20 era-seed census | no re-roll inside the publish window; no era class with gain over 1.1x over 2^-20 | (b) census PASS at 2^24 seeds (no class over 1.1x, stride bijective, R, pos and M uniform, planted cases fire); (c) 64-bit day-key seeding PASS (0 collisions in 2^17); (a) PASS with the era VDF in the node (era-vdf lane, fork era-vdf-node 394a5902 on release-0.3.20-node c4459193, behind era_vdf_activation_daa; master a4eaf766 carries the spec text, `docs/analysis/era-vdf-2026-10-07.md` and `tools/era-vdf/reroll.mjs`): against the real era cut on three fast-time nodes the re-roll harness fires with the VDF off (6 of 6 cuts) and is silent with it on (0 of 6; the adversary's 5.4 to 6.6 s evaluation against a 1 s block interval, the honest chain 3 to 10 blocks ahead, three nodes agreeing on every era seed); the delay is 517 s on the fastest prover measured (chiavdf NUDUPL over GMP, 208.8K squarings/s) at T = 108,000,000, 259x the 2 s window. Open, not a gate: the verify is 22 ms against the 10 ms target (O-4.6, 0.3.22). Record `docs/analysis/attack-pass/f7-era.md` | PASS (a, b, c) |
|
||||
| F8 | Uniformity censuses (line-index 2^28, distinct lines, cross-hash histogram) | uniform within the window model of spec 1.13.1, layer 8; the excess beyond it within 6 sigma over 64 seeds; no hot set under 1% of items beyond the model | line index PASS at 2^28. The 6 Oct stream: 31 of 64 seeds over 1.2x (AP-F8-1, the lossy load source). Sub-version 1 (8c728ca3): 11 of 64. Sub-version 2 (07a809a7 / 8bdcbdd8): 9 of 64; AP-F8-2 (exhaustion) closed there, 0 of 10^6. Sub-version 3 (017e7037: the acceptance executing the shadow block, AP-F8-3; the shared-operand rule; (c'') the distinct-index ratio): 60 of 64 under 1.2x, the four over the named unattributed tail at 1.22x to 1.50x with no chip consequence; 0 exhausted in 24,631 chain-shaped seeds, the draw total by construction. Record `docs/analysis/attack-pass/f8-uniform.md` | FIXED-AND-PASSED (sub-version 3, 017e7037, the frozen generator) |
|
||||
| F8 | Uniformity censuses (line-index 2^28, distinct lines, cross-hash histogram) | uniform within the window model of spec 1.13.1, layer 8; the excess beyond it within 6 sigma over 64 seeds; no hot set under 1% of items beyond the model | line index PASS at 2^28. The 6 Oct stream: 31 of 64 seeds over 1.2x (AP-F8-1, the lossy load source). Sub-version 1 (8c728ca3): 11 of 64. Sub-version 2 (07a809a7 / 8bdcbdd8): 9 of 64; AP-F8-2 (exhaustion) closed there, 0 of 10^6. Sub-version 3 (017e7037: the acceptance executing the shadow block, AP-F8-3; the shared-operand rule; (c'') the distinct-index ratio): 60 of 64 under 1.2x, the four over the named tail at 1.22x to 1.50x, attributed 8 October 2026 to a quarter-bit bucket concentration at one narrow-window site each, with no chip consequence; 0 exhausted in 24,631 chain-shaped seeds, the draw total by construction. Record `docs/analysis/attack-pass/f8-uniform.md` | FIXED-AND-PASSED (sub-version 3, 017e7037, the frozen generator) |
|
||||
| F9 | Acceptance edges (39) + header grinding on an RTX 5090 | zero passing programs with a hot set under 1%; grinding gain under 1% of rate | (a) edges on generator 4 over 10^5 seeds: 34 disagreements in 105,064 candidates (29 const_bit, 4 bias, 1 lane_const), every one a one-bit or sampling-noise property moving the choice to an attempt both stand-ins accept, nothing in the attacker's favour: PASS; (b) hot-set search over 10^6 seeds: 11,696 passing programs (1.17%) concentrate 1% or more of reads on a hot set, worst 17.3%: FINDING, the same or-saturation load-source class as AP-F8-1 found by a second harness (F9-1 merged into AP-F8-1), re-gated on the amended stream; (c) grinding on the 5090: +0.004% at K = 2^14, ceiling +43%: PASS. Record `docs/analysis/attack-pass/f9-grind.md` | (a) PASS; (b) the AP-F8-1 class on the 6 Oct stream, closed by sub-version 3 (F8's census is the re-gate instrument; this harness's hot-share metric counts the era's windows); (c) PASS |
|
||||
| F10 | Ladder signal monotonicity harness | no step without 90% over 7 windows in either direction | known-fail fails, known pass passes; new cases on the exact-share driver: 89% up holds (no step), 89 then 90% down with restarts steps only at 90% after the 7-window cool-down, the floor holds under 100% down (never below rung 0); decision per seed block memoised, identical after a restart, never differs between nodes; 19 of 19 checks per case. Two items to main, not findings: a stale commit string in the ladder lane's igneumd, and proof-synced nodes deciding rung 0 until the witness lands (a precondition line for spec 01). Record `docs/analysis/attack-pass/f10-ladder.md` | PASS |
|
||||
|
||||
|
|
@ -289,7 +289,7 @@ attack-pass) by the coordinator's exception rule; nothing touches GitHub.
|
|||
|---|---|---|---|
|
||||
| F4 weak-day census | 2^24 chain days from 20,729 under `Shape::for_class(&V5_CLASS)`, box 1, 18:5x to 19:1x UTC | byte-identical to the class v4 census: M2 (DSP-bound) 0 of 2^24 days over 1.1x; M1 (LUT adders) 5,476 days, 3.264e-4, the same bounded tail, worst day 4,819,563 at cost 197 against the median 231; planted weak days fire (mul1all M2 unbounded, mulnaf 1.333x). The day-key draw depends on the mixer shape alone and v5 adds only the state flag, so identity is the expected and the measured result | PASS (v4's reading; AP-F4-1 stays the next-class item) |
|
||||
| F8 hot-set gate (pre-freeze reading) | 64 seeds at 2^24, chain path, v5 with the dn3 state, box 2: hand-started at 18:47 UTC (11 seeds, killed on the coordinator's rule: every hand-started run off the boxes, loads 601 and 401), re-queued through `lease pool 64` at 19:23 UTC (17 more seeds), released at 19:4x UTC on the Counter ASIC lane's yield so the class v5 (c''') census, the 0.3.24 board's critical path, could take the pool | every seed read equals sub-version 3's seed for seed (0.9915x to 1.144x, p10 1.50x), as the v5 lane predicted: the leaves change the words, not the read addresses | READING, not the gate line |
|
||||
| F8 hot-set gate, the frozen tip (THE GATE LINE) | igneum-pow class-v5 1c420786 (the 0.995 per-site floor (c''') on sub-version 3's rules; binary sha256 0f5c98dc41a1b3aa..., run from a copy); pairing: the library draws the dn3 epoch-0 program as e5a4ac5978462156, the harness validates bit for bit against the library on the dn3 state (0 mismatches on 66 validation lines); 64 seeds p2 to p65 at 2^24 nonces, chain path, the v5 dataset from v5-dn3-epoch0's state.igsd1, window-model control, build-2 under `lease pool` class v5 as two halves of 32 (ended 21:58:43Z and 22:03:21Z) | 61 of 64 under 1.2x of the window model (0.9919x to 1.144x, p75 1.0024x); 3 over, all inside the named four-seed residue and none new: p10 1.5047x (0x4018f5, 346 reads of 2^31, no predicted source), p8 1.3787x (0x839d33, 419), p4 1.2166x (0x400197, 363); p34 0.9997x under the (c''') floor; p23 1.0000x, p19 0.9997x, p15 0.9998x, p18 1.0001x, p56 1.0000x. Seed for seed the ratios equal sub-version 3's within 0.001 except where the floor moved a draw: the state leaves change the words, not the read addresses. Nothing to a chip | PASS (the known residue p4, p8, p10 unattributed and chased) |
|
||||
| F8 hot-set gate, the frozen tip (THE GATE LINE) | igneum-pow class-v5 1c420786 (the 0.995 per-site floor (c''') on sub-version 3's rules; binary sha256 0f5c98dc41a1b3aa..., run from a copy); pairing: the library draws the dn3 epoch-0 program as e5a4ac5978462156, the harness validates bit for bit against the library on the dn3 state (0 mismatches on 66 validation lines); 64 seeds p2 to p65 at 2^24 nonces, chain path, the v5 dataset from v5-dn3-epoch0's state.igsd1, window-model control, build-2 under `lease pool` class v5 as two halves of 32 (ended 21:58:43Z and 22:03:21Z) | 61 of 64 under 1.2x of the window model (0.9919x to 1.144x, p75 1.0024x); 3 over, all inside the named four-seed residue and none new: p10 1.5047x (0x4018f5, 346 reads of 2^31, no predicted source), p8 1.3787x (0x839d33, 419), p4 1.2166x (0x400197, 363); p34 0.9997x under the (c''') floor; p23 1.0000x, p19 0.9997x, p15 0.9998x, p18 1.0001x, p56 1.0000x. Seed for seed the ratios equal sub-version 3's within 0.001 except where the floor moved a draw: the state leaves change the words, not the read addresses. Nothing to a chip | PASS (the known residue p4, p8, p10, attributed 8 October 2026 to per-site bucket concentration; the largest-bucket bound is a next class's item) |
|
||||
| F9 exhaustion count, the frozen tip (A GATE LINE for the 0.3.24 move) | 10^5 chain-shaped seeds on the v5 chain path (era-composed class, `--chain`) with the dn3 state at igneum-pow class-v5 1c420786, pairing e5a4ac5978462156, build-1, ten chunks of 10,000 under `lease pool 4` (chunks 1, 3, 5 to 9 under class v5; chunks 0, 2, 4 re-leased under class release on the coordinator's order; 14,477 to 14,480 s per chunk, about 1.45 s per seed); binary copied into the run dir; interim line sent at 00:55 UTC (seeds drawn, 0 exhausted, 0 panics, max 30, F1 0 failures), which cleared the move; last chunk written 02:34:54 UTC | 100,000 of 100,000 seeds drawn, 0 exhausted, 0 panics, 0 past attempt index 31, max attempt index 30; histogram by attempt index (0 = accepted on the first draw) 0: 31,454; 1: 21,460; 2: 14,660; 3: 10,263; 4: 7,047; 5: 4,701; 6: 3,297; 7: 2,256; 8: 1,532; 9: 1,027; 10: 702; 11: 509; 12: 365; 13: 216; 14: 153; 15: 103; 16: 80; 17: 56; 18: 39; 19: 20; 20: 24; 21: 9; 22: 6; 23: 9; 24: 3; 25: 4; 26: 2; 27: 1; 29: 1; 30: 1; first-draw acceptance 0.3145, mean attempt index 2.185 (3.185 draws per seed), 4,862 seeds (4.86 percent) at index 8 or above, 255 (0.255 percent) at 16 or above; the 256-attempt cap and the deterministic last resort never reached. Meaning per tier: no epoch seed in 10^5 fails to draw a program, so the liveness halt of AP-F8-2 has no observed case on the frozen tip at this count (the bound it supports is under 3e-5 per seed at 95 percent, about one epoch in 33,000 at worst; a halt a node operator would see as a stuck epoch, a miner as a dead epoch, a holder as a paused chain), and the draw cost stays at about 3.2 candidates per epoch for every node | PASS (0 of 10^5; the record `f9-grind.md`, section (d)) |
|
||||
| F1 shadow redundancy, the frozen tip (A GATE LINE for the 0.3.24 move) | 10^5 class v5 programs through the string-seed path (`generate_from_seed_bytes_program_class`, class V5, every candidate draw through the (c''') floor over 2^20) at igneum-pow class-v5 1c420786, pairing e5a4ac5978462156, build-1, `lease pool 16` class release (cores 8 to 23, re-leased 22:34:05 UTC), binary sha256 bb70bbf69a4b3223... copied into `frozen-1c420786-f1/bin`; 20,774 s of census (5 h 46 min; about 5 core-s per program, the (c''') draw cost), census.csv (sha256 4e34b669f2f5c680..., 100,000 rows) written 04:20 UTC on 8 October 2026 | 100,000 of 100,000 programs; instructions saved min 0.000, mean 0.623, max 4.688 percent (worst `attack-f1/95060` at attempt 0, 6,912 to 6,588 per iteration; `81748`, `66933`, `3006` at the same 4.688; next 4.311); chip-view ops saved mean 0.520, max 4.783; programs over 5 percent 0, over 10 percent 0; soundness: differential mismatches 0 of 100,000 (8 random states each), verifier mismatches 0 of 100,000; 0 panics; histogram of saved, 0.5 percent bins from 0: 55,241; 20,597; 11,762; 9,851; 1,484; 656; 259; 133; 13; 4; 0; 0; draw attempts per program: index 0 31,630, max 30 (the same shape as F9's). Against the v4 10^5 (max 5.078, the AP-F1-1 letter miss): the v5 tip's worst sits 0.39 points under the letter, the two top bins are empty, and the mean is unchanged (0.617 to 0.623), so the v5 leaves add no redundancy and remove the one letter miss. Meaning per tier: the shadow block of every drawn program stays within 5 percent of its naive count under the harness's rules and the honest compiler finds the same shortcuts, so no chip gets a shadow-side discount (a miner on a card pays the full block, a hypothetical ASIC gains nothing here) and the chain's verifier agrees with the harness on every program (0 mismatches), so no node disagrees with another on any drawn block. Harness gap and its fix: section 12 of the record (the running census was the old binary; the flush is in 18a9c04a for every census after it) | PASS (0 of 10^5 over the letter; AP-F1-1 FIXED-AND-PASSED on v5 at this count; the record `f1-shadow.md`, section 13) |
|
||||
| F4 weak-day census, the post-freeze commit | 2^24 chain days at class-v5 8ca66afa (AP-F4-1 in the agreed form: cost A at most 205, k >= 1 or all-ROT-equal rejected, the forty redrawn), the harness on the agreed w32 convention (digits 0 to 31) and median 226; known-failed day 29,337 redrawn under the rule (cost 203 to 228), day 20,729 at 219 unchanged; build-1 `lease pool 12` class adv, 379 s, ended 22:3x UTC | 0 of 2^24 days over 1.1x on M1 (median 226; minimum cost 206 at day 27,016, 1.097x, one adder above the reject line) and 0 on M2; mean 225.79, sd 6.07 (pre-rule: 5.69e-4 over, min 203). The redraw rule removes the LUT tail by construction and the measurement agrees | PASS; AP-F4-1 FIXED-AND-PASSED against class v5 at 8ca66afa |
|
||||
|
|
@ -506,10 +506,10 @@ control, box 2; stream 07a809a7 / 8bdcbdd8, pairing id a788661687db4bb3): FAIL.
|
|||
| p15 | 2.57x | 2, 12 | 4.49 percent | 0.982 | zero through rotl at 0 |
|
||||
| p18 | 2.50x | 6, 30 | 5.55 percent | 0.937 | all-ones through a load |
|
||||
| p56 | 2.01x | 2, 10 | 3.34 percent | 0.994 | unattributed (new over sub-version 1) |
|
||||
| p10 | 1.50x | 8, 28 | 2.04 percent | 0.979 | unattributed (identical to sub-version 1) |
|
||||
| p8 | 1.38x | 14, 51 | 1.42 percent | 0.980 | unattributed |
|
||||
| p34 | 1.25x | 1, 13 | 1.35 percent | 0.997 | one-bit value through sub |
|
||||
| p4 | 1.22x | 1, 8 | 1.45 percent | 0.981 | unattributed (1.57x on sub-version 1) |
|
||||
| p10 | 1.50x | 8, 28 | 2.04 percent | 0.979 | bucket concentration at a narrow-window site (r0, window 2^22, offset 1, last writer mad at 20): largest 256-item bucket 5.6x window expectation, index entropy 13.71 of 14 bits, hottest 0x4004da at 362 reads, source none (identical to sub-version 1) |
|
||||
| p8 | 1.38x | 14, 51 | 1.42 percent | 0.980 | bucket concentration at a narrow-window site (r7, window 2^22, offset 2, last writer xor at 44): largest bucket 3.1x, entropy 13.72 of 14; plus site 6 (instr 33, r3, window 2^23, mad at 30) at 0.834 percent, bucket 3.5x; hottest 0x837de4 at 420 reads, source none |
|
||||
| p34 | 1.25x | 1, 13 | 1.35 percent | 0.997 | one-bit value through sub (r3, window 2^23, offset 1, last writer sub at 5): largest bucket 3.5x, entropy 14.96 of 15, hottest 0x800010 at 541 reads, saturated source 0.0001 percent |
|
||||
| p4 | 1.22x | 1, 8 | 1.45 percent | 0.981 | bucket concentration at a narrow-window site (r2, window 2^22, offset 1, last writer mad at 4): largest bucket 4.5x, entropy 13.74 of 14, hottest 0x4000e7 at 355 reads, source none (1.57x on sub-version 1) |
|
||||
|
||||
Every failing seed is one low-entropy load site. Clean-seed spread of the per-site bucket entropy (848 site rows of
|
||||
sub-version 1's 53 clean seeds): min 0.9865, p1 0.9961, p5 0.9999, so bucket entropy separates only the strong four;
|
||||
|
|
@ -525,12 +525,22 @@ word indices over 2^20 evaluations with the shadow executed against the uniform
|
|||
site ratio 0.9960, p1 0.9990, median 1.0000; the strong five p23 0.8361, p18 0.9274, p19 0.9335, p15 0.9432, p56
|
||||
0.9654; floor 0.98 sits 0.015 from each side. At 2^24 the weak four (p34 0.9181, p4 0.9614, p8 0.9630, p10 0.9612)
|
||||
share their value with two clean seeds (p44 0.9612, p52 0.9613), so the 2^24 stage is not taken and p4, p8, p10 and
|
||||
p34 stay the open tail, unattributed. The ratio refuses about 4 percent of candidates that pass every other test
|
||||
p34 are the tail. The tail attributed (hash lane, 8 October 2026, 09:40 to 09:46 UK, attack-f8 census at 2^24 with
|
||||
the window-model control and by-site attribution, tree b38b4af6 on the frozen 017e7037; the gate ratios reproduced to
|
||||
four places, p4 1.2169x, p8 1.3774x, p10 1.5036x, p34 1.2501x, the hot-set verdict clear on the windowed control for
|
||||
all four): each is a per-site bucket concentration of about a quarter bit (0.26 to 0.29 bits short of 14 on a 2^22
|
||||
window; p34 0.04 of 15) at one narrow-window load site whose last writer is mad, xor or sub, with every other site at
|
||||
its flat share; the ratio tracks the largest-256-item-bucket excess (5.6x gives 1.50x, 3.1x to 4.5x give 1.22x to
|
||||
1.38x); (c'') passes them at 0.9927 to 0.9963 because distinctness does not see a bucket; the check that would catch
|
||||
all four is a per-site largest-bucket bound (about 2x window expectation at the 2^20 units), a generator change for a
|
||||
next class, never for the frozen ones. Meaning per tier: a quarter bit at one site is under the window model's own
|
||||
spread (the gate line's 61 of 64 stands), so no card or chip gains a cacheable hot set from it; the bound is the next
|
||||
class's item, not a change to 017e7037 or 1c420786. The ratio refuses about 4 percent of candidates that pass every other test
|
||||
(4,099-program census at 017e7037: mean attempts 2.086 against 1.998, max 17, 0 lossy-sourced load sites of 65,584,
|
||||
0 exhaustions; suite 103 of 103; devnet epoch-0 at attempt 1, id a785001687d8688a, pairing verified by this lane).
|
||||
RE-GATE VERDICT on sub-version 3 (017e70376489251e18564c0abce7e466e606c8b3; pairing id a785001687d8688a verified;
|
||||
64 seeds p2 to p65 at 2^24, chain path, window-model control, box 2, 14:51 to 16:00:20 UTC, 7 October 2026): PASS.
|
||||
60 of 64 under 1.2x (0.9915x to 1.144x); the four over are the named open tail, unattributed and chased: p10
|
||||
60 of 64 under 1.2x (0.9915x to 1.144x); the four over are the named tail, attributed 8 October 2026 (per-site bucket concentration, the AP-F8-1 tail paragraph): p10
|
||||
1.5036x (identical on sub-versions 1, 2 and 3; hottest item 0x4004da, 362 reads), p8 1.3776x (0x837de4, 420), p34
|
||||
1.2505x (0x800010, 541, the one-bit value through sub at 5), p4 1.2167x (0x4000e7, 355); their hottest items carry
|
||||
355 to 541 reads of 2^31 (one to two per 2^22 items above the mean), no chip consequence, and the ratio rule reads
|
||||
|
|
|
|||
232
docs/analysis/class-v6/family-gate.md
Normal file
232
docs/analysis/class-v6/family-gate.md
Normal file
|
|
@ -0,0 +1,232 @@
|
|||
# Class v6, the family gate: how a parameter family is cryptanalysed as a family
|
||||
|
||||
Research lane D of the class v6 rotating-family design, under the Counter ASIC coordinator. First cut 8 October 2026, 11:0x to 17:00 BST (the deliverable clock); the full report by 09:00 BST on 9 October. Branch `class-v6-family-gate` (this document) and the harness branch `family-gate-v5` (the class v5 crate at 8f481459 plus the census harness, never a chain path). Internal research, not an independent review; nothing here touches a served number, the devnet or the testnet object; no consensus code this week. Every figure carries its source: a lane report on the mirror, a log on a box, or an arithmetic step shown in the text. Figures from memory are labelled approximate.
|
||||
|
||||
The question. Class v6 (the founder's word at 11:1x BST, 8 October 2026) draws per era the parameters a release used to fix (layer 1), lets the dataset track the chain state (layer 2), rotates instruction families by height (layer 3) and generalises the acceptance floor and the uniformity test to each era's draw with a redraw on failure (layer 4). A chip is then built against a FAMILY of hashes, not one hash. The in-house pass of 7 October and the attack board F1 to F10 bounded ONE member of the family (class v4 sub-version 3 at 017e7037 and class v5 at 1c420786). This document says how the family is bounded: what the space is, how many eras must be drawn to say anything about the worst era, which tests the chain runs itself on every era and epoch, what the offline board looks like over the testnet period, what a published proof of testing contains, and what the whole apparatus cannot see.
|
||||
|
||||
## 0. One page
|
||||
|
||||
| Item | The line |
|
||||
|---|---|
|
||||
| The space (section 1) | Seven drawn axes with a tested band each: the mixer multiplier `m` in {4, 8, 16} (8 and 4 measured on cards and the verifier; 16 the verifier's open row), the ten non-load op weights within B points of table 1.4.2 with shuffle and mulhi never raised (B = 2 proposed in spec 1.13.1, B = 4 the research lane's proposal), the read width in {1, 4} words (w16 measured 5 October, w64 excluded), the shadow block shape in {64, 128, 256} instructions at 6,912 per iteration (measured 6 October), the shadow placement fixed at the whole block after instruction 63 (the per-load placement is a known-failed corner: 1.4 percent acceptance, 42 of 64 seeds exhausting 32 attempts), the program length N by the ladder's signal inside rungs 0 to 2 (rung 3 inadmissible by F6), and the existing era draws (the stride `M`, the rotation `R` in 1..31, the interleave, the per-site windows). The day key (ROT, MUL, RC) is drawn daily under the AP-F4-1 redraw rule |
|
||||
| Which tests depend on which axis (section 1.3) | The acceptance rule and every index statistic ((c''), (c'''), the bucket bound, the bit-bias read, the attempts census) run on the closed-form dataset and never see `m`: the mixer axis is bounded per family by adv-mixer-3's rows and F4, not per era. The width axis changes the index space of every site ((c'')'s expectation `E_s` must divide the window by the width, a spec change the harness carries). The shape and weight axes change the draw's stream and so every per-era statistic |
|
||||
| The sampling bound (section 2) | With `n` eras drawn from the chain's own distribution and every one passing a per-era test, the fraction of eras that would fail it is under `3/n` at 95 percent confidence (the rule of three; Wilks 1941 for the order-statistic form): 190 eras bound the failing fraction at 1 in 64 (one era in 32 years of 180-day eras), 3,067 at 2^-10. The bound is on the TESTED property only; the union bound over the per-era tests' own false-pass rates gives the family's false-pass rate, and each test's false-pass rate is itself a rule-of-three number on its known-failed cases (the (c''') floor refused 9 of 9 live hot sets, so its miss rate on that class is under 0.33 at 95 percent: nine cases bound nothing tighter) |
|
||||
| The per-era tests (section 3) | Three rings. Ring A, the chain runs per era at the cut, microseconds: the structural redraw rules (the band membership of every draw, the day-key cost rule, the product-bias rotation class recorded). Ring B, the chain runs per epoch, seconds: the acceptance rule generalised to the family's shape ((a) (b) (a') (c) (c') (c'') (c''') plus the two next-class tests, the per-site largest-256-item-bucket bound and the index-bit bias read, on the same 2^20 pass). Ring C, the gate runs offline per drawn era, box-hours: the F8-form census at 2^24 on 64 seeds, the attempts census, the exhaustion count. Each row carries its known-failed shape and its clean-seed cost so the redraw is priced |
|
||||
| The board (section 4) | F1 to F10 and the nine lanes classified per-era, per-family or chain-run, with the harness taking the era draw as an input; the proof of testing is one JSON record per drawn era (the draw, the object, the binary, the seeds, every verdict with its statistic, threshold and log sha256, the core-seconds) and one family summary (eras per stratum, the worst era per test, the refuse rate per band, the bound's arithmetic) |
|
||||
| The honest line (section 5) | The gate sees what its tests see. It does not see the diffuse era-stride class below the bit-bias read's resolution (a bias under 0.3 percent at 2^20), a mechanism that lives in a joint corner no stratum names, a mixer weakness below adv-mixer-3's bands, or an era whose draw sits in the untested 1 in 64. A GPU-like chip loses nothing on any era; what a corner buys it is a per-era hot set bounded at 1.002x (the floor) or 1.0024x (the diffuse class), or, at `m = 4`, a mixer with 2 applications of measured margin instead of 6 |
|
||||
| Running now (section 6) | The harness `family_gate_era_census` on build-1 from 11:16 BST: one drawn era per seed, every family parameter from the era's own stream, the chain draw through the real rule keyed on the family's shape, one TSV row per era with the (c'') ratio, the bucket ratio, the bit bias and the attempts; the base control (`v5_attempts_census`, the shipped draw) beside it. The coverage table in section 6 is filled from the logs at 16:xx BST |
|
||||
|
||||
## 1. The parameter space
|
||||
|
||||
### 1.1 The axes, their bands and the margin each band was read from
|
||||
|
||||
| Axis | Band proposed for the draw | What fixed the band (the measured rows) | The tested margin inside the band | Known-failed corner, named |
|
||||
|---|---|---|---|---|
|
||||
| Mixer multiplier `m` (applications per round, `LoadClass::mixer_mult`; 72 per item at `m = 8`, 8 between dependent reads) | {4, 8, 16}; the research lane's outline; this lane's reading: {8} plus {4} as a corner, {16} only after the verifier row | x4 and x8 measured (`docs/plans/mixer-x4.md` section 6.4: 1.92 and 2.79 ms per unit on a loaded M5 Max core; the daily build 42 ms at x8 on the 5090, measured); x16 estimated at about 3.7 ms per unit on the M5 Max core and 9 ms on a 2019-class core (chip-model-v3 section 3 item 1), against the 10 ms verifier gate | adv-mixer-3 (`report-mixer-3.md`, "The round margin, stated"): no statistic survives 2 of the 8 keyed applications between reads at bands 0.0015 (Q2, 2^24 states), 0.00026 (2^27), 0.00018 (Q2b, 2^28); SAT solved at k = 1 in 137 s and timed out at k = 2, 3, 4; two real days and eight random days agree. So at `m = 8` 6 of 8 applications are margin; at `m = 4` the same rows leave 2 of 4; at `m = 16` 14 of 16 | None measured. The corner is `m = 4` by margin and `m = 16` by the verifier; the all-ROT-equal day key is the day-level corner (rejected by the AP-F4-1 rule) |
|
||||
| Op-mix weights (the ten non-load families, sum 75) | Each weight within B points of table 1.4.2 (add 12, xor 10, mul 8, mad 8, shfl 8, rotl 7, sub 6, mulhi 6, rotr 6, or 4), renormalised by largest remainder; shfl and mulhi never raised; B = 2 (spec 1.13.1, proposed) or B = 4 (the research lane) | The microbench (`counter-asic-4-research.md` 15.1a, the 5090 alone, 8 October): pJ per counted op at the stock clock and the 1,300 MHz lock: arx 11.3 / 6.2, mul 13.9 / 8.3, mulhi 39.6 / 21.0, prmt 22.3 / 11.5, lop3 24.1 / 13.0, shfl 55.8 / 29.4; the shuffle is 4.9x the add, so a draw that raises shfl raises the card's premium per instruction with no better `k` for a chip (15.1b). F7's era census: the op-weight corners (15 to 31 of 75) read 1.0x against the GPU, 0 memory effect | The acceptance's rejection rate moves with the lossy share: at the table 0.68 per candidate ((a') 83.5 percent of rejections; adv-accept row 90, 20,000 seeds); the F7 census at B = 2 read every corner clean for the chip; nothing was measured at B = 4 before today (section 6) | The lossy corner: or, mul and mulhi all at +B. It raises (a') rejections and so the attempts per seed; the exhaustion bound `r^256` is the number to read there (section 3, ring C) |
|
||||
| Read width `W` (words per load) | {1, 4} | `docs/plans/read-width.md` (5 October): w16 within the rules (5090 139.8 against 136.1 MH/s, 9070 XT 17.90 against 18.15, M5 Max within 1 percent); w64 bandwidth-bound (5090 share 0.58, 71.9 MH/s): out; the per-load mixes out on the 5 percent spread rule | The acceptance runs unchanged on aligned addresses (read-width.md section 2), but (c'') and (c''') read a site's distinct ALIGNED indices against `E_s = N - N^2 / 2W_s`: at `W = 4` the index space is `W_s / 4`, so the expectation must follow or every width-4 program reads 0.976 at a quarter window and is refused by the 0.98 floor. The harness divides the window by the width (`site_window_words`); the spec line is owed | `W = 16` (w64): excluded by measurement, never in the band |
|
||||
| Shadow block shape (instructions per block, passes per iteration) | {64 x 108, 128 x 54, 256 x 27}: 6,912 shadow instructions per iteration at rung 0 | 64-instruction blocks ran 2.5 to 3.5 percent faster than 256 on the 5090 and the M5 Max (6 October, measured); 1,024 cost the M5 Max 17 percent (out) | F1's shadow redundancy bound (3.0 percent of peephole-removable instructions, the v5 generator's `SHADOW_REMOVABLE_MAX_PERMILLE`) was set from F1's census at 256 instructions; the removable fraction per block is a property of the block's length, so the fraction must be re-read at 64 and 128 (a per-family row). The acceptance's (a') fixpoint and the shadow's execution in (c) take any length | The per-load placement (16 sub-blocks of 16 after each load): dead as a chain class (`counter-asic-4-research.md` 20.2a-close): 22 of 1,621 candidates accepted, 42 of 64 seeds exhaust 32 attempts, candidate 0 carries index bit 0 set in 40 of 1,024 addresses at site 0 (z 29.5). The placement axis therefore has ONE value in the band |
|
||||
| Program length `N` (counted ops per hash) | Not drawn: the ladder's signal (rungs 0 to 2); the research lane's outline keeps it so | F6: the worst of 10^5 class v4 programs 8.708 ms on the half-core proxy, so N about 300,000 fits under 10 ms (rung 2 admissible, rung 3 not); the M5 Max loses 3.3 to 10 points across the band (measured ladder) | The verifier's worst case was censused at rung 0 only; a draw inside the ladder needs the 10^5-program worst case at the top rung (per-family row) | Rung 3 (inadmissible by F6) |
|
||||
| Era stride and interleave (`M` odd, `R` in 1..31, `pos` four ascending bit positions, the fold rotations, the per-site windows `k_off`, `o`) | As spec 1.13.1 draws them today | F7's 2^24 era census (stride bijective, R, pos, M uniform, no class over 1.1x); adv-cache-2 section 2.3: the same 32 base programs read 2 of 32 with a site over 1.04x under `R = 29` and 16 of 32 under drawn eras (8 over 1.2x, worst 1.75x), because `rotl(x * M, R)` places a product's biased low bits (P(bit 0) = 1/4) at address bits R and up, inside the 28-bit index unless R is 29 or 30; at D = 29 only R = 30 and 31 cut bit 0 | The whole 64-seed F8 census is a census over drawn eras (each f8 seed carries its own era), so the per-era uniformity verdicts of sub-version 3 and class v5 (60 of 64 and 61 of 64 under 1.2x) already sample this axis; the devnet's clean reading at R = 29 is the accident, the drawn-era figure the chain's | R in 1..27 with a product as the last writer of a load's source (sub-class A); the warp-uniform mulhi source (sub-class B, 1 in 16,000 warps) |
|
||||
| Dataset size `D` (layer 2) | 2^28 words today, 2^29 at the 2 GiB genesis step, growing on the 1.13.3 schedule with the state as a floor | The acceptance's closed form is pinned at D = 28 (`ACCEPT_DATASET_LOG2`); the live dataset is larger; the stand-in gap measured at 0.0004 under D = 28 (adv-accept Q2, 54 programs) | Unmeasured at D = 29: which R values hide the product bits changes with D, and the window cap `min(k_off, D - 26)` changes the per-site windows | D at a value where the acceptance's D = 28 windows and the live windows disagree: the stand-in gap row of ring C |
|
||||
| Day key (ROT x 8, MUL x 16, RC x 16, drawn daily from the day seed) | As spec 1.8.4, under the AP-F4-1 redraw rule in class v5 (cost A at most 205 rejected, k >= 1, the eight ROT equal rejected) | F4 and adv-mixer-2: 0 of 2^24 days over 1.1x on both metrics with the rule (8ca66afa); 5.69e-4 of days over 1.1x on LUT area without it, 15 days a century, worst 28 April 2050 at 1.113x | The rule is per day and chain-run; it does not depend on `m` (the cost is per application) | Day 29,337 (redrawn under the rule); the planted mul1all and mulnaf days fire |
|
||||
|
||||
### 1.2 The joint space and what a draw covers
|
||||
|
||||
Counting the discrete axes alone: 3 (m) x 2 (W) x 3 (shape) x the weight perturbations ((2B + 1)^10 before the caps: about 9.8 million at B = 2, 3.5 billion at B = 4) x 31 (R) x 2^31 (M) x 1,820 (pos) x 31^6 (the fold rotations). The space is of order 2^80 before the per-site windows, which are per program. No census walks it. What a census can do is (i) draw eras from the chain's own distribution (the era stream over random `E_n`) and bound the fraction of eras that fail a test (section 2.1), and (ii) pin the axes that carry a KNOWN mechanism at their corner and draw the rest (section 2.3), so a mechanism that depends on one named axis is read at its worst value. A mechanism that depends on a joint corner nobody named is in the honest line (section 5).
|
||||
|
||||
### 1.3 Which tests see which axis
|
||||
|
||||
| Test | `m` | weights | `W` | shape | N | era stride, windows | D | day key |
|
||||
|---|---|---|---|---|---|---|---|---|
|
||||
| The acceptance rule and the index statistics ((c''), (c'''), bucket, bit bias), on the closed form | no (the mixer never runs) | yes (the stream) | yes (the index space) | yes (the stream, the shadow's execution) | yes (the shadow's passes) | yes (`load_index`) | no (D = 28 pinned) | no |
|
||||
| The attempts census and the exhaustion bound | no | yes | yes | yes | yes | yes | no | no |
|
||||
| The F8-form census at 2^24 on the live dataset | yes (the item words) | yes | yes | yes | yes | yes | yes | yes |
|
||||
| adv-mixer-3's distinguisher rows, F2, F4, adv-mixer-2 | yes | no | no | no | no | no | no | yes |
|
||||
| F6 verifier worst case | yes | yes | yes | yes | yes | no | yes (the fill) | no |
|
||||
| F1 shadow redundancy | no | yes | no | yes | yes | no | no | no |
|
||||
| F3, adv-cache, adv-cache-3 (the chained cache) | no (the cache fill is ChaCha12) | no | no | no | no | no | yes (the cache doublings) | yes |
|
||||
| F7 era census | no | yes (the perturbation) | yes | no | no | yes | no | no |
|
||||
| F5 chip model, F10 ladder | the band's top | the band's dearest mix | yes | no | the ladder | no | yes | no |
|
||||
|
||||
Reading: the per-era statistical tests are blind to `m` by construction, so the mixer is a per-FAMILY axis with three values and is closed by re-running adv-mixer-3's ladder and F4 at `m = 4` and `m = 16` (section 4), not by drawing eras. The weights, the width and the shape are per-era axes and are what the drawn-era census of section 6 walks.
|
||||
|
||||
## 2. The sampling bound
|
||||
|
||||
### 2.1 Zero failures in `n` eras (the rule of three, Wilks)
|
||||
|
||||
Let a per-era test have a fixed verdict per era and let `p` be the fraction of the family's eras (under the chain's own draw) that fail it. If `n` eras drawn independently from that draw all pass, then with confidence `1 - alpha`, `p <= eps` where `(1 - eps)^n = alpha`, that is `n >= ln(alpha) / ln(1 - eps)`, about `3 / eps` at 95 percent and `4.6 / eps` at 99 percent (Hanley and Lippman-Hand 1983; Wilks 1941 gives the same arithmetic as the one-sided nonparametric tolerance limit on the worst order statistic). The table, with the era length of layer 3 (180 days) turned into years:
|
||||
|
||||
| `eps` (the failing fraction bounded) | One failing era expected every | `n` at 95 percent | `n` at 99 percent |
|
||||
|---|---|---|---|
|
||||
| 1/16 | 8 years | 45 | 70 |
|
||||
| 1/64 | 32 years | 190 | 293 |
|
||||
| 1/256 | 126 years | 766 | 1,177 |
|
||||
| 2^-10 | 505 years | 3,067 | 4,713 |
|
||||
| 2^-20 | the F4 and F7 gate's fraction | 3.1 million | 4.8 million |
|
||||
|
||||
What this buys and does not. The F4 and F7 gates ask "no class with gain over 1.1x at a fraction over 2^-20" and reach it by censusing 2^24 draws of a CHEAP statistic (microseconds per day key or era seed). A per-era test that costs box-hours (the F8 census at 2^24) can be run on hundreds of eras, so it bounds the failing fraction at the 1/64 to 1/256 class, never 2^-20. That is why layer 4 puts the tests on the chain: a per-era test the chain runs on EVERY era (ring A) or every epoch (ring B) needs no sampling bound at all; the offline census (ring C) is then a check on the chain-run tests' calibration (their clean refuse rate and their known-failed firing per stratum), and a reading of the one statistic the chain cannot afford, the live-dataset census.
|
||||
|
||||
### 2.2 The union bound over the per-era tests
|
||||
|
||||
Let the chain run tests `T_1 .. T_k` on every era or epoch, and let `delta_i` be the probability that `T_i` passes an era (or program) that carries the failure class `T_i` exists for. The family's false-pass rate on the union of those classes is at most `sum delta_i`. Each `delta_i` is itself bounded by the rule of three on the test's known-failed cases: a test that fired on `f` of `f` known-failed cases has `delta_i <= 3 / f` at 95 percent. The numbers today:
|
||||
|
||||
| Test | Known-failed cases it fired on | `delta` at 95 percent | Source |
|
||||
|---|---|---|---|
|
||||
| (c''') floor at 0.995 on the few-item hot-set class | 9 of 9 live hot sets refused (minimum sites 0.9809 to 0.9919), both single-item programs refused | under 0.33 | adv-accept, "the floor's final tally", 01:13 BST 8 October; class-v5 section 14 |
|
||||
| (c'') floor at 0.98 on the low-entropy band | 5 of 5 (p23, p18, p19, p15, p56) | under 0.60 | attack-pass-2026-10.md, sub-version 3 |
|
||||
| (a') freshness on the lineage-visible constant class | 11 of 11 (sub-version 1's eleven seeds under 1.2x on sub-version 3) | under 0.27 | attack-pass-2026-10.md, the sub-version 1 table |
|
||||
| The bucket bound (in sigma of the bucket's expectation at 2^20) on the quarter-bit class | 4 of 4 would be caught (p4, p8, p10, p34: largest bucket 3.1x to 5.6x at narrow windows, +17 to +37 sigma), not yet wired as a rule | under 0.75 once wired; the clean spread is measured in section 6 | the hash lane's attribution, 09:46 BST 8 October |
|
||||
| The index-bit bias read on the product class | 3 of 3 named sites (Devnet 3 site 0 at P(bit 0) = 0.25; era-drawn-28 site 15 at 0.778; the per-load candidate 0 at z 29.5), and 7 of 7 in the 16-era smoke run at 130 to 511 sigma | under 0.30 on ten cases; but the read is a record, not a refusal (section 3.2) | adv-cache-2 2.3; counter-asic-4-research.md 20.2a; section 6 |
|
||||
| The day-key cost rule | the planted mul1all and mulnaf days, day 29,337 | 0 of 2^24 days over 1.1x after the rule (a census, not a case count) | f4-weakday.md, 8ca66afa |
|
||||
|
||||
Reading: the per-test miss rates are bounded by HANDFULS of known cases, so the union bound today is a loose number (the sum exceeds 1). The way to tighten it is not more eras but more known-failed cases per test, which the adversarial sweeps supply cheaply: adv-accept's tail holds 22 programs beyond the 1.2x gate of 37 measured live, and the drawn-era census of adv-cache-2 holds 19 biased sites of 1,056. A test with 60 fired cases has `delta` under 0.05; with 300, under 0.01. The proof of testing (section 4.3) therefore carries, per test, the count of known-failed cases it fired on, and that count is the number a reader checks first.
|
||||
|
||||
### 2.3 Stratified draws over the corners
|
||||
|
||||
The axes with a known mechanism and their corner values: `m` in {4, 16} (margin, verifier), weights at the lossy cap (or, mul, mulhi at +B) and at the table, `W` in {1, 4}, shape in {64, 256}, R in {1..27} against {28..31} (the product-bias class visible or hidden; at D = 29 the hidden set is {30, 31}), the windows forced to quarter (`k_off = 2` at every site, the F8 tail class), D in {28, 29}. That is 2 x 2 x 2 x 2 x 2 x 2 x 2 = 128 corner cells for the per-era statistics (the mixer cells are per-family rows), plus the random stratum (every axis drawn). The plan: at least 8 eras per cell for the cheap ring-B statistics (1,024 eras, about 2 core-hours each at the (c''') cost, 2,000 core-hours, 64 box-hours of 32-core slots) and the random stratum at 3,000 eras (the 2^-10 line of 2.1 at 95 percent for the ring-B tests, 6,000 core-hours, 190 box-hours); the live-dataset census at 2^24 on 64 seeds for 24 corner representatives and 64 random eras (88 eras at 45 to 95 core-hours each, about 6,000 core-hours, 190 box-hours). About 450 box-hours in all, 2 to 3 days of both boxes at the 88-core pool, inside the testnet period by a wide margin. Section 6 records what has run.
|
||||
|
||||
## 3. The per-era automatic tests (layer 4)
|
||||
|
||||
The three rings. A test's ring says who runs it and what a failure costs.
|
||||
|
||||
| Ring | Who runs it, when | Cost per run | What a failure does |
|
||||
|---|---|---|---|
|
||||
| A: structural, per era | every node at the era cut, on the drawn parameters | microseconds | the era stream's next block of draws is consumed (a redraw), up to a cap, then the base table (the class v4 values) as the last resort, so the draw is total and no consensus path panics (the AP-F8-2 shape) |
|
||||
| B: the acceptance, per epoch | every node at the epoch draw, on each candidate | about 2.2 s per chosen candidate on one box core at 2^20 (the (c'') pass), plus 0.3 s for the 64-unit parts; the two next-class tests ride the same 2^20 pass | the next attempt, as today; the cap 256 and the last resort unchanged |
|
||||
| C: offline, per drawn era | the family gate on the boxes, before the testnet and through it | box-hours | a finding against the family's band (a band narrowed, a rule added), never a chain event |
|
||||
|
||||
### 3.1 Ring A: the structural rules the chain runs per era
|
||||
|
||||
| Rule | Draw it reads | Known-failed shape | Clean refuse rate | Source |
|
||||
|---|---|---|---|---|
|
||||
| Band membership: `m` in the band, `W` in the allowed set, the shape in the set, every weight within B of the table with shfl and mulhi at or under their base, the sum 75 | the layer-1 draws | a draw outside the band (a unit test) | 0 by construction (the draw is bounded) | spec 1.13.1's form |
|
||||
| The day-key cost rule (AP-F4-1, class v5) | ROT, MUL | mul1all, mulnaf, day 29,337 | 6.1e-4 per day | f4-weakday.md 6.7 to 8; 8ca66afa |
|
||||
| The rotation class recorded: whether R leaves a product's low bits inside the index at the era's D | R, D | none (a record, not a refusal: restricting R to {29, 30} would cut the interleave's entropy from 31 to 2 values; the value-level test of ring B is the catch) | 0 | adv-cache-2 2.3 |
|
||||
| The weights' lossy share bound: or + mul + mulhi at most the table's 18 plus B, so the exhaustion bound `r^256` stays under 1e-18 (r under 0.85) | weights | the lossy corner of section 6 if its `r` reads over 0.85 | 0 by construction | row 90 (r = 0.681 at the table) and section 6 |
|
||||
|
||||
### 3.2 Ring B: the acceptance rule generalised to the family, per epoch
|
||||
|
||||
| Part | Generalisation | Known-failed shape (fires today) | Clean refuse rate (the cost) | Per-candidate cost |
|
||||
|---|---|---|---|---|
|
||||
| (a) (b) | unchanged | the class v2 census vectors (22, 37, 51) | 11.6 and 3.0 percent of rejections | microseconds |
|
||||
| (a') the freshness fixpoint over base then shadow | keyed on the family's shape (`is_family_shape`: shadow in {64, 128, 256} at 6,912 per iteration, `m` in {4, 8, 16}, the mix one-hot on the drawn width) in place of the one class v4 shape, in the draw's source rule and the acceptance alike | sub-version 1's eleven seeds | 83.5 percent of rejections (57.5 percent of candidates) | microseconds |
|
||||
| (c) the dynamic test with the shadow executed | the interpreter already runs any block length, any pass count and any width (the fold) | p23 at attempt 1 (the shared-operand idiom) | 0.9 percent | about 3 ms (64 units) |
|
||||
| (c') saturated sources | unchanged | the forced-saturation plant | 0.05 percent | in (c) |
|
||||
| (c'') the distinct-index ratio at 0.98 | `E_s = N - N^2 / (2 W_s / W)`: the window divided by the width | p15, p18, p19, p56 | 1.1 percent | 2.2 s at 2^20 |
|
||||
| (c''') the hot-item floor at 0.995 | the same `E_s`; the floor's clean spread re-read per stratum (section 6): a fixed 0.995 under a spread that moves with the shape or the width is either a liveness cost or a miss | seed 100767 (0.9919) and the nine live hot sets | 2.435 percent of accepted class v4 programs, +0.045 on the mean attempt | in the (c'') pass |
|
||||
| The per-site largest-256-item-bucket bound (NEW, the F8 tail's catch) | the largest count over a site's 4,096-word buckets in its window against `N / (W_s / 4096)`, in SIGMA of the bucket's expectation (`(max - E) / sqrt(E)`), refused above a band set from the clean spread. The ratio alone cannot carry the bound: a clean full-window site's largest of 65,536 Poisson(16) buckets reads 2.1x at +4.4 sigma, a quarter-window site's largest of 16,384 Poisson(64) buckets 1.5x at +4 sigma (the 16-era smoke run read ratios 2.2 to 2.4 on clean sites); the four tail seeds' 3.1x to 5.6x at narrow windows are +17 to +37 sigma | p4, p8, p10, p34 | measured in section 6 (the columns `bucket_z_max`, `bucket_win`) | one linear pass over the (c'') indices |
|
||||
| The index-bit bias read (NEW, adv-cache-2's value-level test) | per site, the one-count of each free index bit (bits above the width's alignment and below the window's cut) over the 2^20 evaluations, in sigma (`sigma = sqrt(N) / 2 = 512`); a 6-sigma band is a bias of 0.3 percent at 2^20 (the product law's bit 0 at 25 percent reads z about 512, bit 1 at 3/8 z 256, bit 3 at 3.1 percent z 64, bit 6 at 0.4 percent z 8, bit 7 at 0.2 percent z 4: passes). MEASURED on the first 16 drawn eras (11:21 BST, section 6): 7 of 16 accepted programs carry one site with a bias of 130 to 511 sigma at address bit R or R + 1 (the era's rotation), the era-stride class exactly, on programs (c''') passes at 0.9954 to 1.0000; the 9 others read under 3.8 sigma. So as a REFUSAL the read would redraw about 40 percent of epochs; its right use is as a record per era plus the structural lever (fold the product's low bits in `load_index` before the rotation, a next-class item), and the chip price is stated in section 5 | Devnet 3 site 0, era-drawn-28 site 15, the per-load candidate 0; and now the 7 of 16 | 7 of 16 at 6 sigma (a refusal is not the form); 0 of 16 at a 600-sigma band | one pass over the indices, 28 bit tests each |
|
||||
| The cap and the last resort | unchanged at 256; the last resort's own verdict is adv-accept-3's finding 1 (9 percent of last-resort programs fail (a)); the family keeps the open fix (continue past 256 until one passes) | the reject-everything mirror | 0 reached in 1.02 x 10^6 seeds | n/a |
|
||||
|
||||
### 3.3 Ring C: the offline tests per drawn era
|
||||
|
||||
| Test | What it reads | Known-failed shape | Clean cost per era | Sample needed for its own verdict |
|
||||
|---|---|---|---|---|
|
||||
| The attempts census (row 90's form) | every candidate of each seed's chain draw through the real rule; `r` per candidate, the parts' shares, the attempt histogram, `P(exhaust) = r^256`, 0 at the cap | the forced-exhaust plant (hits the cap, prints the last resort); the per-load class (r about 0.98) | 1,000 seeds: 202 s on 23 threads at the table (1.3 core-hours); about 5 core-seconds per accepted program with (c''') | 1,000 seeds per stratum reads `r` to 0.01 |
|
||||
| The F8-form uniformity census at 2^24 on the live dataset | the item histogram against the window model (the program's own 16 draws under the era's windows at the era's D), the top 0.1 percent within 1.2x, the hot-set test `X_f >= f`, the 6-sigma largest bucket, the per-site attribution | quarter-lines, half-lines, const-item (the plants); p31 (29.27x), p23 (4.82x) | 42 to 95 core-minutes per seed at 2^24 (the two halves of 32 on build-2 took 41 to 46 minutes at 30 to 32 cores; the 64 seeds of sub-version 3 took 69 minutes of the box); 64 seeds about 45 to 100 core-hours | 64 seeds per era bound the fraction of epochs over 1.2x at 3/64 (4.7 percent) at 95 percent: a calibration of ring B, not a hot-set hunt (adv-accept's sweep found 9 hot sets in 796,042 draws, 1e-5, every one refused by the floor) |
|
||||
| The stand-in gap at the era's D | the (c'') and bucket statistics on the closed form at D = 28 against the live dataset at the era's D on the same programs | none yet (the gap read 0.0004 at D = 28; a D where the windows disagree is the plant to build) | one 2^24 run per program, about 1 core-hour; 54 programs per era class | per D value, not per era |
|
||||
| The exhaustion count at scale | 10^4 to 10^5 chain-shaped seeds per stratum | the per-load class | 1.45 s per seed (F9's chain path): 4 core-hours per 10^4 | 10^5 per lossy corner reads the past-31 tail |
|
||||
|
||||
## 4. The board over the testnet period
|
||||
|
||||
### 4.1 F1 to F10 and the nine lanes, classified
|
||||
|
||||
| Row | Harness input | Class | Per what | Cost per run | Note |
|
||||
|---|---|---|---|---|---|
|
||||
| F1 shadow redundancy | the shape (block length, passes) | per family | each of the three shapes | 10^4 programs at 5 core-seconds each (the (c''') draw): 14 core-hours; 10^5: 140 | the 3.0 percent `SHADOW_REMOVABLE_MAX_PERMILLE` re-read per shape |
|
||||
| F2, adv-mixer, adv-mixer-3 (the round margin) | `m`, the day | per family | `m` in {4, 16} on 10 days each | index census 2^32 t about 7 core-hours per k per day; sac at 2^24 similar; SAT 1 core-hour per k | at `m = 4` the gate "no distinguisher beyond 2 of m" leaves 2 of 4 |
|
||||
| F3, adv-cache, adv-cache-3 (the chained cache) | the cache log2 (layer 2's doublings) | per family | each cache size step | minutes (the closure search), the curve by arithmetic | the fill is not drawn |
|
||||
| F4, adv-mixer-2 (the weak day) | `m`, the day key | per family and chain-run per day | 2^24 days per `m` | 379 s on 12 cores (1.3 core-hours) | the rule is chain-run; the census is its calibration |
|
||||
| F5 chip model | the band's top (`m = 16`, the dearest mix, `W = 4`, rung 2) | per family | once per band | minutes | the premium row per corner |
|
||||
| F6 verifier worst case | `m`, shape, `W`, N, the fill at D | per family | the top corner (`m = 16`, rung 2, `W = 4`) | 10^5 programs timed on the half-core proxy: about 100 core-hours | the x16 row decides whether 16 enters the band |
|
||||
| F7 era census | the era draw with the layer-1 draws added | per family | 2^24 era seeds | minutes | stride bijective, R, pos, M, the weights' corners uniform |
|
||||
| F8 uniformity | the era (every axis) | per era (ring C) and chain-run per epoch (ring B) | 64 seeds per drawn era | 45 to 100 core-hours | section 3.3 |
|
||||
| F9 acceptance edges, grinding, exhaustion | the era | per era (the exhaustion count) and per family (the 5090 grinding row) | 10^4 seeds per stratum | 4 core-hours | the GPU row once per band |
|
||||
| F10 ladder monotonicity | N | per family | once | the fast-time harness, minutes | unchanged by the draws |
|
||||
| adv-cache-2 (hot set, era stride) | the era | per era | 32 drawn programs at 2^23 | 0.7 core-hours per program | the value-level read is ring B now |
|
||||
| adv-accept, adv-accept-2, adv-accept-3 | the era | per era (the sweep and the attempts census) and per family (the A6000 header row) | as the attempts census | as above | the last-resort fix is the family's |
|
||||
|
||||
### 4.2 The testnet period as the window
|
||||
|
||||
Before the first miner: the per-family rows at the corners (F1 at three shapes, the mixer ladder at `m = 4` and 16, F4 per `m`, F6 at the top corner, F7 with the new draws), and the ring-C census on the corner cells and the random stratum of section 2.3. Through the period: every era the chain actually draws is a drawn era of the census (the chain's own eras are the best sample, the one the rule of three speaks about), so the F8-form census at 2^24 runs on each live era within its first day, and the attempts census on each; a live era that fails ring C is a finding against the band, filed and priced, never a chain event (the chain's ring-A and ring-B tests already passed it). The board's verdict at the end of the period: the count of live eras drawn and passed, the corner cells drawn and passed, the worst reading per test, the refuse rate per stratum, and the bound's arithmetic from those counts.
|
||||
|
||||
### 4.3 The proof of testing (the published format)
|
||||
|
||||
One JSON record per drawn era, in `docs/analysis/class-v6/gate-records/<family-id>/<stratum>/<era-label>.json`, the shape of `docs/plans/counter-asic-3-gate/*.json`:
|
||||
|
||||
```
|
||||
{ "family": { "id": "<sha256 of the genesis band table>", "spec": "docs/spec/01-lottery-hash.md@<commit>", "object": "igneum-pow@<commit>" },
|
||||
"era": { "label": "igneum-family-gate/era/<k>", "stratum": "random | lossy-cap | w4 | shape64 | ...",
|
||||
"draw": { "m": 8, "weights": [12,10,8,8,8,7,6,6,6,4], "width_words": 1, "shape": [256, 27], "R": 17, "M": "0x9ad30d99", "pos": [0,2,12,13] } },
|
||||
"harness": { "binary": "<sha256 of the pinned copy>", "box": "igneum-build-1", "lease": "<the lease line>", "started": "<UTC>", "ended": "<UTC>", "core_seconds": 7210 },
|
||||
"tests": [ { "name": "attempts-census", "seeds": "igneum-family-gate/program/<k>/epoch/0..999", "r": 0.681, "parts": {"a_prime": 0.835, ...}, "max_attempt": 28, "exhausted": 0, "verdict": "PASS", "log": "<path>", "log_sha256": "<hex>" },
|
||||
{ "name": "c3-floor", "floor": 0.995, "min_ratio": 0.9962, "min_site": 6, "verdict": "PASS", ... },
|
||||
{ "name": "bucket-bound", "bound": 2.0, "max_ratio": 1.31, "verdict": "PASS", ... },
|
||||
{ "name": "bit-bias", "band_sigma": 6, "max_z": 2.4, "verdict": "PASS", ... },
|
||||
{ "name": "f8-census-2e24", "seeds": 64, "over_1.2x": 2, "worst": 1.38, "hot_sets": 0, "verdict": "PASS", "known_failed_fired": ["quarter-lines", "const-item"], ... } ],
|
||||
"label": "internal research, not an independent review" }
|
||||
```
|
||||
|
||||
And one family summary per board cut, `docs/analysis/class-v6/gate-records/<family-id>/summary.md`: eras drawn per stratum; per test the count passed, the worst reading, the refuse rate, the known-failed cases fired (the count that bounds `delta`); the rule-of-three line per test (`3 / n` at 95 percent); the union bound's sum; the box-hours; the list of corner cells not reached. A reader checks the record by re-running one era from its label with the pinned binary; every number in the summary is a count over the records.
|
||||
|
||||
## 5. The honest line
|
||||
|
||||
What the family gate cannot see, and how a chip would use it.
|
||||
|
||||
| Blind spot | Why the gate misses it | What a chip gets from it | Bound today |
|
||||
|---|---|---|---|
|
||||
| The era-stride class, measured today at the bit level on 7 of 16 drawn eras (section 3.2): not diffuse, a 25 percent bias on ONE address bit (bit R, the product's bit 0 through `rotl(x * M, R)`) at one site, on programs every floor passes | the (c''') floor reads distinct counts, which a one-bit bias barely moves (0.9954 to 1.0000 on the seven); the bit read sees it at 130 to 511 sigma but refusing it would redraw about 40 percent of epochs; the class is structural (`load_index`'s form and the weights' products), so the catch is a next-class change to the address form, not a per-era floor | a store holding the favoured half of that site's window (128 MiB at D = 28) serves 75 percent of that site's reads instead of 50: 25 percent of 1/16 of a hash's reads, about 1.6 percent of reads at f = 1/2 from one site in about 40 percent of eras (arithmetic on the measured bias); the honest partial-store curve already costs 1.26x the ops at f = 1/2 (adv-cache-2 Q4), so the f = 1 verdict stands; the top-0.1-percent reading of the ledger (1.0024x) was the same class seen through the coarser instrument | the per-era record (ring A names the rotation class; ring B logs the bit read); the structural fix is the family's first owed item for the research lane |
|
||||
| A joint corner no stratum names | the 128 cells pin the axes with a KNOWN mechanism; a mechanism that needs, say, a particular `M` with a particular weight table and a particular shape is reached only by the random stratum, which bounds its fraction at 3/n | one era (180 days) of whatever the corner is worth, at most once per occurrence | 1/64 to 1/256 of eras untested at 95 percent (section 2.1); the chain-run rings catch the known shapes on every era |
|
||||
| The mixer below adv-mixer-3's bands | biases under 0.00018 (Q2b), correlations under 0.00073 with multi-bit masks, differentials under 2^-19, any structure a SAT model of 2 or more applications would expose; at `m = 4` the measured margin is 2 applications | a shortcut that saves applications against the 9,360 ops per item; none found at any k | the round margin, stated; `m = 4` is the corner that spends 4 of the 6 measured spare applications |
|
||||
| The verifier at `m = 16` and rung 2 on a 2019-class core | unmeasured (an estimate of 9 ms against the 10 ms gate) | nothing for a chip; a node tier retired if the corner is drawn | the row is owed before 16 enters the band |
|
||||
| The acceptance's stand-in at D = 28 against a live D = 29 | the windows cap `min(k_off, D - 26)` and the rotation's cut set move with D; the gap is measured at D = 28 only | a per-site concentration the closed form does not reproduce | 0.0004 at D = 28; unmeasured at 29 (ring C row) |
|
||||
| The union bound's own looseness | the per-test miss rates rest on 3 to 11 known-failed cases each (section 2.2), so the family's false-pass rate is not yet a number under 1 | nothing new; the bound is on what the gate claims, not on the hash | fixed by cases, not eras: 60 fired cases per test for `delta` under 0.05 |
|
||||
| The last-resort program | 9 percent of last-resort programs fail (a) and are handed out unchecked; a lossy-corner era that raised `r` toward 0.95 would reach it at 2e-6 per epoch | a program that re-reads one address in two loads of the same hash | ring A's lossy-share bound keeps `r` under 0.85 (`r^256` under 1e-18); the fix (continue past 256) is owed to the rule's owner |
|
||||
| The era redraw's own grindability | a ring-A redraw consumes the stream's next block, so an adversary who could steer `E_n` could steer which block is used; the era VDF of F7 (517 s on the fastest prover, 259x the window) closes the steering of `E_n` itself | nothing beyond F7's bound | F7 (a) PASS with the VDF in the node |
|
||||
|
||||
A GPU-like chip (the `f = 1` stored-dataset chip with a programmable core, chip-model-v3 section 5) loses nothing on any era of the family: every drawn parameter is firmware to it, and what the family costs it is the core sized for the band's top (the research lane's USD 30 to 60 per chip, modelled). The family gate's job is therefore not to defeat that chip (the identity of the research file's section 2 says the per-joule edge is the card's own idle, 2.1x at `k = 1`) but to make sure no drawn era hands ANY chip more than the one hash did: a per-era hot set, a per-era mixer shortcut, a per-era verifier miss. Everything in this document is a bound on that increment, and the increments found so far are 1.002x and 1.0024x.
|
||||
|
||||
## 6. Running now, and the coverage measured
|
||||
|
||||
Started 11:1x BST, 8 October 2026, on igneum-build-1 under `lease pool` (class measure, owner class-v6-family-gate), the scripts under `/srv/builds/_adv-family-gate/` (fg-setup.sh, fg-build.sh, fg-census.sh), every binary run from a pinned copy under `bin/<tag>/` with its sha256 (AP-H2's rule), logs and TSV rows under `logs/`, copies of the finished logs land under `docs/analysis/class-v6/logs/` on this branch with the full report.
|
||||
|
||||
| Run | What | Where | State |
|
||||
|---|---|---|---|
|
||||
| base | `v5_attempts_census` (the shipped class v5 draw: shape 256 x 27, `m = 8`, `W = 1`, the table weights) over f8-label seeds 1,000 to 11,000, each seed its own drawn era (M, R, pos, windows) | build-1, 24 cores, binary 4bec799c (8f481459 unmodified) | running from 11:16 BST |
|
||||
| fg1 random | `family_gate_era_census` with every axis drawn (shape in {64, 128, 256}, `m` in {4, 8, 16} recorded, `W` over {1, 4}, weights at B = 4 with shfl and mulhi never raised) | build-1 | the harness built at 11:2x BST; the smoke run and the chunks follow |
|
||||
| fg1 corners | the same harness pinned per cell: `IGNEUM_FG_LOSSY_CAP`, `IGNEUM_FG_WIDTH=4`, `IGNEUM_FG_SHAPE=64`, the combinations | build-1, build-3, build-4 as the pool frees | queued |
|
||||
|
||||
The coverage table (filled from the TSV rows at 16:xx BST for the 17:00 cut; the full read at 09:00 BST tomorrow):
|
||||
|
||||
| Stratum | Eras drawn | `r` per candidate | Mean attempt, max | Exhausted | min (c'') ratio (the worst era) | Under 0.995 (the (c''') refuse rate on the accepted draw) | Largest bucket ratio (worst era, site) | Largest bit bias in sigma (worst era, site, bit) |
|
||||
|---|---|---|---|---|---|---|---|---|
|
||||
| base (shipped draw) | pending | | | | | | | |
|
||||
| random (every axis drawn) | pending | | | | | | | |
|
||||
| lossy cap | pending | | | | | | | |
|
||||
| W = 4 | pending | | | | | | | |
|
||||
| shape 64 | pending | | | | | | | |
|
||||
|
||||
## 7. Owed by 09:00 BST on 9 October (the full report)
|
||||
|
||||
1. The coverage table of section 6 filled from the logs, with the per-stratum refuse rates and the union-bound arithmetic on the measured numbers, and the TSV rows and logs under `docs/analysis/class-v6/logs/`.
|
||||
2. The clean spread of the bucket ratio and the bit bias per stratum, so the two new ring-B tests get a bound and a clean refuse rate (not a guess).
|
||||
3. The lossy-corner `r` against the 0.85 line, and the exhaustion count at 10^4 seeds on that corner.
|
||||
4. The width-4 reading of (c'') and (c''') with the divided expectation, and the spec line for 1.4.6.5.
|
||||
5. The mixer rows at `m = 4` and 16 (adv-mixer-3's index and sac at k = 2 on two days; the SAT at k = 2) as the per-family corner rows, if the boxes have the cores after the other lanes' jobs arrive; else the plan with its hours.
|
||||
6. The F8-form census at 2^24 on 64 seeds of one lossy-cap era and one width-4 era, the first ring-C rows on the family (about 2 box-hours each).
|
||||
7. The gate-record JSON written for every era of the census from the TSV (the format of 4.3), and the summary.
|
||||
|
||||
## 8. Sources
|
||||
|
||||
In-tree (the mirror's master and lane branches at 8 October 2026, 11:00 BST): `docs/plans/cryptanalysis/in-house-pass.md` (sections 13 and 14, the nine lanes' close); `docs/analysis/attack-pass-2026-10.md` (F1 to F10; the sub-version 1, 2 and 3 re-gate tables; the tail attribution of 8 October, 09:40 to 09:46 BST); `docs/analysis/cryptanalysis/report-mixer-3.md` on branch adv-mixer-3 at 981bfff2 (the round margin); `docs/analysis/cryptanalysis/report-chained-cache-2.md` on adv-cache-2 at bfc3746c (section 2.3, the era-stride table); `docs/analysis/cryptanalysis/report-acceptance-rule-3.md` on adv-accept-3 at 7826d2b2 (Q1, Q1b); `docs/analysis/cryptanalysis/report-acceptance-rule.md` on adv-accept at 8f188e5a (row 90, the floor's tally, gap-deep); `docs/spec/01-lottery-hash.md` 1.4.6, 1.4.7, 1.8.4, 1.13; `docs/design/class-v5-stored-state.md` on class-v5 at 8f481459 (sections 11 and 14) and `docs/design/class-v5-harness/` (v5-attempts-census-1000.log, v5-census-4600-0.log); `docs/plans/counter-asic-3-status.md` section 7c; `docs/plans/read-width.md`; `docs/analysis/counter-asic-4-research.md` on counter-asic-4 at 7a133d76 (15.1a, 15.1b, 20.2a, 20.2b, 20.3); `docs/design/class-v6-rotating-family.md` on the same branch (the outline).
|
||||
|
||||
Public, read 8 October 2026:
|
||||
|
||||
- Hanley, J. A. and Lippman-Hand, A., "If nothing goes wrong, is everything all right? Interpreting zero numerators", JAMA 249(13), 1743 to 1745, 1983; the rule of three as a one-sided 95 percent bound 3/n on a binomial rate with zero events in n trials: https://en.wikipedia.org/wiki/Rule_of_three_(statistics)
|
||||
- Wilks, S. S., "Determination of Sample Sizes for Setting Tolerance Limits", Annals of Mathematical Statistics 12(1), 91 to 96, 1941; the nonparametric tolerance limit on the extreme order statistic, the same arithmetic as 2.1: https://www.projecteuclid.org/euclid.aoms/1177700380
|
||||
- Böhme, M., "STADS: Software Testing as Species Discovery", ACM TOSEM 27(2), 2018; the Good-Turing estimate `f_1 / n` of the discovery probability as the residual-risk bound of a testing campaign with no finding (the fuzzing-coverage view of section 2): https://arxiv.org/abs/1803.02130
|
||||
- OSTIF, "Four audits of RandomX for Monero and Arweave have been completed: results" (2019; Trail of Bits, X41 D-SEC, Kudelski Security, Quarkslab; no critical finding; the one-round AES diffusion and the BLAKE2 rows): https://ostif.org/four-audits-of-randomx-for-monero-and-arweave-have-been-completed-results/
|
||||
- Quarkslab, "Security audit of Monero RandomX" (2019; the "alternative configurations" caveat: the audits bounded the shipped configuration, which is the single-member reading this document generalises): https://blog.quarkslab.com/security-audit-of-monero-randomx.html
|
||||
- Least Authority, ProgPoW algorithm audit (final report 9 September 2019; the Ethereum Cat Herders, the Ethereum Foundation and Bitfly as clients): https://leastauthority.com/blog/2019/09/09/
|
||||
- The hardware audit of ProgPoW (Bob Rao, 2019; "works well against conventional ASIC strategies", the memory-intensive threat kept open), as reported: https://criptonoticias.com/mineria/desarrolladores-ethereum-presentan-resultados-auditoria-progpow
|
||||
443
docs/analysis/class-v6/hardware-future.md
Normal file
443
docs/analysis/class-v6/hardware-future.md
Normal file
|
|
@ -0,0 +1,443 @@
|
|||
# Class v6 research lane B: the hardware future, five years out
|
||||
|
||||
Lane B of the class v6 rotating-family research (the founder's word of 8 October 2026, 11:1x UK: "see if anything can be
|
||||
optimised, added or invented"). First cut landed 8 October 2026, 11:5x UK; the full report fills the same file. Every
|
||||
figure carries a label: **measured** (a number read off an instrument in this repository, with the file), **claimed**
|
||||
(a vendor's or a paper's number, with the URL and the date read), **modelled** (arithmetic on claimed figures by the
|
||||
method of `docs/analysis/chip-model-v3.md` section 5), **approximate** (from memory or an estimate; the sensitivity is
|
||||
given). Nothing here is a measurement of a chip. Reading public research is in-house; nothing was paid for or asked of
|
||||
anyone outside.
|
||||
|
||||
The question, as the coordinator put it: for each memory or packaging line, what does it do to a chip's cost per
|
||||
dependent random read over a dataset of 1 to 8 GiB that grows with chain state (energy per read, latency, capacity cost
|
||||
per GB, availability to a non-hyperscaler), what k band does it give the chip five years out, and which ONE of the four
|
||||
v6 layers (1: per-era parameter draws; 2: the state-sized dataset with a floor; 3: scheduled family epochs; 4: the
|
||||
(c''') acceptance floor and the F8 uniformity test per era) blunts it, with a number. Where a line beats every layer,
|
||||
this file says so with the number.
|
||||
|
||||
## 0. One page
|
||||
|
||||
The reads are the hash. Under class v3 the RTX 5090 spends 2.40 microjoules per hash on 128 dependent reads, 18.8 nJ
|
||||
per read all-in, and the memory system itself spends 2.0 nJ of that (chip-model-v3 5.3, modelled); the card's own
|
||||
marginal per dependent DRAM read is 10.9 nJ unlocked and 8.7 nJ at the 1,300 MHz lock (measured 8 October 2026,
|
||||
counter-asic-4-research 15.1a). Every chip in this file is a machine that pays the memory's nanojoule and not the
|
||||
card's ten, plus whatever the shadow (the program work drawn into the memory wait) forces it to pay at `k` times the
|
||||
GPU's cost per op. That identity does not change with any technology below; what changes is the memory's nanojoule,
|
||||
the rate a chip can read at, what a GB costs, and who can buy it.
|
||||
|
||||
**The three findings that change v6's design**
|
||||
|
||||
1. **The strongest five-year chip is not a DRAM chip. It is a 2 GiB SRAM full store on one reticle of merchant N2, and
|
||||
none of the four layers reaches it.** TSMC N2 reads 38 Mb/mm^2 of SRAM (claimed, IEEE Spectrum, 12 December 2024,
|
||||
volume in 2025), so 2 GiB is about 452 mm^2 of macro, one die under the 858 mm^2 reticle, roughly USD 400 to 600 of
|
||||
silicon at a USD 30,000 wafer (approximate). It has no activate ceiling, so its rate is power-bound: about 2,100
|
||||
MH/s at 300 W, 0.14 microjoules per hash, **13x to 17x the 5090 per joule at zero shadow and about USD 0.3 per
|
||||
MH/s** against the 5090's 14.7 and the GDDR7 chip's 2.8 (modelled; the wire energy, 0.5 to 2.0 nJ per read, is the
|
||||
sensitivity). Layer 2's floor moves its capex, not its joules: at 4 GiB it is two dies, at 8 GiB four, USD 1,000 to
|
||||
2,500 of silicon, and its edge per joule falls only from 17x to about 13x because an inter-die hop costs 0.27 nJ
|
||||
(UCIe, claimed 0.5 pJ/bit). A floor that would blunt it on joules (16 to 32 GiB, eight to sixteen reticles) retires
|
||||
every honest card under 32 GB first. The only lever that reaches it is the shadow at `k`: with the shadow core on
|
||||
the same N2 die the ALU band is 0.3 to 0.8 (the record's), and the class v4 premium holds **4.8x at k = 0.5, 2.7x
|
||||
at k = 1**; at the 5090's whole ALU budget (about 330,000 ops per hash, 575 W) 3.7x and 2.0x. The design change:
|
||||
layer 1's program-length draw is sized against this chip, not the GDDR7 board, with its lower bound at the shadow
|
||||
that holds the record's 2.1x today and its upper bound at the honest cards' full latency shadow, re-based every
|
||||
family epoch (layer 3) on the cards then mining; and the public "2x" line is not reachable in this model against
|
||||
this chip at any `k` under 1. What slows it is money and time (an N2 project, USD 100 M to 500 M and 18 to 24
|
||||
months, approximate), which is the clock of Counter ASIC 3.0 item 4, not a hash property.
|
||||
|
||||
2. **Per-bank processing-in-memory is structurally blind to this hash; the real near-memory threat is the custom
|
||||
HBM4E base die, and layers 1 to 4 do nothing to it.** HBM-PIM, AiM, LPDDR5X-PIM and UPMEM put a compute unit beside
|
||||
each bank (or a DPU per 64 MB); a dependent read's next address is uniform over the dataset, so it lands in the same
|
||||
bank with probability bank bytes over dataset bytes: **1.6 percent at 2 GiB on a 32 MB bank, 0.4 percent at 8
|
||||
GiB**, and UPMEM has "no direct communication channel among DPUs" (claimed, the PrIM paper), so the other 98
|
||||
percent of reads go to the host. The unit that can follow the chain across banks is a controller on the stack's
|
||||
base die, which is exactly what TSMC's custom C-HBM4E is: "the custom base die will integrate memory controllers and
|
||||
PHY" on N3P at 0.75 V, "2x the power efficiency", Micron production 2027, SK hynix HBM4E in 2026 (claimed,
|
||||
TrendForce, 1 December 2025). That is the `f = 1` chip of the record with its controller moved into the stack: about
|
||||
0.9 to 1.0 nJ per read, and HBM4's 32 channels (JEDEC JESD270-4, April 2025) double the activate-bound ceiling per
|
||||
stack, so **6.5x to 14x per joule at zero shadow** (the ceiling unmeasured, as the record's HBM rows are). The four
|
||||
layers act on the program, the item map and the capacity; this chip runs any program and holds 36 to 64 GB. What
|
||||
brakes it until about 2028 is availability (HBM allocated to AI, 20 to 26 week leads, Samsung asking USD 4 to 5 per
|
||||
Gbit for HBM4 against 1.5 for HBM3E, October 2026) and the shadow at `k`: 4.4x at k = 0.5, 2.6x at k = 1.
|
||||
|
||||
3. **The denominator is the wrong card.** Every chip edge in the record is quoted against the 5090 at 2.40 microjoules.
|
||||
The Apple M5 Max measured 0.78 microjoules per hash at the GPU-plus-DRAM meter (latency-shadow-2026-10-06, 6
|
||||
October 2026), 3.1x the 5090 per joule, and LPDDR6 SoCs (JEDEC JESD209-6, 2025; 14.4 Gbps, 32-byte atoms) are that
|
||||
tier's next step. Against the M5 Max the GDDR7 chip reads 1.7x, one HBM3 stack 2.4x, the HBM4 base die 3.6x to
|
||||
4.4x, the N2 SRAM die about 5x, and with the shadow at k = 0.5 the SRAM die reads about 3x. The honest joule, not
|
||||
the 5090's, is the chain's resistance, and the same chips are 2x to 3x less frightening against it. The design
|
||||
change: v6's acceptance floor (layer 4) and the shadow sizing (layer 1) are scored per card tier with the
|
||||
unified-memory SoC tier as the reference joule, the dataset is kept inside 16 GB unified memory (8 GiB at the top of
|
||||
the schedule does that), and the public text states the edge over the best honest joule, which is the number a
|
||||
miner can act on.
|
||||
|
||||
The honest line, in one sentence: five years out a 2 to 8 GiB dataset fits in one to four reticles of merchant SRAM at
|
||||
USD 500 to 2,500 of silicon, every DRAM line converges on the same 0.5 to 1.0 nJ per read with its controller in the
|
||||
stack, and no layer of the four touches either; the shadow at the measured `k` band holds 3x to 5x, the honest tier's
|
||||
own efficiency halves that again, and the clock (project cost against daily issuance) is the wall that is left.
|
||||
|
||||
## 1. The method and the denominators
|
||||
|
||||
| Quantity | Value | Label | Source |
|
||||
|---|---|---|---|
|
||||
| The 5090 at class v3 | 136.1 MH/s at 326 W, 2.40 microjoules per hash, 17.5 G dependent reads per second, 415 ns at 256 lanes, a 32-byte sector per 4-byte read | measured | `docs/bench-log.md`; chip-model-v3 5.1 |
|
||||
| The 5090 per dependent DRAM read, the whole card's marginal | 10.9 nJ unlocked, 8.7 nJ at the 1,300 MHz lock (dram_chase_1g, 18.17 G reads per second) | measured, 8 October 2026 | counter-asic-4-research 15.1a |
|
||||
| The 5090 L2 hit, per dependent read | 2.4 nJ unlocked, 1.4 nJ at the lock | measured | the same |
|
||||
| The 5090 per counted ALU op (the class v4 shadow's mix) | 11.3 pJ unlocked, 6.2 pJ at the lock (int_arx); the shadow's own 10.4 and 6.5 | measured | the same; counter-asic-4-research section 1 |
|
||||
| The 5090 at the 1,300 MHz lock, class v3 | 134.6 MH/s at 223 W, 1.67 microjoules | measured, 7 October 2026 | counter-asic-3-status 7c, the clock grid |
|
||||
| The class v4 premium `F` on the 5090 | 1.10 microjoules unlocked (145 W), 0.65 at the lock (82 to 88 W) | measured | the same |
|
||||
| Apple M5 Max, class v3, GPU plus DRAM channels | 27.08 MH/s at 21.0 W, 0.78 microjoules; class v4 at 100,000 ops 1.40 (+16 W); 6.9 pJ per counted op | measured, 6 October 2026 (the SoC's other rails and the wall are not in the 21 W) | `docs/analysis/latency-shadow-2026-10-06.md` section 3 |
|
||||
| RX 9070 XT, class v3 | about 18.6 MH/s at about 304 W, 10.6 microjoules; 2.4 G reads per second | rate measured, watts approximate | `docs/analysis/horizon/algorithm.md` 5.1 |
|
||||
| The memory system's own cost per random 32-byte read | GDDR7 2.0 nJ, HBM3 1.2 nJ | modelled on O'Connor et al. 2017 Tables 2 and 3 and Samsung's pJ per bit roadmap | chip-model-v3 5.3 |
|
||||
| The record's `f = 1` chips at zero shadow | GDDR7 board 166 MH/s at 77.6 W, 0.466 microjoules, 5.1x; one HBM3 stack 83.6 MH/s at 26.8 W, 0.321, 7.5x; eight stacks 666 MH/s at 174 W, 0.262, 9.2x | modelled | chip-model-v3 5.4 to 5.6 |
|
||||
| The chip's `k` on the shadow's work | ALU 0.3 to 0.8; int8 tile 0.03 to 0.3 (the worse lever); L2 hit 0.1 to 0.3; shuffle 0.4 to 0.7 | the GPU side measured, the chip side claimed | counter-asic-4-research 15.1a |
|
||||
|
||||
The chip's energy per hash is `E = 128 x E_read + P_static / rate + k x F`, the rate the smaller of the memory's
|
||||
activate-bound ceiling over 128 and the power budget over the per-hash energy, and the edge is the card's microjoules
|
||||
over the chip's. Two `k` columns appear below: `k_read`, the memory's energy per dependent read over the 5090's measured
|
||||
10.9 nJ (what the technology itself buys, independent of any program), and the shadow `k` band, the chip's cost per
|
||||
forced op over the GPU's, which no memory technology changes (it is a logic-node question: a chip core at N2 against a
|
||||
GPU at N3 or N4 sits at the band's low end, 0.3; at the same node, 0.5 to 0.8; approximate).
|
||||
|
||||
Reads are counted at the part's atom: 32 bytes on GDDR7, HBM3, HBM4 and LPDDR6 (each gives a 32-byte minimum access;
|
||||
JEDEC, claimed), 64 bytes on an SRAM macro or a line-based part. The class v6 read-width draw (4 to 64 bytes per read
|
||||
under layer 1) does not move any row: a chip's controller fetches the atom whatever the hash asks for, as the 5090
|
||||
fetches its 32-byte sector for a 4-byte load, and the record's w64 reading (the 5090 bandwidth-bound at 71.9 MH/s,
|
||||
chip-model-v3 5.7) says a wider honest read costs the card and gives the chip nothing. The dataset's size enters only
|
||||
through capacity cost and die count; its growth (layer 2) enters through the number of dies or stacks a chip must carry
|
||||
at each family epoch.
|
||||
|
||||
## 2. The table
|
||||
|
||||
Energy is per dependent random read at the part's atom. Latency is the read's own (controller to data), not the GPU's
|
||||
queueing. Cost per GB is factory-gate where a source gives it, with contract pricing about 2x (Silicon Analysts, October
|
||||
2026). "Edge" is per joule against the 5090 at class v3 and zero shadow; the bracket is against the M5 Max's 0.78.
|
||||
"Year" is when a non-hyperscaler could put the part on a board. Every chip-side figure is modelled unless labelled.
|
||||
|
||||
| Technology | Year | Energy per dependent read | Latency | Cost per GB | Availability to a non-hyperscaler | `k_read` (over 10.9 nJ) | Edge at zero shadow, per joule | The layer that blunts it, and by how much |
|
||||
|---|---|---|---|---|---|---|---|---|
|
||||
| GDDR7 on a PCB, 16 devices, a 28 nm controller (the record's `f = 1` chip) | now | 2.0 nJ (modelled); 4.5 pJ per bit streaming (claimed, Micron) | about 55 ns controller, tRC about 45 ns | USD 10 (2 GB parts, ending) to 20 to 23 (3 GB parts at USD 60 to 70), September 2026 (claimed, TrendForce) | anyone, through distribution; the 2026 DRAM price cycle (LTAs USD 7.8 to 21 per GB, May 2026, claimed) roughly triples the chip's memory bill against 2025 | 0.18 | 5.1x (1.7x); 166 MH/s at 78 W | none of the four; the shadow at k = 1 holds 2.1x (the record); the dataset's size does not matter because the chip over-provisions capacity for channels (16 devices whatever the dataset) |
|
||||
| GDDR7 at 36 to 48 Gbps, 4 and 6 GB devices | 2027 to 2028 (claimed, Micron roadmap via Guru3D and OC3D) | the same 2.0 nJ: the activate ceiling and the row energy do not move with the pin rate | the same | per-GB falls, per-channel rises: a random-read chip buys channels, not bytes | anyone | 0.18 | 5.1x | none; denser devices HURT the chip (fewer channels per GB), so this line goes the chain's way |
|
||||
| HBM3E, one stack, a 28 nm controller on a one-stack interposer | now | 1.2 nJ (modelled); 4.05 pJ per bit streaming (claimed, Samsung) | about 50 ns | USD 8.3 factory gate (USD 300 per 36 GB), about 2x on contract (claimed, Silicon Analysts, October 2026); plus about USD 200 of interposer | Tier-1 volume pricing, 20 to 26 week leads, "supply constrained through 2026" (claimed); a one-stack buyer pays broker prices | 0.11 | 7.5x (2.4x); 84 MH/s at 27 W (ceiling unmeasured, 10.7 G reads per second; 2.3 G at the JEDEC tFAW, which would read 1.8x) | none; the shadow at k = 1 holds 2.4x (the record) |
|
||||
| HBM4 (JESD270-4, April 2025): 2,048-bit, 32 channels x 2 pseudo-channels, 8 Gbps, 2 TB/s, 36 to 64 GB, VDDQ 0.7 to 0.9 V, a TSMC N12 base die at 0.8 V "1.5x efficiency" (claimed) | 2027 to 2028 for a non-hyperscaler | 1.0 to 1.1 nJ (modelled: the I/O term at 0.8 V against 1.1 V, the 909 pJ row activation unchanged) | about 50 ns | USD 15.3 (USD 550 per 36 GB, October 2026 estimate); Samsung asking USD 4 to 5 per Gbit for 2027 (USD 32 to 40 per GB) (claimed) | allocated to AI accelerators through 2027; "mid-to-high $4 per gigabit" in this month's negotiations (claimed, 2 October 2026) | 0.10 | 4.5x to 11x (1.5x to 3.6x): the 32 channels double the activate-bound ceiling per stack if tFAW is per channel (unmeasured) | none of the four; the shadow at k = 0.5 holds 4.4x, at k = 1 2.6x |
|
||||
| Custom HBM4E base die (C-HBM4E): the controller and PHY in the stack on N3P at 0.75 V, "2x the power efficiency" (claimed, TrendForce, 1 December 2025); Micron 2027, SK hynix 2026 | 2028 or later for a non-hyperscaler | 0.9 to 1.0 nJ (modelled: no interposer crossing for the controller's traffic) | about 45 ns | HBM4E class, USD 20 to 40, plus a custom base die (USD 50 to 100 per stack, approximate) | by design a per-customer product of the three DRAM makers; the named customers are NVIDIA and Google; a miner-maker of Bitmain's size could commission one (approximate) | 0.09 | 6.5x to 14x (2.1x to 4.4x) | **beats all four layers**; the shadow at k = 0.5 holds 4.4x, at k = 1 2.6x; the shadow core sits on the same N3P base die |
|
||||
| Fine-grained, hybrid-bonded DRAM on logic (FGDRAM-class 256-byte rows, "tFAW effectively eliminated", 51 percent lower energy per access, 4x bandwidth, claimed, O'Connor et al., MICRO 2017; hybrid-bonded stacks and 3D DRAM on the 2028 to 2030 roadmaps, approximate) | 2029 to 2031 | 0.5 to 0.7 nJ (modelled: 230 pJ activation for a 256-byte row plus about 1.2 pJ per bit of movement over bonded pads) | about 40 ns | HBM class, USD 15 to 40 (approximate) | custom, the three DRAM makers, top customers first | 0.05 | 12x to 20x (4x to 6x); about 125 MH/s per stack at 19 W, 1,000 MH/s at 150 W for eight | **beats all four layers**; the shadow at k = 0.5 holds 5.1x, at k = 1 2.8x |
|
||||
| Per-bank PIM: Samsung HBM-PIM (a PCU per bank, 2021), SK hynix GDDR6-AiM (16 Gbps, 1.25 V, 2022) and AiMX (32 GB card), Samsung LPDDR5X-PIM (Hot Chips, 25 August 2026, 614 GB/s internal) and LPDDR6-PIM (JEDEC work "substantial progress") | now to 2027 | the host memory's own: 1.8 nJ (HBM2), 2.0 (GDDR6 class); the PIM unit never sees the read it would need | the same | the host part's plus a premium | HBM-PIM and AiM were samples and prototypes; LPDDR5X-PIM mass production "as early as 2027" (claimed) | n/a: no path for a cross-bank dependent read | none beyond the base-die row: the unit serves 1.6 percent of reads at 2 GiB (a 32 MB bank), 0.4 percent at 8 GiB | layer 2, trivially: any dataset over a bank; the number is bank bytes over dataset bytes |
|
||||
| UPMEM DPU-in-DRAM: 128 DPUs per 8 GB DIMM, 64 MB MRAM per DPU, 350 MHz, MRAM by DMA at most 628 MB/s per DPU, "no direct communication channel among DPUs" (claimed, the PrIM paper, 2021); 1.2 W per 4 Gb chip, 10x DRAM's price at sampling, 1.5x projected (claimed, The Next Platform, 2020) | now | about 0.3 microseconds per 64-byte DMA at 350 MHz (approximate from the paper's alpha-plus-beta model); 2 GiB spans 32 DPUs and every cross-DPU hop is a host round trip of microseconds | microseconds | 1.5x to 10x DDR4 | anyone, in server DIMMs | n/a | none: dead at any dataset over 64 MB | layer 2's floor alone (2 GiB = 32 DPUs with no path between them) |
|
||||
| LPDDR6 (JESD209-6, 2025): 24-bit channels as two 12-bit sub-channels, 32-byte minimum access, 10.7 to 14.4 Gbps, 4 to 64 Gb dies (claimed, JEDEC via PCWorld and HotHardware) | 2026 to 2028 | 1.5 to 2.0 nJ (approximate: short rows, low-voltage I/O over a PCB, 16 to 32 banks per channel) | about 60 ns | USD 8 to 21 in the 2026 cycle (LTAs, claimed); about USD 3 to 4 in 2024 (approximate) | anyone; it is also the honest SoC tier's memory | 0.15 to 0.18 | about 4x to 5x for a 32-channel controller chip (1.3x to 1.6x against the M5 Max, which already IS this part with a GPU) | none needed: the honest tier converges on it; see finding 3 |
|
||||
| 3D DRAM (Samsung VS-DRAM 16 layers, VCT 4F2; Neo 3D X-DRAM 230 layers; SK hynix and Micron stacked cells), "from 2030" (claimed, heise, 29 May 2024) | 2030 or later | no vendor claims a latency or activate change; the row energy class is the planar part's (approximate) | the same | lower per GB after 2030 | the three makers | 0.1 to 0.2 | the DRAM rows above | none needed inside five years; it lowers the chip's and the card's capacity cost alike |
|
||||
| RLDRAM 3 (Micron, 2011): tRC under 10 ns, 16 banks, no activate command, "SRAM-like random access" (claimed, Micron); 576 Mb and 1.125 Gb devices at 2,133 Mb/s (approximate) | now, in small volume | 2 to 4 nJ (approximate: a full small-row access per read; no energy figure found, the datasheet's power calculator exists) | under 10 ns | USD 400 to 800 (USD 50 to 100 per 1.125 Gb device, approximate, a networking part) | anyone, catalogue | 0.2 to 0.4 | about 2 G random reads per second PER DEVICE (16 banks over 8 ns), 32 G for 16 devices: 250 MH/s per board, about 5x per joule (approximate) | layer 2: USD 3,000 to 6,000 of memory at 8 GiB; the line to watch is AMD's "Folded Banks" (ISCA 2025): 8x the activate parallelism in HBM gives 6.7x the irregular bandwidth (claimed, the abstract) |
|
||||
| FPGA with HBM2e: AMD Alveo V80 (Versal XCV80, 32 GB, 820 GB/s, 190 W, USD 9,495 MSRP, May 2024, claimed), Versal HBM VH1782, Altera Agilex 7 M (two HBM2e stacks, 820 GB/s), Alveo U55C USD 4,747 | now | HBM2 class, 1.8 nJ, but the fabric's controller reaches only the JEDEC tFAW ceiling: 2.3 to 2.4 G reads per second per stack (Shuhai, FCCM 2020; the record) | about 100 ns | USD 300 per GB of card | anyone, 10 to 24 week leads | 0.17 | 0.6x (0.2x): 4.8 G reads per second for two stacks, about 37 MH/s at 150 W, at 5x the 5090's price | none needed; no HBM3E FPGA was found announced (unverified) |
|
||||
| Wafer-scale SRAM: Cerebras WSE-3, 44 GB SRAM, 21 PB/s, 900,000 cores, 46,225 mm^2 on N5 (claimed, Cerebras and The Next Platform, March 2024); CS-3 about 23 kW and "maybe $2.5 million" (claimed, approximate) | now, by the system | about 7 nJ (approximate): a 512-bit reply crossing about 140 mm of mesh on average at about 0.1 pJ per bit per mm | about 0.5 microseconds across the wafer | USD 50,000 per GB | by the system only | 0.6 | 0.1x to 0.4x: a uniformly random dependent chain is bisection-bound on a 2D mesh (about 110 G reads per second per wafer, up to 500 G with the dataset replicated twenty times), 5 to 22 M reads per second per watt against the 5090's 54 M; 1/1,000 per dollar | none needed; layer 2 removes the replicas as the dataset grows |
|
||||
| CXL memory pools (CXL 2.0 and 3.x; about 70 ns of controller on top of local DDR5, 100 to 160 ns on Xeon 6 against 75 local, claimed, Introl, February 2026; USD 4 to 7 per GB before the 2026 cycle) | now | DDR5's 2 to 3 nJ plus the link | 170 to 250 ns through a host | USD 4 to 21 | anyone | 0.2 to 0.3 | 0.4x: 500 M 64-byte transactions per second per x8 device at about 25 W (approximate) | none needed; a capacity tool, not a random-read engine |
|
||||
| Optical I/O: Ayar Labs TeraPHY (UCIe-compliant, about 5 pJ per bit, USD 500 M raised 3 March 2026, claimed); Celestial AI Photonic Fabric (6.2 pJ per bit, about 120 ns round trip, claimed) | 2027 or later | 6x to 8x the interposer's 0.8 pJ per bit per bit moved | plus 120 ns | n/a | n/a | worse than copper for this traffic | no edge: a pooling fabric; the dependent chain wants the memory closer, not farther | none needed |
|
||||
| Chiplets and die-to-die: UCIe 0.25 to 0.5 pJ per bit (claimed, UCIe via SNIA); BoW 0.5 to 0.7; CoWoS-S USD 600 to 900 per H100-class package, a one-stack interposer about USD 200 (the record) | now | adds 0.27 nJ per 544-bit read that crosses a die boundary | plus 5 to 10 ns per hop | the package: USD 100 to 200 organic with UCIe-S, USD 200 to 900 for 2.5D | UCIe IP from several vendors; CoWoS capacity booked by AI through 2027 (approximate) | n/a | moves the SRAM chip's multi-die rows (below) and lets a 28 nm controller sit beside memory on an organic package | none needed |
|
||||
| SRAM scaling at 2 nm: TSMC N2 38 Mb/mm^2 HD, +11 percent over N3E (claimed, IEEE Spectrum, 12 December 2024); wafers about USD 30,000, booked to 2028 (claimed, 2026) | now (N2 in volume from 2025) | 1.0 nJ for a 64-byte read from a 452 mm^2 array (approximate; 0.5 to 2.0: the global wire at about 1.3 pJ per bit across a 24 mm die is the term) | 10 to 20 ns | USD 200 to 300 per GB of silicon (one 600 mm^2 die, about USD 400 to 600, holds 2 GiB) | N2 is a merchant node: any customer with a project (Apple, AMD, NVIDIA, MediaTek, Qualcomm; the Bitcoin chip makers are on N3 and N4 class already, approximate) | 0.09 | **13x to 17x (4x to 5x)**: no activate ceiling, power-bound at about 2,100 MH/s per die at 300 W, USD 0.3 per MH/s of silicon; two dies at 4 GiB and four at 8 GiB cost USD 1,000 to 2,500 and read about 13x | **beats layers 1, 3 and 4; layer 2 cuts its capex, not its joules**: one reticle at 2 GiB, two at 4 GiB, four at 8 GiB; the shadow at k = 0.5 holds 4.8x, at k = 1 2.7x; on the M5 Max's joule about 3x at k = 0.5 |
|
||||
|
||||
Density against the schedule: SRAM gains 6 to 11 percent per node every two to three years (N3E +6, N2 +11, claimed),
|
||||
the dataset doubles every four years (spec 1.13.3: 2 GiB at genesis, 4 GiB at year 4). The SRAM chip loses that race
|
||||
slowly: its die count doubles each doubling and its per-read energy rises 0.1 to 0.3 nJ per extra hop. It does not lose
|
||||
it inside five years.
|
||||
|
||||
## 3. What each line does to the four layers, read the other way
|
||||
|
||||
| Layer | What it does to the lines above | Number |
|
||||
|---|---|---|
|
||||
| 1. Per-era draws (mixer rounds, op-mix weights, read width, program length, shadow placement) | The read width and the mixer draws move no chip row: every chip in the table stores the dataset and reads the atom. The program length IS the shadow, and it is the only draw that reaches the memory-system chips | at `F` = 1.10 microjoules (class v4) the strongest DRAM chip reads 2.6x to 2.8x at k = 1 and 4.4x to 5.1x at k = 0.5; at the full 5090 shadow (`F` about 2.0) 2.0x and 3.7x |
|
||||
| 2. The state-sized dataset with a floor | Kills per-bank PIM and UPMEM outright; raises the SRAM chip's die count and capex; does nothing to any DRAM chip, which carries 24 to 64 GB per stack and over-provisions capacity for channels anyway | PIM serves 1.6 percent of reads at 2 GiB, 0.4 at 8; the SRAM chip's silicon USD 500 at 2 GiB, 1,000 at 4, 2,500 at 8, its joules 17x to 13x |
|
||||
| 3. Scheduled family epochs every 180 days | None of the chips in the table is fixed-function; the controller chip runs any program and the SRAM chip's shadow core is a sequencer | 0 |
|
||||
| 4. The (c''') floor and the F8 uniformity test per era | Keeps the hot-set cache at the record's 1.067x ceiling; the L2 hit at 2.4 nJ on the 5090 against 0.2 to 0.5 on a chip means the uniformity test is what stops a small cache from being the chip's edge | 1.067x at the ceiling (the record) |
|
||||
| A fifth: the denominator | The honest tier's own operating point is the resistance: the 5090 at the lock reads 1.67 microjoules, the M5 Max 0.78; every chip edge halves to thirds against them | the SRAM die 5x and the base die 3.6x to 4.4x against the M5 Max at zero shadow; about 3x with the shadow at k = 0.5 |
|
||||
|
||||
## 4. The lines in detail
|
||||
|
||||
### 4.1 Processing-in-memory and processing-near-memory
|
||||
|
||||
Samsung's HBM-PIM (Aquabolt-XL, February 2021) places a programmable computing unit inside each bank of an HBM2 stack
|
||||
and reports 2.5x system performance and over 60 percent energy saved on a Xilinx Alveo host (claimed, Samsung, 24
|
||||
August 2021). SK hynix's GDDR6-AiM (February 2022) adds compute to a 16 Gbps GDDR6 die at 1.25 V, claims up to 16x on
|
||||
some AI operations and 80 percent less power, and the AiMX card (2023) carries 32 GB of it (claimed, SK hynix). Samsung's
|
||||
LPDDR5X-PIM (Hot Chips, 25 August 2026) reaches 614 GB/s inside the package against 76.8 GB/s over the external
|
||||
interface at LPDDR5X-9600, 3x the tokens per second on Llama 3.1 8B, with mass production "as early as 2027" and
|
||||
LPDDR6-PIM in JEDEC work (claimed, TrendForce and Sammyfans, 25 to 26 August 2026). UPMEM's DPU-in-DRAM ships: 128
|
||||
DPUs per 8 GB DIMM, 64 MB per DPU, 350 MHz, MRAM reached only by DMA with a fixed cost plus a per-byte cost and at most
|
||||
628 MB/s per DPU for 2,048-byte transfers, and "there is no direct communication channel among DPUs" (claimed, the PrIM
|
||||
characterisation paper, arXiv 2105.03814, read 8 October 2026). The academic line (IMPICA, ICCD 2016: a pointer-chasing
|
||||
engine on a 3D stack's logic layer, 1.2x to 1.9x and 10 to 41 percent less energy on linked lists, hash tables and
|
||||
B-trees, claimed) puts the chaser on the base die, not in the bank, for the same reason this hash defeats the bank
|
||||
units: the next address is anywhere.
|
||||
|
||||
What it does to the chip's cost per dependent read: nothing good for the attacker at the bank level. The PIM unit's
|
||||
arithmetic is the wrong kind (FP16 SIMD, not 32-bit integer ARX) and the wrong place: with uniform addresses the chain
|
||||
leaves the bank after one read with probability 1 minus bank bytes over dataset bytes (98.4 percent at 2 GiB on a 32 MB
|
||||
bank), and in UPMEM's case leaves the DPU with no path but the host. The near-memory version (a chaser with its own
|
||||
controller on the base die) is the record's `f = 1` chip, and that is where PNM becomes real: see 4.2.
|
||||
|
||||
Blunted by: layer 2, by the dataset's size alone. k: none (no path).
|
||||
|
||||
### 4.2 HBM3E, HBM4 and the custom base die
|
||||
|
||||
JEDEC's JESD270-4 (16 April 2025; read via eeNews Europe, 18 April 2025, and the search summaries, the Business Wire
|
||||
and All About Circuits pages refusing the fetch) doubles the channel count to 32 with two pseudo-channels each on a
|
||||
2,048-bit interface at up to 8 Gbps, 2 TB/s per stack, 4 to 16-high stacks of 24 or 32 Gbit dies up to 64 GB, VDDQ 0.7
|
||||
to 0.9 V and VDDC 1.0 to 1.05 V (claimed). TSMC builds the standard HBM4 base die on N12 at 0.8 V for "roughly 1.5x"
|
||||
efficiency and the custom C-HBM4E base die on N3P at 0.75 V for "2x the power efficiency of today's DRAM
|
||||
manufacturing", and "the custom base die will integrate memory controllers and PHY components typically housed
|
||||
separately"; Micron targets 2027 production, SK hynix a first tailored HBM4E in the second half of 2026 with 12 nm for
|
||||
mainstream and 3 nm for NVIDIA and Google premium designs, Samsung 4 nm now and 2 nm for custom HBM (claimed,
|
||||
TrendForce, 1 December 2025 and 23 January 2026). Prices: HBM2e USD 120 per 16 GB, HBM3 200 per 24, HBM3E 300 per 36,
|
||||
HBM4 about 550 per 36 (estimate), factory gate, with contract about 2x and 20 to 26 week leads (claimed, Silicon
|
||||
Analysts, October 2026); Samsung is asking "mid-to-high $4 per gigabit" for 2027 HBM4 against about 1.5 for HBM3E
|
||||
(claimed, Sammyfans, 2 October 2026).
|
||||
|
||||
What it does to the chip's cost per read: the row activation (909 pJ per 1 KB row, HBM2, O'Connor Table 3) does not
|
||||
move; the movement and I/O terms fall with the voltage and the base-die node; a 32-channel stack doubles the activate
|
||||
parallelism the record's HBM rows are bound by (10.7 G reads per second per HBM3 stack, unmeasured; 2.3 G at the JEDEC
|
||||
tFAW). The arithmetic on the record's method: HBM4 1.0 to 1.1 nJ per read and 21.3 G reads per second per stack (166
|
||||
MH/s at about 36 W, 0.22 microjoules, 11x; at the JEDEC-tFAW ceiling 36 MH/s at 19 W, 0.53, 4.5x); the custom base die
|
||||
0.9 to 1.0 nJ with its controller inside (166 MH/s at 29 W, 0.18, 14x; 6.5x at the low ceiling). The latency stays in
|
||||
the 45 to 50 ns class; the capacity (36 to 64 GB) is 4x to 8x any floor layer 2 could set without retiring the honest
|
||||
cards.
|
||||
|
||||
Who can buy it: through 2027 the stacks are allocated to AI accelerators at Tier-1 volume terms; a custom base die is a
|
||||
per-customer engagement with the DRAM maker. A chip maker of Bitmain's or Canaan's size (the history's rows: tape-outs
|
||||
on 7 nm-class nodes, R&D in the tens of millions of dollars a year) could commission one from 2028 (approximate); a
|
||||
USD 5 M startup cannot. The brake is money and queue, not physics, and it expires.
|
||||
|
||||
Blunted by: nothing among the four. The shadow at `k` = 0.5 holds 4.4x, at `k` = 1 2.6x; the shadow core is logic on
|
||||
the N3P base die and sits at the band's low end against a GPU on an older node.
|
||||
|
||||
### 4.3 LPDDR6
|
||||
|
||||
JESD209-6 (2025) gives 10,667 to 14,400 MT/s on a 24-bit channel split into two 12-bit sub-channels, a 32-byte minimum
|
||||
access with 32 and 64-byte bursts, 4 to 64 Gb dies, lower voltages than LPDDR5, a dynamic efficiency mode and on-die
|
||||
ECC (claimed, JEDEC via PCWorld, HotHardware and MicrocontrollerTips, 2025). The bank count per channel and the tFAW
|
||||
are not in the public summaries read (unverified); LPDDR5's 16 banks per channel and a tFAW near 20 ns are the
|
||||
assumption (approximate). A 32-channel, 64-sub-channel controller chip then reads about 12.8 G dependent reads per
|
||||
second (approximate), 100 MH/s, at 1.5 to 2.0 nJ per read: about 4x to 5x the 5090 per joule, the GDDR7 board's class
|
||||
at a lower price per channel. The dies are the cheapest random-access memory a non-hyperscaler can buy outside the
|
||||
2026 price cycle (USD 3 to 4 per GB in 2024, approximate; USD 8 to 21 in 2026 LTAs, claimed).
|
||||
|
||||
The point of this line is not the chip. The M5 Max already is an LPDDR5X part with a GPU, at 0.78 microjoules per hash
|
||||
measured at the GPU-plus-DRAM meter, 3.1x the 5090 per joule; the Windows-class LPDDR5X SoCs (NVIDIA's and Qualcomm's
|
||||
desktop parts, approximate) and the LPDDR6 generation after them are the honest tier's floor. A controller chip on the
|
||||
same memory beats that tier by 1.3x to 1.6x at zero shadow. The resistance of the chain is set by this tier, and v6
|
||||
should say so (finding 3).
|
||||
|
||||
Blunted by: none needed.
|
||||
|
||||
### 4.4 3D DRAM
|
||||
|
||||
Samsung's VS-DRAM (VLSI 2023), 16 stacked layers demonstrated against Micron's 8, VCT 4F2 cells as the stepping stone
|
||||
with prototypes in 2025 and commercial 3D DRAM "by approximately 2030"; Neo Semiconductor's 3D X-DRAM at 230 layers
|
||||
and 128 Gbit per die as a concept (claimed, heise 29 May 2024, Yole, ComputerBase). No source read claims a latency or
|
||||
activate-rate change; the gain is capacity per area (about 3x). For a chip that reads 1 to 8 GiB at random, capacity
|
||||
per die is not the constraint (channels are), so 3D DRAM lowers the honest card's and the chip's cost per GB alike and
|
||||
changes no row. Outside the five-year edge.
|
||||
|
||||
### 4.5 CXL memory pools
|
||||
|
||||
CXL 2.0 expanders on Xeon 6 measure 100 to 160 ns against 75 ns local DDR5; a CXL 3.1 controller adds about 70 ns;
|
||||
pooled DDR5 was USD 4 to 7 per GB before the 2026 cycle (claimed, Introl, 1 February 2026, and the search summaries).
|
||||
A dependent chain through a host CPU and a PCIe-class link at 64 bytes per transaction is bound by the link's
|
||||
transaction rate (about 500 M per second per x8 device at about 25 W, approximate): 0.4x the 5090 per watt. A capacity
|
||||
tool. No edge, no layer needed.
|
||||
|
||||
### 4.6 Wafer-scale
|
||||
|
||||
The WSE-3 holds 44 GB of SRAM at 21 PB/s across 900,000 cores on 46,225 mm^2 of N5; the CS-3 draws about 23 kW and
|
||||
costs "maybe $2.5 million" (claimed, Cerebras and The Next Platform, 14 March 2024; the power from the search summaries).
|
||||
A 2 GiB dataset spread over the wafer is read by a dependent chain whose next address is uniformly random across 215
|
||||
mm of mesh: the traffic is all-to-all, the mesh is bisection-bound, and the average reply crosses about 140 mm of wire.
|
||||
At about 0.1 pJ per bit per mm (approximate) a 512-bit reply costs about 7 nJ before routers, 3x the GDDR7 board's
|
||||
2.0; at about 950 links across the bisection at 32 bits per cycle and about 1 GHz (approximate), the wafer completes
|
||||
about 110 G reads per second, 500 G with the dataset replicated twenty times in regions, 5 to 22 M reads per second per
|
||||
watt against the 5090's 54 M. Per joule 0.1x to 0.4x, per dollar one thousandth. The wafer is a streaming machine; this
|
||||
hash is not streaming. No layer needed; layer 2 removes the replicas as the dataset grows.
|
||||
|
||||
### 4.7 Chiplets, interposers and optical I/O
|
||||
|
||||
UCIe gives 0.25 to 0.5 pJ per bit by package type (claimed, UCIe consortium via SNIA SDC 2022 and 2025 pages); BoW 0.5
|
||||
to 0.7; CoWoS-S is USD 600 to 900 per H100-class package and a one-stack interposer about USD 200 (the record). A
|
||||
read that crosses a die boundary pays about 0.27 nJ (544 bits at 0.5 pJ) and 5 to 10 ns, which is what makes the
|
||||
multi-die SRAM chip of 4.9 cost 1.1 to 1.3 nJ per read instead of 1.0. Optical I/O (Ayar Labs' TeraPHY at about 5 pJ
|
||||
per bit, UCIe-compliant, a USD 500 M round on 3 March 2026; Celestial AI's Photonic Fabric at 6.2 pJ per bit and about
|
||||
120 ns round trip; claimed) is 6x to 8x the interposer's energy per bit and adds latency: it pools memory across
|
||||
packages, which this traffic never wants. No row moves.
|
||||
|
||||
### 4.8 FPGA with HBM
|
||||
|
||||
The Alveo V80 (Versal XCV80, 32 GB HBM2e as two 16 GB stacks, 820 GB/s, 190 W, USD 9,495 MSRP, May 2024) and the U55C
|
||||
(USD 4,747) are what a non-hyperscaler can buy today with HBM on it; Altera's Agilex 7 M-series carries the same two
|
||||
HBM2e stacks at 820 GB/s (claimed, AMD, Wccftech, The Next Platform). The record's reading stands: an HBM2 stack under a
|
||||
soft controller reaches the JEDEC tFAW ceiling, 2.3 to 2.4 G random reads per second (Shuhai, FCCM 2020, Figure 7),
|
||||
so two stacks give about 4.8 G, about 37 MH/s at about 150 W (approximate), 0.6x the 5090 per joule at 5x its price. No
|
||||
HBM3E FPGA was found announced in the pages read (unverified). No layer needed.
|
||||
|
||||
### 4.9 SRAM at 2 nm: the full store on one reticle
|
||||
|
||||
TSMC's N2 reads 38 Mb/mm^2 of high-density SRAM, 11 percent over N3E (claimed, IEEE Spectrum, 12 December 2024;
|
||||
volume from 2025); wafers are about USD 30,000 and "booked to 2028" (claimed, tech-insider, 2026). The arithmetic: 2
|
||||
GiB is 17,180 Mbit, 452 mm^2 of macro; with periphery, a controller, the lanes' registers and a shadow core, a 550 to
|
||||
650 mm^2 die under the 858 mm^2 reticle; about 95 gross dies per wafer, 55 to 70 percent good with row and column
|
||||
repair (approximate), USD 400 to 600 of silicon. No DRAM, no interposer, an organic package. Under class v5 the
|
||||
dataset's items are leaves of the chain state refreshed per window; the chip rewrites 2 GiB per window at on-die
|
||||
bandwidth, the same 32 ms every GPU pays (the record, chip-model-v3 5.10), and holds a node or shares one across a farm
|
||||
as the record prices.
|
||||
|
||||
Energy per read: the macro's 64-byte read, about 0.1 nJ (approximate), plus the global wire. The record took 0.6 pJ per
|
||||
bit of wire across a 128 mm^2 array; scaling with the side of the die gives about 1.3 pJ per bit across 600 mm^2, 0.68
|
||||
nJ for 512 bits, so about 1.0 nJ per read with the controller, range 0.5 to 2.0 (the sensitivity of every SRAM figure
|
||||
here). Latency 10 to 20 ns. No activate ceiling, no tFAW, no refresh: the rate is power-bound. At 300 W with 30 W of
|
||||
static and controller power: 270 W over 128 nJ per hash is about 2,100 MH/s per die, 0.14 microjoules per hash, 17x
|
||||
the 5090 at zero shadow (13x at 1.3 nJ, 8x at 2.0, 30x at 0.5); USD 0.25 per MH/s of silicon, about 0.4 with the
|
||||
board. Two dies at 4 GiB: half the reads cross one UCIe hop, 1.14 nJ, 15x, USD 1,000. Four dies at 8 GiB: 1.3 nJ, 13x,
|
||||
USD 2,000 to 2,500, a 4-die organic package. The honest cards hold 8 GiB fine (16 GB and up); a floor that pushed the
|
||||
dataset past what a package can hold (16 to 32 GiB, eight to sixteen reticles at USD 5,000 to 10,000 and 1.5 to 2.0
|
||||
nJ per read, still 7x to 9x) would retire every honest card under 32 GB first. Layer 2 therefore sets this chip's
|
||||
capex and die count, not its joules, and the floor's number is a card-lifetime decision, not a chip decision.
|
||||
|
||||
The project: the history's IBS figures (5 nm USD 416 M to 542 M, 3 nm 590 M) price an SoC; an SRAM array with a
|
||||
controller and a sequencer core is simpler and the startup figure ("$50M to $75M" for 7 nm, SemiAnalysis) is the
|
||||
better guide, so USD 100 M to 500 M at N2 (approximate) and 18 to 24 months to a first chip (approximate). That is the
|
||||
clock of Counter ASIC 3.0 item 4 and the daily-issuance threshold of the history (chips at USD 20 K to 50 K of daily
|
||||
issuance for compute-bound hashes; 32 months for Ethash at the largest prize): the SRAM chip arrives when the prize
|
||||
pays for an N2 project, and nothing in the hash moves that date.
|
||||
|
||||
Blunted by: layer 2 on capex only (USD 500 to 2,500 across the floor's range); the shadow at `k` on joules: with the
|
||||
shadow core on the same N2 die against a GPU on N3 or N4 the ALU band sits at 0.3 to 0.5; at `F` = 1.10 the chip reads
|
||||
4.8x at k = 0.5 and 2.7x at k = 1; at the 5090's whole latency shadow (about 330,000 ops per hash, `F` about 2.0,
|
||||
575 W) 3.7x and 2.0x; against the M5 Max's joule about 3x at k = 0.5.
|
||||
|
||||
### 4.10 RLDRAM and the activate-free line
|
||||
|
||||
RLDRAM 3 (Micron, 2011; ISSI second-sourced) has a tRC under 10 ns, 16 banks per device, no separate activate
|
||||
command and "SRAM-like random access" (claimed, Micron's product page and the 2011 announcements), in 576 Mb and 1.125
|
||||
Gb devices at up to 2,133 Mb/s (approximate). One device completes about 2 G random reads per second (16 banks over 8
|
||||
ns), six times a GDDR7 device's share of the 5090 board's 21.3 G; sixteen devices, 2 GiB, about 32 G reads per second,
|
||||
250 MH/s per board. The energy per read is not published in anything read (a power calculator exists); a full
|
||||
small-row access per read at an old node reads 2 to 4 nJ (approximate), so about 5x per joule, at USD 400 to 800 per
|
||||
GB (approximate, a low-volume networking part). It is the proof that an activate-free DRAM exists, and AMD's "Folded
|
||||
Banks" (ISCA 2025, with AMD Research: 8x the activate parallelism in a 3D-stacked HBM gives 6.7x the irregular
|
||||
bandwidth, claimed from the abstract; the PDF refused the fetch) is the same idea on the HBM roadmap. If a DRAM maker
|
||||
ships it in HBM, the activate ceilings in the record's HBM rows rise 6x to 8x and the HBM chip's rate per stack with
|
||||
them; its energy per read falls by the row-size term (O'Connor's FGDRAM: 51 percent). That is the DRAM-on-logic row.
|
||||
|
||||
Blunted by: layer 2 on RLDRAM's capacity cost (USD 3,000 to 6,000 at 8 GiB); nothing on the HBM version.
|
||||
|
||||
## 5. The k bands for the research lane's chip rows
|
||||
|
||||
For `docs/design/class-v6-rotating-family.md`. The shadow `k` is the chip core's energy per forced op over the GPU's
|
||||
at the same operating point (the record's ALU band 0.3 to 0.8 on the 5090's measured 6.2 to 11.3 pJ per op); the
|
||||
memory `k_read` is the technology's energy per dependent read over the 5090's measured 10.9 nJ. "Edge" is per joule at
|
||||
zero shadow; "with the shadow" is at the class v4 premium `F` = 1.10 microjoules on the 5090 (`E_chip` = `E_mem` + `k F`).
|
||||
|
||||
| Chip row | Year | `E_read` nJ | Rate per chip, MH/s | `E_hash` at zero shadow, microjoules | Edge over the 5090 (2.40) | Edge over the M5 Max (0.78) | `k_read` | Shadow `k` band | With the shadow, k = 0.5 / 1 | Silicon and memory, USD per MH/s |
|
||||
|---|---|---|---|---|---|---|---|---|---|---|
|
||||
| GDDR7 board, 28 nm controller (the record) | now | 2.0 | 166 | 0.466 | 5.1x | 1.7x | 0.18 | 0.5 to 0.8 (28 nm core: the high end) | 3.3x / 2.1x | 2.8 (2025 memory), about 7 in the 2026 cycle |
|
||||
| HBM3E, one stack | now | 1.2 | 84 (ceiling unmeasured) | 0.321 | 7.5x | 2.4x | 0.11 | 0.3 to 0.8 | 3.8x / 2.4x | 6.6 |
|
||||
| HBM3E, eight stacks | now | 1.2 | 666 | 0.262 | 9.2x | 3.0x | 0.11 | 0.3 to 0.8 | 4.1x / 2.5x | 4.0 |
|
||||
| HBM4, one stack, N12 base die | 2027 to 2028 | 1.0 to 1.1 | 166 (36 at the JEDEC tFAW) | 0.22 (0.53) | 11x (4.5x) | 3.6x (1.5x) | 0.10 | 0.3 to 0.8 | 4.4x / 2.6x | about 5 |
|
||||
| Custom HBM4E base die, N3P, controller in the stack | 2028 or later | 0.9 to 1.0 | 166 (36) | 0.18 (0.37) | 14x (6.5x) | 4.4x (2.1x) | 0.09 | 0.3 to 0.5 (an N3P core) | 4.4x / 2.6x | about 5 |
|
||||
| DRAM on logic, FGDRAM-class rows, hybrid bonded | 2029 to 2031 | 0.5 to 0.7 | 125 per stack, 1,000 for eight | 0.15 | 16x (12x to 20x) | 5.2x | 0.05 | 0.3 to 0.5 | 5.1x / 2.8x | about 4 (approximate) |
|
||||
| SRAM full store, one N2 reticle, 2 GiB | 2027 to 2028 (an N2 project) | 1.0 (0.5 to 2.0) | about 2,100 at 300 W | 0.14 | 17x (8x to 30x) | 5.6x | 0.09 | 0.3 to 0.5 (an N2 core) | 4.8x / 2.7x | 0.25 to 0.4 |
|
||||
| SRAM full store, two N2 dies, 4 GiB | the same | 1.14 | about 1,850 | 0.16 | 15x | 4.9x | 0.10 | 0.3 to 0.5 | 4.6x / 2.7x | 0.55 |
|
||||
| SRAM full store, four N2 dies, 8 GiB | the same | 1.3 | about 1,600 | 0.185 | 13x | 4.2x | 0.12 | 0.3 to 0.5 | 4.5x / 2.6x | 1.3 to 1.6 |
|
||||
| LPDDR6 controller chip, 32 channels | 2027 | 1.5 to 2.0 | about 100 | 0.25 to 0.30 | 4x to 5x | 1.3x to 1.6x | 0.15 to 0.18 | 0.3 to 0.8 | 3.1x / 2.0x | about 3 (approximate) |
|
||||
| Per-bank PIM, UPMEM, FPGA with HBM2e, wafer-scale, CXL, optical | | | | | under 1x or no path | | | | | |
|
||||
|
||||
Arithmetic, the SRAM row: 270 W over (128 x 1.0 nJ) = 2.11 G hashes per second; 300 W over 2.11 G = 0.142
|
||||
microjoules; 2.40 over 0.142 = 16.9x; with the shadow at k = 0.5: (0.142 + 0.55) over (2.26 + 1.10) = 0.692 over 3.36 =
|
||||
4.86x; at k = 1: 1.242 over 3.36 = 2.71x. The base-die row: 166 M x 128 x 0.95 nJ = 20.2 W plus 4 static plus 5
|
||||
controller = 29.2 W; 29.2 over 166 M = 0.176 microjoules; 2.40 over 0.176 = 13.6x. The M5 Max column divides 0.78 by
|
||||
the same `E_hash`. Every chip-side figure is modelled; the GPU-side figures are the record's measurements.
|
||||
|
||||
## 6. Consequences per tier
|
||||
|
||||
| Tier | What this file means | What is being done |
|
||||
|---|---|---|
|
||||
| Home miner, one 8 GB card | Nothing changes today: no chip exists, and the first one in this file (an N2 SRAM die or an HBM4 base-die chip) is a USD 100 M-class project with a 2028-class date. When one lands it runs at 0.14 to 0.22 microjoules per hash against this card's 10 to 20; this tier is the first out, as the record says. The dataset's floor decides this tier's life more than any chip does: 4 GiB at year 4 (the spec's schedule) retires it then | the shadow sizing and the floor are the founder's numbers to set (section 7); the share-pattern detector (Counter ASIC 3.0 item 4) is what tells this miner a chip has arrived |
|
||||
| One 16 GB card (9070 XT class) | Holds 8 GiB with room; AMD's 2.4 G reads per second at 304 W is 7x behind the 5090 per joule and 50x to 100x behind the chips here | the vendor-share metric; nothing in the hash moves AMD's dependent-read rate |
|
||||
| One 24 or 32 GB card, the 5090 at the lock | 1.67 microjoules at the 1,300 MHz lock; the chips here are 8x to 12x ahead per joule at zero shadow and 2.5x to 4x with the class v4 shadow at k = 0.5 | the Ember knob carries the lock rows; the shadow's upper bound at the full ALU budget is the lever this file sizes |
|
||||
| The unified-memory SoC (M5 Max, LPDDR5X and LPDDR6 desktops) | 0.78 microjoules at the GPU-plus-DRAM meter: the honest tier the chips beat least (1.7x to 5.6x at zero shadow, about 3x with the shadow). Capex-poor (27 MH/s per USD 4,000 machine) but joule-rich | finding 3: v6 scores the floor and the shadow per tier with this tier as the reference joule; the dataset stays inside 16 GB unified memory |
|
||||
| A rig | A rig's cost is electricity; against an N2 SRAM chip at USD 0.3 per MH/s and 0.14 microjoules it earns 1/10 to 1/17 of a chip per watt and leaves when chips hold the hashrate | the issuance trigger: the bounty and the benchmark live before daily issuance crosses about USD 50 K (the record) |
|
||||
| A pool user | A chip fleet is a few operators; the share-pattern detector is the warning | the detector on the observer, before the public testnet (the record) |
|
||||
| The public claim | "Under 2x" is not reachable against any chip in this file at a `k` under 1. The honest sentence is: the strongest chip five years out beats a 5090 by 2.6x to 2.8x per joule at k = 1 and about 4.5x at k = 0.5 with the shadow on, and the best honest SoC by about 3x; and it costs an N2 project | the research lane's synthesis carries the number; nothing from this file goes to the site or the devnet |
|
||||
|
||||
## 7. Decisions this raises for the founder
|
||||
|
||||
Each carries a default and a deadline; silence means the default.
|
||||
|
||||
1. **Size the shadow against the SRAM chip, not the GDDR7 board.** Layer 1's program-length draw gets a lower bound at
|
||||
the length that holds the record's 2.1x on the GDDR7 chip today and an upper bound at the honest cards' full latency
|
||||
shadow (the 5090's about 330,000 ops unlocked, about 150,000 at the lock; the M5 Max about 290,000; the 9070 XT
|
||||
about 650,000; approximate from the record), re-based at every family epoch on the cards then mining. Default: the
|
||||
research lane writes the draw with these bounds into the synthesis; the hash lane measures the rate and the watts at
|
||||
the upper bound on the 5090 and the M5 Max before the first v6 era is cut. Deadline: 20:00 UK today (the synthesis).
|
||||
2. **The floor (layer 2).** 2 GiB at genesis is one N2 reticle; 4 GiB two; 8 GiB four. The floor moves the chip's
|
||||
capex (USD 500 to 2,500), not its joules (17x to 13x), and 8 GiB is the last size inside 16 GB unified memory and
|
||||
the 16 GB card tier. Default: the spec's schedule stands (2 GiB plus 0.5 GiB a year, doubling at year 4), chosen on
|
||||
card lifetime; the floor is not a chip lever and this file does not ask to raise it. Deadline: none; a note in the
|
||||
synthesis.
|
||||
3. **The reference joule (a fifth layer, or a rule).** Resistance is stated against the best honest joule (the
|
||||
unified-memory SoC tier, then the 5090 at the lock), not the unlocked 5090. Default: the research lane adopts it in
|
||||
the synthesis's chip rows (section 5's M5 Max column) and the public text, when there is one, carries the edge over
|
||||
the best honest joule. Deadline: 20:00 UK today.
|
||||
4. **The clock.** The chips in this file are USD 100 M-class projects with 2028-class dates; the issuance trigger, the
|
||||
benchmark and the share-pattern detector of Counter ASIC 3.0 item 4 are what decide when they are built. Default:
|
||||
unchanged from the record. Deadline: none.
|
||||
|
||||
## 8. Unverified and owed
|
||||
|
||||
- Every chip-side energy figure is modelled on the record's method (O'Connor's HBM2 breakdown, Samsung's pJ per bit
|
||||
roadmap, the 909 pJ row activation standing in for HBM3, HBM4 and GDDR7); the SRAM wire figure (0.6 pJ per bit at 128
|
||||
mm^2, scaled with the die's side) is from memory and moves the SRAM rows by 2x either way; the UCIe hop (0.5 pJ per
|
||||
bit) is the consortium's claim; the FGDRAM row size (256 bytes) and its 51 percent are the paper's simulation.
|
||||
- HBM4's banks per pseudo-channel and tFAW per channel are behind the JEDEC paywall (the Business Wire and All About
|
||||
Circuits pages refused the fetch); the "2x the activate ceiling" rests on 32 channels with tFAW per channel, as the
|
||||
record's HBM rows rest on the same assumption at 16; both unmeasured. The AWS F2 hour the record names (chip-model-v3
|
||||
5.3) is still the one measurement that would settle the HBM2 figure, and an HBM3 or HBM4 part is not rentable at the
|
||||
controller level by anyone outside a hyperscaler today.
|
||||
- LPDDR6's bank count and tFAW are not in the summaries read; the row is LPDDR5's structure (approximate).
|
||||
- RLDRAM 3's energy per read and its 2026 price are not published in anything read; the row is approximate.
|
||||
- The Cerebras mesh figures (link width, clock, bisection) are approximate; the fabric bandwidth was not on the pages
|
||||
read (The Next Platform gives only its change against WSE-2).
|
||||
- Dates: the DRAM-on-logic and hybrid-bonded HBM timelines ("2028 to 2031") are approximate; the sources read give
|
||||
3D DRAM "from 2030" and C-HBM4E production in 2027; the hybrid-bonding pages were not fetched (the TrendForce page
|
||||
refused). The N2 project cost and time are approximate.
|
||||
- The web-search budget of this session ran out at about 11:3x UK after 26 searches; the remaining facts were read by
|
||||
direct fetch of the pages named in section 9. Pages that refused (403): JEDEC's Business Wire release, All About
|
||||
Circuits, ACM's Folded Banks page, OC3D's GDDR7 capacity note, All About Circuits' HBM-PIM note. Their figures are
|
||||
carried from the search summaries and marked claimed.
|
||||
- Nothing was run on the Mac; nothing was built or benchmarked anywhere. The one measurement this file would want next
|
||||
is on the record's queue already: the 5090 and the M5 Max at the shadow's upper bound (decision 1).
|
||||
|
||||
## 9. Sources (URL and the date read; all read 8 October 2026 unless a file is named)
|
||||
|
||||
Repository: `docs/analysis/chip-model-v3.md` (sections 5.1 to 5.11, 6); `docs/analysis/counter-asic-4-research.md`
|
||||
on branch counter-asic-4 at fb61ed4b (sections 1, 15.1a, 20.4); `docs/analysis/asic-resistance-history.md` (2.5, 2.6);
|
||||
`docs/plans/counter-asic-3-status.md` (7c, the clock grid); `docs/spec/01-lottery-hash.md` (1.8, 1.13.3, 1.14);
|
||||
`docs/analysis/latency-shadow-2026-10-06.md`; `docs/analysis/sram-mirror.md`.
|
||||
|
||||
- JEDEC HBM4 (JESD270-4, 16 April 2025): https://www.eenewseurope.com/en/hbm4-standard-doubles-channel-count-for-ai-boost (18 April 2025); https://hothardware.com/news/jedec-finalizes-hbm4-spec; https://www.businesswire.com/news/home/20250416843598/en (refused)
|
||||
- TSMC HBM4 and C-HBM4E base dies: https://www.trendforce.com/news/2025/12/01/news-tsmc-unveils-custom-c-hbm4e-details-n3p-logic-dies-reportedly-target-2x-efficiency-gain/ (1 December 2025); https://www.trendforce.com/news/2026/01/23/news-samsungs-custom-hbm4e-design-reportedly-aimed-for-mid-2026-parallels-sk-hynix-and-micron/ (23 January 2026)
|
||||
- HBM prices: https://siliconanalysts.com/data/hbm-pricing (October 2026); https://www.sammyfans.com/2026/10/02/samsung-seeks-more-than-3x-hbm3e-pricing-for-hbm4/ (2 October 2026); https://www.trendforce.com/news/?p=62555
|
||||
- GDDR7 prices and roadmap: https://www.trendforce.com/news/2026/09/24/news-micron-reportedly-ends-2gb-gddr7-narrowing-supply-options-for-nvidias-rtx-50-series/ (24 September 2026); https://www.guru3d.com/story/micron-fiveyear-roadmap-shows-24gb-36gbps-gddr7-in-2026; https://overclock3d.net/?p=314548 (refused; the 4 and 6 GB parts in 2027 to 2028 from the search summary)
|
||||
- DRAM prices 2026: https://wccftech.com/mobile-dram-prices-expected-to-increase-by-100-quarter-over-quarter-as-long-term-agreements-now-getting-signed-at-prices-as-high-as-21-gb/ (4 May 2026); https://tech-insider.org/ddr5-ram-prices-2026/
|
||||
- Samsung HBM-PIM: https://news.samsung.com/global/samsung-brings-in-memory-processing-power-to-wider-range-of-applications (24 August 2021); https://www.allaboutcircuits.com/news/beyond-high-bandwidth-memory-samsung-breaks-processing-in-memory-into-AI-applications/ (refused)
|
||||
- SK hynix AiM and AiMX: https://news.skhynix.com/developed-processing-in-memory (2022); https://www.hc2024.hotchips.org/assets/program/conference/day1/11_HC2024.SKhynix.GuhyunKim.rev920240822.pdf
|
||||
- Samsung LPDDR5X-PIM and LPDDR6-PIM: https://www.sammyfans.com/2026/08/25/samsung-unveils-lpddr5x-pim-dram/ (25 August 2026); https://www.trendforce.com/news/2026/08/26/news-samsungs-4nm-gaia-could-mark-first-pim-commercialization-in-ai-pcs-mass-production-as-early-as-2027/ (26 August 2026); https://en.fnnews.com/news/202609060934024282
|
||||
- UPMEM: https://arxiv.org/pdf/2105.03814 (the PrIM characterisation, text extracted with pdftotext: Table 1, section 3.2, the inter-DPU statement); https://www.nextplatform.com/2020/02/04/putting-in-memory-processing-through-the-paces/ (4 February 2020); https://old.hotchips.org/hc31/HC31_1.4_UPMEM.FabriceDevaux.v2_1.pdf
|
||||
- IMPICA: https://ghose.cs.illinois.edu/papers/16iccd_impica.pdf (ICCD 2016)
|
||||
- Fine-grained DRAM: https://www.cs.utexas.edu/~skeckler/pubs/MICRO_2017_Fine_Grained_DRAM.pdf (text extracted with pdftotext: 3.92 pJ per bit per HBM2 access, 1.21 of it activation, the 256-byte row, tFAW "effectively eliminated", 51 percent)
|
||||
- Folded Banks (ISCA 2025): https://dl.acm.org/doi/10.1145/3695053.3731111 (refused today; the abstract as the record read it on 6 October 2026); https://wantongli.ucr.edu/news/announcement22-ISCA%202025
|
||||
- LPDDR6: https://www.pcworld.com/article/2845759/lpddr6-memory-standard-announced-as-ddr5-dram-takes-over.html; https://hothardware.com/news/jedec-lpddr6-standard-released; https://www.microcontrollertips.com/what-is-jesd209-6-and-why-is-it-important-for-edge-ai/
|
||||
- CXL: https://introl.com/blog/cxl-memory-expansion-pooling-disaggregated-memory-ai-data-center-2025 (1 February 2026); https://www.snia.org/sites/default/files/2025-09/SNIA-SDC25-Peethambaran-CXL-as-scalable-cost-effective-Memory.pdf
|
||||
- Cerebras: https://www.cerebras.ai/chip; https://www.nextplatform.com/2024/03/14/cerebras-goes-hyperscale-with-third-gen-waferscale-supercomputers/ (14 March 2024); https://sacra.com/c/cerebras-systems ("a couple million per system")
|
||||
- FPGA with HBM: https://wccftech.com/amd-announces-mass-production-of-the-alveo-v80-compute-accelerator-9495-price-tag/ (17 May 2024); https://www.amd.com/en/products/accelerators/alveo/u55c/a-u55c-p00g-pq-g.html; https://www.nextplatform.com/2022/03/08/a-cornucopia-of-memory-and-bandwidth-in-the-agilex-m-fpga; https://arxiv.org/abs/2005.04324 (Shuhai)
|
||||
- 3D DRAM: https://heise.de/en/news/Huge-RAM-3D-DRAM-with-multiple-layers-planned-from-2030-9738064.html (29 May 2024); https://www.yolegroup.com/industry-news/samsung-reveals-16-layer-3d-dram-plans-with-vct-dram-as-a-stepping-stone/
|
||||
- RLDRAM 3: https://www.micron.com/products/memory/dram-components/rldram-memory; https://newelectronics.co.uk/content/news/micron-unveils-third-generation-rldram-technology (2011); https://arxiv.org/pdf/1810.07059
|
||||
- SRAM at N2: https://spectrum.ieee.org/tsmc-n2-2670436570 (12 December 2024); https://marklapedus.substack.com/p/intel-tsmc-tout-sram-breakthroughs; wafer prices https://tech-insider.org/tsmc-2nm-wafer-price-2026/
|
||||
- UCIe and BoW: https://www.snia.org/sites/default/files/2025-05/SNIA-SDC22-Sharma-Universal-Chiplet-Interconnect-Express.pdf; https://www.3dtested.com/news/new-ucie-chiplet-standard-supported-by-intel-amd-and-arm
|
||||
- Optical: https://www.theregister.com/2026/03/03/ayar_labs_500m/ (3 March 2026); https://www.allpcb.com/allelectrohub/photonic-interconnects-aim-to-solve-ai-memory-bottlenecks (the Celestial AI figures)
|
||||
- H100 pointer-chase latency (353 ns, claimed): https://arxiv.org/pdf/2608.15764
|
||||
333
docs/analysis/class-v6/history.md
Normal file
333
docs/analysis/class-v6/history.md
Normal file
|
|
@ -0,0 +1,333 @@
|
|||
# Class v6 research lane A, history: every ASIC-resistant proof of work, how it fell or held, and what that binds on the four layers
|
||||
|
||||
8 October 2026, branch `class-v6-history`, the Counter ASIC coordinator's history lane. The founder's word at 11:1x UK: class v6 is declared with four layers as its spine, and the research opens "see if anything can be optimised, added or invented". This file extends and corrects `docs/analysis/asic-resistance-history.md` (5 October 2026, the deep dive: 31 rows, 24 papers, ten lessons, seven ranked additions); it does not repeat that file's rows. What is new here: the exact MECHANISM of every chip (what it specialised: the memory, the hash core, the instruction mix, the parameter fixity), what each design missed, the timeline from announcement to chip to response, and for each one the mapping to class v6's four layers with "does v6 close it" in one sentence and one number. Every figure about another chain cites a URL with the date it was read, or is labelled approximate. Every Igneum figure names the repo file. Reading public research is in-house; nothing is paid or asked of anyone outside.
|
||||
|
||||
First cut landed on the mirror's master at 11:26 UK on 8 October (merge 4c58ad65: the table, the mechanisms, the three lessons), ahead of the 15:00 clock; this revision folds in the synthesis lane's reading of the six items (`docs/design/class-v6-rotating-family.md` section 7b) and cross-cites lane B's hardware file; the full report by 09:00 UK on 9 October carries any row the other lanes move. A line goes to the coordinator and to the synthesis lane at each landing.
|
||||
|
||||
## 0. One page
|
||||
|
||||
**The four layers, as declared, against the history's chip classes.** Every chip that ever beat a resistant hash belongs to one of five classes; the table says which layer of v6 answers each class, and with what number. "Closes" means the chip's measured or claimed edge falls under 2x per joule by a mechanism the layer supplies; "does not close" means the layer does not touch the chip's edge, and the number stands.
|
||||
|
||||
| Chip class (the rows of section 1 it covers) | What the chip specialised | Its best measured edge | Which v6 layer answers it | Does v6 close it | The number after v6 |
|
||||
|---|---|---|---|---|---|
|
||||
| A. Fixed-function pipeline on a compute-bound hash (X11, Blake-256, Blake2b, Blake2s, kHeavyHash, Eaglesong, Blake3, SHA512/256d, NexaPow, X16R's FPGA) | the hash's round function unrolled in silicon; the instruction mix fixed at genesis | 33x to 1,280x per joule (Antminer KA3, D3, KS5 Pro) | layers 1 and 3 (the op mix, program length and families drawn or unlocked per era; already closed since class v2 by the per-epoch random program) | yes, and it was already closed: a per-epoch program has no round function to unroll | 0 of 128 loads and 0 of 512 program ops are a fixed function; what remains is class E |
|
||||
| B. SRAM-scale memory (Scrypt's 128 KB, CryptoNight's 2 MB, Lyra2REv2's sponge, Cuckatoo's edge bitmap, Equihash's 144 MB) | the hash's whole working set on die or across a few dies, with a time-memory trade-off the designer had not drawn | 19x to 1,100x (Scrypt), 40x to 50x (CryptoNight X3), 12x to 100x (Equihash Z9 to Z15), 4x (Cuckatoo G1) | layer 2 (the dataset above any SRAM die, growing with chain state with a floor; the 256 MiB cache growing with it) | yes: the recompute chip that holds the cache on die reads 0.92x at the op budget and 1.86x per joule, and the cache's size forces it onto a 7 nm or better node | `chip-model-v3.md` section 2 and 5.4: 0.31x bare, 0.92x with the 3x factor, 1.86x per joule at f = 0; the curve from f = 0 to 1 is monotone and the partial-store chip is worse than both ends |
|
||||
| C. The memory system without the GPU (the Ethash chips: Linzhi Phoenix, Jasminer X4, Antminer E9; the f = 1 chip of the model) | a controller and PHY for the same DRAM the card carries, a 32-byte atom per read, no shader, no scheduler, no clock tree; 55 W of memory without the 271 W of GPU | 2.1x to 4.8x per joule measured (Ethash, 2020 to 2022); 5.1x (GDDR7) to 7.5x (one HBM3 stack) modelled for Igneum at zero premium | none of the four directly: every per-era draw is firmware to a chip that stores the dataset; layer 2 only when the dataset passes the chip's board | **NO.** The f = 1 chip keeps 5.1x per joule on GDDR7 at zero premium and 2.1x with the class v4 shadow at k = 1; v6's draws move neither figure. What moves it is the honest card's own joules (the operating point, 3.6x at the 1,300 MHz knee) and the shadow's premium | 5.1x / 3.6x / 2.1x (zero premium unlocked / knee / knee with the shadow at k = 1), `counter-asic-4-research.md` sections 0 and 20.4; the chip's USD 2.8 per MH/s against the card's 14.7 |
|
||||
| D. The firmware-survivable chip against periodic change (Monero's chips across four forks, Vorick's "survives forks at under a 5x hit", the X16R FPGA, the Equihash chip "able to follow parameter forks") | a programmable sequencer over the hash's op set; the per-block or per-fork change read as a configuration | chips back at 85 percent of Monero's hashrate four months after the v8 fork; 1.3x on X16R | layers 1 and 3 are the automatic form of the change those chains made by hand; they cost no governance event | partly: v6 closes the GOVERNANCE failure (no fork, no reset of the hashrate to a rentable size) and taxes die area for the reserve; it does not close the chip, because a reserve and a draw band readable at genesis are built in from day one | the draw's cost to the chip is a recompile per epoch and a new dataset mapping per era; the number is the "GPU without graphics" of ledger M1, which is class C's chip with a sequencer beside it: 5.1x less the shadow's k |
|
||||
| E. The hot set and the steered address (Kik's 64-bit seed on ProgPoW, Dinur-Nadler on MTP, AP-F8-1 on class v4, the weak-day MUL draw) | a small SRAM serving the reads a biased draw or a cooperating node concentrates | 1.067x at v4's ceiling (0.52 to 4.6 percent of reads on 0.1 percent of items); a memory skip on ProgPoW 0.9.3; MTP from 2 GB to under 1 MB | layer 4 (the (c''') floor and the F8-form uniformity test generalised to every era's draw, with a redraw on failure) | yes, for the class the test models: the floor at 0.995 refuses every live hot set the in-house pass found (nine, 0.9809 to 0.9919) at 0.7 percent of candidates | `docs/spec/01-lottery-hash.md` 1.4.7.2 (class v5); the open residue is the shadow-written concentrations at 0.9992 to 0.9997, worth about 1.0004x to a chip |
|
||||
|
||||
**The three lessons that bind on v6** (section 3 has the evidence):
|
||||
|
||||
1. **The chip that stores the dataset is firmware-immune to every draw; only joules and memory growth move it.** Every per-era parameter (mixer rounds, op weights, read width, program length, shadow placement) and every family epoch is read by the f = 1 chip's sequencer as a configuration, as Monero's chips read four forks and X16R's FPGA read the per-block order. The number v6 inherits is 5.1x per joule at zero premium (2.1x with the shadow at k = 1), and the lever is the honest card's operating point and the shadow's premium, not the draw.
|
||||
2. **Automatic change beats the human fork only where it costs the chip a redesign, and the one parameter that does is the memory.** Grin's six-monthly tweaks held because each was a new algorithm the lane was scheduled to retire; Monero's forks lost on the second lap; Ethash's DAG growth is the one scheduled change in the record that killed a shipped chip (the E3, when the DAG passed its 4 GB of DDR3). Layer 2 is that lesson made a rule, and its rate decides everything: at 2 GiB plus 0.5 GiB a year a 32 GB chip board outlives the chain, so layer 2 as declared ages out the honest 8 GB card before any chip unless the floor is set against DRAM cost per gigabyte, not against chain state.
|
||||
3. **A steered or biased address pattern is always found after launch unless the test lives in the acceptance rule, and every new draw needs its own null.** ProgPoW's seed, MTP's blocks and class v4's lossy sources were the same attack three times; layer 4 puts the test where it must be, and its cost is one census per era draw on the node (2.2 s per candidate at 2^20 today) with the null re-derived for every drawn parameter, because the window model that defines "uniform" changes with the read width and the program length.
|
||||
|
||||
**What the history says to add** (section 5): a layer 2 floor and a per-tier ceiling stated before its rate (the synthesis lane has since made the ceiling layer 2's first constant); the issuance clock and the share-pattern detector (unchanged from the 5 October ranking, still unbuilt); the read width's draw band stopped where the honest card stops being latency-bound ({4 B, 16 B} on the measured warrant, nothing wider); the op-mix band bounded by the per-vendor energy table; the reserve ordered by what a sequencer chip cannot fold into firmware.
|
||||
|
||||
## 1. The chips, one row per mechanism
|
||||
|
||||
Columns: the hash; the chip (vendor, model); the mechanism (what it specialised); what the design missed; the timeline (hash live, to the chip, to the response); the v6 layer that answers it; does v6 close it; the number (the chip's measured or claimed per-joule edge, and what the layer leaves). Every ratio is arithmetic on the cited rate and watt figures of the chip and the best consumer GPU of its year, approximate by construction; section 2 carries the sources. "Closed at v2" means the per-epoch random program already removed the mechanism and v6 inherits it.
|
||||
|
||||
| Hash (chain) | Chip | Mechanism: what it specialised | What the design missed | Timeline | v6 layer | Closed by v6 | The number |
|
||||
|---|---|---|---|---|---|---|---|
|
||||
| Ethash (Ethereum) | Bitmain Antminer E3 | 18 chips with 4 GB of commodity DDR3; "a memory interface connected to a small compute engine" | the hash needs only a memory interface; and the chip's memory was under-sized | live Jul 2015; chip announced Apr 2018, shipped Jul 2018; died by DAG growth Mar to Oct 2020 | 2 (the only layer that reached it) | class C: no | 1.0x to 1.1x per joule; the DAG passed its 4 GB at 20 to 27 months |
|
||||
| Ethash | Innosilicon A10, A10 Pro, A11 Pro | the same with faster, larger DRAM (6 to 8 GB) | as above | Jul 2018 to Dec 2021 | none | no | 1.4x to 2.5x |
|
||||
| Ethash | Linzhi Phoenix (E1400) | 64 compute units and 72 mixers per board beside 4.4 GB of "decentralized memory inside its ASIC"; sized to the DAG | memory energy per bit is the whole cost; many small memories by many small cores cut it | announced Sep 2018; tapeout Sep 2019; samples Dec 2020; no mass production | none | no | 2.1x to 2.2x |
|
||||
| Ethash | Jasminer X4 (Sunlune) | DRAM dies hybrid-bonded (wafer-to-wafer DBI) onto a 40/45 nm logic die, 5 GB per unit, 40 chips per server | off-package DRAM at 3 to 4 pJ per bit was the cap; bonding takes it under 1 | Jun 2021 chip; Oct 2021 ship; the Merge 11 months later | none | no | 5.1x (about 7.3 pJ per bit all in) |
|
||||
| Ethash | Bitmain E9, E9 Pro | conventional, 6 to 7 GB | as the E3, four years of DRAM later | Jul 2022 (8 weeks before the Merge); Feb 2023 | none | no | 3.0x, 4.1x |
|
||||
| ProgPoW (never on Ethereum; KawPow, FiroPoW, ProgPowZ, Quai) | none; Linzhi claimed 3x to 8x with no derivation; one academic VU35P FPGA at 5.6 MH/s | a sequencer over eleven ops reads the per-period program as configuration (unbuilt); the on-die cache chip priced at "<< 0.1x" energy (unbuilt) | the light-evaluation chip was left as a suggestion; a 64-bit seed (Kik) | EIP May 2018; audits Sep 2019; exploit Mar 2020; dead Mar 2020; no chip on any adopter in 6 years | 1, 3 (the period made an era draw), 4 (the seed class) | class D and E yes; the Rao chip is class C, no | claimed 1.1x to 1.2x for the compute chip; the memory-system chip never priced; Igneum's reads 5.1x |
|
||||
| RandomX (Monero) | Bitmain Antminer X5 | many RISC-V chips on a board over commodity DRAM: an in-order machine for a fixed VM spec; insides never published | CFROUND's cost on x86, a scratchpad-only AES circuit, the latency slack of a fixed 256-instruction program (v2's own list) | live Nov 2019; private mining from about 2021; X5 Sep 2023; X9 announced Dec 2025 and withdrawn May 2026 (zero shipped); v2 released Mar 2026, activation pending | 1 (program length and op mix drawn, which v2 had to fork to change) | class D: yes for the class; the gap itself has no GPU analogue | 1.46x (X5, measured); 3.8x (X9, claimed, never shipped); 5.4x (Pinecone R1X, claimed, undelivered) |
|
||||
| CryptoNight (Monero) | Bitmain Antminer X3 (180 x BM1700); Baikal Giant N; secret chips from early 2017 | one or two 2 MB scratchpads in on-die SRAM with a hardware AES round per chip (inference from 1.2 kH/s at 2.6 W per chip) | the working set was a 2014 L3, which is a die | live Apr 2014; secret chips about 33 months; X3 announced at 47 and bricked by the v7 fork before delivery; chips back inside 4 months of v8; none in CN-R's 9 months | 2 (the dataset above any die); 1 and 3 (CN-R's per-block program is Igneum's per-epoch one) | yes | 40x (X3 against a Vega 64); Igneum's f = 0 chip 1.86x per joule |
|
||||
| Cuckatoo31 (Grin) | Obelisk GRN1 (cancelled) | one TSMC 16 nm die with 512 MiB of SRAM holding the node bits, lean mining; 150 GPS at 800 W per chip | the resource was SRAM size at 320 MB, and a die was designed for it | hash live Jan 2019; announced Jan 2019; sold Apr; cancelled Jul 2019 | 2 | yes (closed at v3) | 50x planned; the 2025 bounty: memory trades for time, not energy |
|
||||
| Cuckatoo32 (Grin) | iPollo G1 (30 x 12 nm chips) | node bits on die, the 512 MB edge bitmap in serial DRAM (the design's geometry; the G1's own split unpublished) | half the working set stayed in DRAM | Dec 2020, 23 months | 2 | yes | 3x |
|
||||
| Equihash 200,9 (Zcash) | Bitmain Z9 mini, Z9 (BM1740); A9; Z11; Z15 Pro | the whole 144 MB working set on one die ("about 128 MB", eDRAM or SRAM); the Fudan NDSS 2019 design: an on-die linear sorter with the lists in off-chip DDR4, parameter-independent | the 1,000x halving penalty had no proof; 144 MB fit a die; a chip was designed to follow any (n, k) | live Oct 2016; secret chips before May 2018; Z9 mini at 18 months; Z15 Pro at 80 | 2 (a 2 GiB set is not a die); the parameter-following chip is layer 1's warning | yes by layer 2 | 12x (Z9 mini) to 110x (Z15 Pro); the Fudan design 13x in simulation |
|
||||
| Scrypt (Litecoin) | Innosilicon A2; KnC Titan; Antminer L3+ (BM1485); L7 (BM1489) | one 128 KB scratchpad of on-die SRAM per core, 12 cores per 28 nm chip (L3+), 7 nm with 480 chips (L7); Percival's own lookup gap (half the memory for 25 percent more work) | the scratchpad was a 2011 cache; the time-memory trade favoured the chip at 2x to 4x by the designer's note | live Oct 2011; A2 Apr 2014 (30 months); L3+ Jun 2017; L7 Nov 2021 | 2 | yes | 70x (A2) to 1,300x (L7); Igneum's f = 0 chip 1.86x |
|
||||
| Scrypt-N (Vertcoin 2014) | none; dropped pre-emptively | an automatic N doubling a chip follows with more SRAM or a wider lookup gap | public and slow growth sizes the chip for years | Jan 2014 to Dec 2014 | 2 (the precedent) | n/a | no chip shipped |
|
||||
| Lyra2REv2 (Vertcoin) | FPGA bitstreams (2018), then Dayun Zig Z1 | a sponge of about 200 KB per core on die (approximate); 28 nm | SRAM-scale memory inside a hash chain | live Aug 2015; FPGA 2018; Z1 Sep 2018 (37 months); fork Feb 2019 | 2 | yes | 20x |
|
||||
| X16R (Ravencoin) | CVP-13 FPGA bitstreams; OW1 and SKC Turing R1 | sixteen fixed cores with per-block routing | the draw changed the order, not the hardware | live Jan 2018; FPGA named Sep 2018; 45 percent of blocks by Jul 2019; fork Oct 2019; chips "evident" again Jan 2020 | 1 (the warning) | the fixed-function lane closed at v2; the draw is governance | 0.75x (OW1) to 5x (R1) |
|
||||
| MTP, Argon2d (Zcoin) | none; Dinur-Nadler's attack before launch | the prover steers the data-dependent addresses into under 1 MB at a 170x penalty | the attacker controlled the memory's contents | 2017 attack; live Dec 2018; replaced Oct 2021 | 4 | yes (the day key is a VDF of chain state; the floor refuses hot sets) | 2 GB to under 1 MB; Igneum's residue about 1.0004x |
|
||||
| Yescrypt, yespower | none | L2-latency-bound sequential work; small prizes | n/a | 2014 on | 2 | n/a | no chip |
|
||||
| KawPow, Autolykos v2, Octopus, Verthash, FishHash | none | DRAM-scale random reads on small prizes | untested at a prize that pays for a controller project | 2020 to 2024 | 2 | class C: not tested | no chip; the Ethash record is their test |
|
||||
| kHeavyHash (Kaspa) | IceRiver KS0 to KS5L; Antminer KS3, KS5 Pro | a fixed 64 x 64 nibble matrix pipeline | compute with a matrix in it is the cheapest silicon there is | live Nov 2021; KS0 Sep 2023 (22 months); GPU share gone by late 2023 | closed at v2; the mm8 reserve's warning | yes | 170x to 720x |
|
||||
| Eaglesong (Nervos) | Toddminer C1; Antminer K5, K7 | a fixed sponge pipeline | compute | 4 months | closed at v2 | yes | about 100x |
|
||||
| Blake3 (Alephium); Blake2s (Kadena); Blake-256 (Decred); Blake2b (Sia); X11 (Dash); SHA512/256d (Radiant) | the 5 October file's rows | fixed pipelines | compute | 4 to 31 months | closed at v2 | yes | 33x to 6,500x |
|
||||
| NexaPow (Nexa) | DragonBall A21 | a secp256k1 Schnorr signature per nonce in hardware | a wide multiplier chain is already what the GPU does well | live 2023; chip Dec 2024 | closed at v2 | yes | 2.2x: the one compute row where the chip's edge stayed small |
|
||||
|
||||
What the table says, sorted by class: class A (fixed pipelines) 33x to 6,500x, closed at v2; class B (SRAM-scale sets) 12x to 1,300x, closed at v3 by the dataset and the drawn curve; class C (the memory system) 1.0x to 5.1x measured on Ethash, modelled 5.1x to 9.2x for Igneum, NOT closed by any layer; class D (firmware-survivable sequencers) 0.75x to 5x on the program side, closed as governance and open as a chip; class E (steered addresses) closed by layer 4 for the class it models.
|
||||
|
||||
## 2. The chips, in depth
|
||||
|
||||
One section per proof of work. Each carries the mechanism, the miss, the timeline, the layer mapping and the number. Where a lane's return says "not found" the row says so.
|
||||
|
||||
### 2.1 Ethash (Ethereum, July 2015): the E3, the Innosilicon line, Linzhi, Jasminer and the E9
|
||||
|
||||
**The mechanism of the hash.** A DAG of 1 GB growing 8 MB per epoch of 30,000 blocks (about 0.7 GB a year), 64 random 128-byte reads per hash mixed by FNV, keccak at each end; bandwidth-bound by design. EIP-1057 states the miss in one sentence: Ethash "requires external memory due to the large size of the DAG. However that is all that it requires - there is minimal compute ... a custom ASIC could remove most of the complexity, and power, of a GPU and be just a memory interface connected to a small compute engine" (https://eips.ethereum.org/EIPS/eip-1057, read 8 October 2026).
|
||||
|
||||
**The chips, and what each specialised.**
|
||||
|
||||
| Chip | Announced, shipped | The mechanism, as far as any source states it | MH/s, W, MH per joule | Against the best GPU of its year (derived, approximate) | Source (read 8 October 2026) |
|
||||
|---|---|---|---|---|---|
|
||||
| Bitmain Antminer E3 | leaked March 2018, announced 3 to 4 April 2018 at USD 800 (five per customer), shipped 16 to 31 July 2018; later batches USD 1,800 | 18 Ethash chips on three boards with 4 GB of commodity DDR3; chip, node, controller and read width never published; Bitmain's own support called it "a 4G video card" whose DDR "is up to the upper limit"; Rao's audit classes it as the conventional strategy (compute in silicon, memory off chip) | 180 claimed, 190 to 200 shipped, at 800 W: 0.24 MH/J | 1.0x to 1.1x against a tuned GTX 1080 Ti (45 MH/s at about 200 W, 0.225); under Rao's best overclocked 2019 GPU (0.40) | https://cryptoslate.com/bitmain-e3-asic-ethereum-miner/ ; https://2miners.com/blog/asic-miners-for-ethereum-antminer-e3-vs-innosilicon-a10-eth-master-comparison/ ; https://coingeek.com/memory-limitations-prompt-bitmain-antminer-e3-to-halt-etc-support/ ; https://www.kryptex.com/en/hardware/nvidia-gtx-1080-ti/reviews |
|
||||
| Innosilicon A10 ETHMaster, A10 Pro (6 GB), A10 Pro+ (7 GB), A11 Pro (8 GB) | A10 announced 23 July 2018 at 365, 432 and 485 MH/s (USD 3,800 to 5,000); A10 Pro June 2020; A10 Pro+ January 2021; A11 Pro presold March 2021 at 2,000 MH/s and 2,500 W, shipped December 2021 at 1,500 MH/s and 2,350 W ("20 percent less efficient"; broker quotes about USD 27,000) | the same conventional chip with a larger and faster memory system; the DRAM type is not stated on any page read (GDDR6 is the trade's assumption, approximate); node and read width not found | A10 485 at 850 W: 0.57; A10 Pro 500 at 860: 0.58; A10 Pro+ 750 at 1,350: 0.56; A11 Pro 1,500 at 2,350: 0.64 (0.80 claimed) | A10 2.5x against the 1080 Ti; A10 Pro 1.4x and A11 Pro 1.6x (2.0x claimed) against a tuned RTX 3090 (120 MH/s at about 295 W, 0.41) | https://www.criptonoticias.com/mineria/nuevo-minero-asic-innosilicon-procesa-485-mh-ethereum ; https://www.theblock.co/post/125871/innosilicon-ethereum-miner-a11-pos ; https://whattomine.com/coins/151-eth-ethash/asics |
|
||||
| Linzhi Phoenix (E1400) | announced 13 to 14 September 2018 by Chen Min (ex-Canaan) at 1,400 MH/s and 1 kW for April 2019; planned tapeout December 2018, actual September 2019; sample rollout 21 December 2020; no mass production; price never published; the company now "studying new opportunities" | two E1400 boards, each 64 compute units and 72 "mixers" with 4.4 GB of "decentralized memory inside its ASIC design" (The Block); the DRAM type never published (one 2019 forum post says an interposer and stacked HBM dies, unverified); the 4.4 GB sized to the DAG rather than to a commodity 6 or 8 GB, which reads as memory sized per chip (inference); Linzhi claimed a ProgPoW chip would reach 3x to 8x | 2,600 claimed, 2,733 measured by F2Pool, at about 3,000 W: 0.87 to 0.91 | 2.1x to 2.2x against the tuned 3090 | https://www.theblock.co/post/88622/questions-new-ethash-asic-ethereum ; https://www.coindesk.com/tech/2020/12/21/linzhi-begins-rollout-of-long-awaited-ethereum-miner-phoenix ; https://bitcoinmagazine.com/business/new-mining-manufacturer-linzhi-announces-ethereum-asic-miner ; https://linzhi.io/ ; https://github.com/Souptacular/linzhi |
|
||||
| Jasminer X4 (Sunlune) | chip announced 6 June 2021; X4 server announced 11 October 2021, first batch shipped 29 October 2021; launch price not found (USD 497 used today) | **the only Ethash chip that moved the memory**: TechInsights found "the first ever DRAM-to-Logic hybrid-bonding" (wafer-to-wafer DBI), DRAM dies bonded face to face onto a 32 mm by 21 mm logic die on XMC's planar 40/45 nm node; Jasminer's words: "3DIC technology, by integrating the data storage unit and the computing unit on the same chip"; 5 GB per unit, 40 chips per X4 server; the DRAM vendor, capacity per die and node not found | 2,500 at 1,200 W: 2.08 (the X4-1U 520 at 240 W: 2.17) | 5.1x against the tuned 3090; a physics check: 64 reads of 128 bytes is 65,536 bits a hash, so 2.08 MH/J is about 7.3 pJ per bit all in, under any off-package DRAM | https://www.techinsights.com/ko/node/51986 ; https://www.techinsights.com/ko/node/52149 ; https://semiconductor-digest.com/?p=22931 ; https://miningnow.com/asic-miner/jasminer-x4-2500mh-s/ |
|
||||
| Bitmain Antminer E9, E9 Pro | teased 27 April 2021 as "3 GH/s, the work of 32 GPUs"; shipped July 2022 at 2.4 GH/s, eight weeks before the Merge; E9 Pro February 2023, Classic only | conventional off-chip DRAM at larger scale: E9 (model 240-E) 6 GB in six bins 2,100 to 2,400 MH/s; E9 Pro (260-E) 7 GB; memory type not found on any page read; no teardown | E9 2,400 at 1,920 W: 1.25; E9 Pro 3,680 at 2,200: 1.67 | 3.0x and 4.1x against the tuned 3090 | https://d-central.tech/antminer-e9-family/ ; https://www.asicminervalue.com/miners/bitmain/antminer-e9-2-4gh ; https://www.coindesk.com/tech/2021/04/27/bitmain-to-release-antminer-e9-asic-for-ethereum-mining |
|
||||
|
||||
**Why the cap sits at 2x to 5x.** Rao's audit (6 September 2019): every DAG read is random at about 40 ns of latency "completely independent of the memory bandwidth or the computation engine"; "typical DRAM energy dissipation is 3 to 4 pJ per bit" and "the energy expended to move data from DRAM to compute are the same for GPU or ASIC", so the shipping chips showed "about 1.6x hashrate per watt over GPUs" (E3 0.24, A10 0.57, the best overclocked GPU 0.40 MH/W in his table); integrating memory with logic cuts the movement energy "much more than 10x" to "under 0.3 pJ per bit", "the looming threat" (https://github.com/ethcatherders/progpow-audit, the PDF's text, read 8 October 2026). Ren and Devadas (TCC 2017) give the bound: memory hardness bounds area, not energy; the energy of a memory access is comparable on a chip and a CPU, so bandwidth hardness is the only energy lever (https://eprint.iacr.org/2017/225). The derived ladder at 65,536 bits a hash: pure memory energy caps Ethash at about 0.76 MH/J on DDR3, 2.8 on GDDR6 and 3.9 on HBM2 (O'Connor et al., MICRO 2017: HBM2 3.92 to 3.97 pJ per bit, GDDR5 14.0); the shipped chips sit at 0.24 (E3), 0.6 (Innosilicon), 0.9 (Linzhi), 1.25 to 1.67 (E9, E9 Pro) and 2.1 (Jasminer, by leaving commodity packaging). The cap was the memory's own energy per bit, and the one chip that beat it moved the memory onto the die's face.
|
||||
|
||||
**The timeline.** Hash live July 2015; the E3 at 32 months (announced) and 36 (shipped); the first chip over 2x at 65 months (Linzhi, December 2020); 5x at 75 months (Jasminer, October 2021); the Merge at 86 (15 September 2022). The E3's death by DAG growth: Classic first, at epoch 328 (DAG about 3.56 GB, March 2020), then Ethereum, with a 30 March 2020 firmware stretching the DDR to about block 11.4 million (about October 2020): 20 to 27 months after shipping. Ethereum's responses: Zamfir's April 2018 poll (57 percent for an anti-chip fork); EIP-1057 created 2 May 2018, a 93 percent community vote in April 2019, audits delivered September 2019, "accepted" on 21 February 2020, EIP-2538's opposition on 25 February, then stagnant; the share claim in the EIP's own text: "as much as 40 percent of the Ethereum network may now be secured by ASICs" (undated inside a 2018 to 2020 document; no year-by-year series exists). After the Merge: Classic's hashrate went 64 to 183 TH/s in one day; today Classic reads 129.9 TH/s and ETHW 2.15; at USD 0.10 per kWh every Ethash chip in the table loses money (E9 Pro minus USD 5.28 a day), and a later wave (iPollo V1 3.6 GH/s at 3,100 W, June 2022; Jasminer X16-P 5.8 GH/s at 1,900 W, August 2023) holds Classic (https://hashrateindex.com/blog/how-much-ethereum-mining-hashrate-can-other-blockchains-absorb/ ; https://2miners.com/etc-network-hashrate ; read 8 October 2026).
|
||||
|
||||
**The mapping to v6.** Ethash is class C in full, and its chips are the f = 1 chip of `chip-model-v3.md` section 5 at three points on the packaging ladder: commodity DRAM on a board (E3, E9: 1x to 4x), memory sized and placed per chip (Linzhi: 2x), DRAM bonded to the logic (Jasminer: 5x, the model's HBM3 row). None of v6's four layers touches a chip of this class: the program, the mixer, the op mix, the family schedule and the acceptance floor are all firmware or configuration to a controller that stores the dataset; the only layer that reaches it is layer 2, and only when the dataset passes the chip's board, which at 2 GiB plus 0.5 GiB a year is year 60 for a 32 GB board (section 4.2). Does v6 close it: **no**. The number: 5.1x per joule on GDDR7 and 7.5x on one HBM3 stack at zero premium against the 5090 unlocked, 3.6x at the 5090's 1,300 MHz knee, 2.1x at the knee with the class v4 shadow at k = 1 (`counter-asic-4-research.md` section 0); the history's measured band for exactly this chip class is 1.0x (E3) to 5.1x (Jasminer), and Jasminer's number is the model's HBM-class row reached in 2021 on a 40 nm logic die. The forward line of the same mechanism is lane B's (`docs/analysis/class-v6/hardware-future.md`, master 34f63b3c, section 4.4 and its table row for fine-grained hybrid-bonded DRAM on logic: 13x to 17x per joule at zero shadow, modelled, on the 2028 to 2030 roadmaps); the Jasminer X4 is that row's shipped precedent, five years early and at 5x on a planar node, which is the reason to read lane B's 13x to 17x as a ceiling a first product will not reach and a second one will approach. The one thing Igneum has that Ethash did not: the honest card is latency-bound at 4-byte reads, not bandwidth-bound at 128, so the chip's energy per read is the activate's 909 pJ plus a 32-byte atom (2.0 nJ on GDDR7 against the card's measured 8.7 to 10.9 nJ marginal), which is where the 5.1x comes from, and the shadow is the only term on the card's side of that ratio.
|
||||
|
||||
### 2.3 RandomX (Monero, 30 November 2019): the chips, RandomX v2, and the X9's withdrawal
|
||||
|
||||
**The mechanism of the hash.** A VM running 8 chained programs of 256 instructions, 2,048 iterations each, over a 2 MiB scratchpad in three tiers (16 KiB, 256 KiB, 2 MiB) and a 2,080 MiB dataset derived from a 256 MiB cache by SuperscalarHash, a random superscalar program of about 450 instructions with 155 64-bit multiplies per function, tuned to a 170-cycle latency to match DRAM; double-precision floating point in all four rounding modes; the light-mode chip (cache on die) pays 760 cycles and 1,240 multiplies per item, "energy comparable to loading 64 bytes from DRAM" (https://github.com/tevador/RandomX/blob/master/doc/design.md and doc/specs.md, read 8 October 2026). Its DRAM argument: "DRAM cannot do more than about 25 million random accesses per second per bank group", about 1,500 H/s per bank group.
|
||||
|
||||
**The chips, and what each specialised.**
|
||||
|
||||
| Chip | Date | What is known of the inside | Rate, watts | Per joule against the best CPU | Source (read 8 October 2026) |
|
||||
|---|---|---|---|---|---|
|
||||
| Bitmain Antminer X5 | announced 27 August 2023, shipped September 2023 | "Bitmain's first RISC-V architecture CPU" (the reseller's only line); Spagni: not an ASIC but "a board containing multiple RISC-V CPU chips"; SChernykh: the chips were likely in use from about 2021, two years before sale, and do not beat Ryzen rigs per joule; core model, count, node, DRAM type and amount: NOT FOUND, no teardown | 212 kH/s at 1,350 W (157 H/W) | 1.46x over a Ryzen 9 7950X (107.5 H/W on Kryptex); a 100 W-capped Ryzen 9 9950X at 199 H/W beats it | https://criptonoticias.com/mineria/bitmain-lanza-antminer-x5-mineria-monero-asic ; https://bt-miners.com/products/bitmain-antminer-x5-monero-miner-212k-bt-miners/ ; https://pool.kryptex.com/en/device/cpu/amd/ryzen-9-7950x |
|
||||
| Bitmain Antminer X9 | sales opened 26 December 2025 at USD 5,600, shipping scheduled July 2026; WITHDRAWN by mid-May 2026, refunds within hours, zero units shipped, "technical adjustments and a new strategy" through resellers, no Bitmain statement | "custom RISC-V cores specifically optimized for RandomX" (Bitmain's claim as relayed in Monero issue 10270); nothing else | 1,000 kH/s at 2,472 W (404 H/W), claimed | about 3.8x over the 7950X, claimed, never measured | https://bitmain.com.vc/news/bitmain-launches-antminer-x9 ; https://github.com/monero-project/monero/issues/10270 ; https://oneminers.com/blogs/news/whatever-happened-to-the-antminer-x9-bitmain-monero-miner (2 October 2026) |
|
||||
| Pinecone INIBOX R1X | launched March 2026; shipping windows slipped from August to 10 to 18 October 2026; USD 3,200 to 4,950 | "built from ground up silicon", "optimized memory architecture for RandomX"; cores, node, DRAM: NOT FOUND; no delivered unit tested | 1,200 kH/s at 2,055 W (584 H/W), claimed | about 5.4x over the 7950X, claimed, undelivered | https://pineconebox.com/product/3 ; https://millionminer.com/news/monero-mining-guide-2026-antminer-x5-x9-pinecone-r1x-randomx |
|
||||
| tevador's own "possible ASIC design" (24 December 2018, pre-release, marked outdated) | | 4 GiB of HBM for the dataset, 64 MiB of SRAM for 256 parallel 256 KiB scratchpads, 256 decoder and scheduler cores, 28 single-instruction workers; about 120,000 programs a second at about 300 W, "9 times more power efficient than a CPU" | | 9x, by the designer's own estimate of the pre-release design | https://github.com/tevador/RandomX/issues/11 |
|
||||
|
||||
**What the design missed, in its authors' words.** RandomX v2 (PR 317 by SChernykh, merged 17 February 2026; v2.0 released 25 March 2026; Monero mainnet activation in PR 10038, open since August 2025, no date) names the three gaps a chip or a "specially designed CPU" took: (1) CFROUND, the rounding-mode switch, "costs up to 10 percent of hashrate on Ryzen CPUs" and "this is where an ASIC or a specially designed CPU can get an easy advantage"; v2 switches rounding 16 times less often; (2) the scratchpad initialisation was the only AES, so "a dedicated circuit for scratchpad initialization" paid off; v2 puts 16 AES operations per iteration in the main loop; (3) "while CPU cores got faster over the years, RAM latency stayed basically the same", about 50 to 55 ns from tuned DDR4 in 2019 to tuned DDR5 in 2026, so the fixed 256-instruction program left latency slack a faster core could not fill; v2 lengthens the program to 384 and prefetches two iterations ahead. Work per hash rises 52.9 percent; measured CPU hash rates move from minus 12.9 percent (a 100 W-capped 9950X) to plus 8 percent (a 28 W laptop part) (https://github.com/tevador/RandomX/blob/master/doc/design_v2.md and /pull/317, read 8 October 2026). The press reading: v2 "doesn't seem to be an attempt to eliminate every form of specialization", it removes "unintended advantages that benefited hardware in version 1.0" (https://www.coinpro.ch/en/?p=42081, 31 March 2026).
|
||||
|
||||
**The timeline.** Live 30 November 2019; X5 at parity hardware 46 months later (September 2023), on chips SChernykh believes mined privately from about 2021 (21 months after launch); the X9 announced at 73 months and withdrawn at 78; v2 released at 76 months with a 52.9 percent work increase and no activation date; the R1X undelivered at 82 months. The X9's withdrawal is read by the trade press as Bitmain waiting for v2 rather than shipping a part the fork would hit (https://oneminers.com/blogs/news/antminer-x9-cancelled-what-bitmain-pulling-the-model-means-for-monero-mining, 31 July 2026). Corrections to the 5 October file's row 17: the X9 was not delivered in July 2026 (withdrawn, zero units), and "no fork as of October 2026" is now "v2 released, activation pending".
|
||||
|
||||
**The mapping to v6.** RandomX is class D (the firmware-survivable machine): every X5 claim is a many-core RISC-V board over commodity DRAM, a better CPU for a fixed VM spec, and the v2 fixes are exactly the parameters class v6 layer 1 draws (program length, the op mix's cost on the honest machine, the memory latency slack). Two readings bind: first, RandomX's whole gap is the CPU's out-of-order overhead against an in-order many-core board, and Igneum's honest machine is already the in-order many-lane design, so the X5's 1.46x has no Igneum analogue; the Igneum analogue of "a better machine for the fixed spec" is class C's memory chip at 5.1x. Second, the v2 changes show what a per-era draw of program length and op mix buys: it closes the slack a faster honest core leaves (the latency-shadow argument of class v4 in RandomX's words), and it costs the honest machine up to 12.9 percent of rate at the power-capped point, which is the Igneum premium question in another chain's numbers. Does v6 close it: yes for the class (layers 1 and 3 draw what v2 had to fork to change), and the number is the X5's 1.46x, which becomes the shadow's premium arithmetic on Igneum (2.1x at k = 1 at the knee).
|
||||
|
||||
**The Qubic episode (2025) as the detector's lesson.** Qubic's pool reached an average of 22.09 percent of Monero's hashrate over the campaign and 23 to 34 percent during ten withholding periods, with six-hour windows near 50 percent and never a daily 51 percent (Lee and Kim, arXiv 2512.01437, AFT 2026, read 8 October 2026); an 18-block reorg on 14 September 2025 invalidated 117 to 118 transactions. Detection rested on things the adversary controlled: one payout wallet, extra-nonce signatures in its coinbase, its own pool API; when Qubic encrypted its job messages and rotated keys those signals went, and Rucknium's warning stands that a miner split across addresses and solo-mining leaves only the orphan rate and double spends as signals. Qubic ran stock CPU miners, so the nonce-distribution method that found the 2018 and 2019 chips (MoneroCrusher: nonces clustered under about 1.34 billion of 4.3; 85.2 percent of the hashrate, about 5,400 machines at 128 kH/s) did not apply. For Igneum's detector (the 5 October addition 4) this means two instruments, not one: the per-program rate spread and nonce pattern for a chip, and a share-by-key-and-template pattern for a concentrated honest fleet; neither survives an adversary who randomises both.
|
||||
|
||||
### 2.2 ProgPoW (EIP-1057, May 2018): the independent review, the exploit, and the adopters
|
||||
|
||||
**The mechanism.** A random program re-drawn every PROGPOW_PERIOD (50 blocks in 0.9.2, 10 blocks, about 2 minutes, in 0.9.3) from the block number, so miners compile ahead; 16 lanes, a 32-register file per lane, 64 outer iterations each with 4 uint32 DAG loads per lane (256 bytes per lane-group read), 11 cache accesses into a 16 KB cache and 18 random math ops drawn from eleven (add, mul, mulhi, min, rotl, rotr, and, or, xor, clz, popcount) with KISS99 as the generator and FNV1a for merging; keccak-f800 with 32-bit words at both ends "to reduce impact on total power"; the stated aim is that "the algorithm's requirements match what is available on commodity GPUs", the stated chip gain "minimal, roughly 1.1 to 1.2x", with the remaining chip levers named as removing the graphics pipeline, the floating-point units and minor merge-function tweaks (https://eips.ethereum.org/EIPS/eip-1057 and https://github.com/ifdefelse/ProgPOW, read 8 October 2026).
|
||||
|
||||
**The independent review, exactly.** Least Authority (report version 9 September 2019): no issues, five suggestions. Suggestion 2, the light-evaluation attack, in the report's words: "on-die scratchpad memory of around 100 MB is possible in ASICs, that we can fetch at least 128 bytes during a single read, and that such a read might have a latency in the range of one to some tens of cycles"; a chip replaces every DAG read with calc_dataset_item(cache, i) over an on-die cache, at a latency near DATASET_PARENTS x k1, "as low as about 300 cycles"; "the energy expended per bit to access DRAM is about 3 pJ per bit, but when the memory access is on-chip, it decreases to 0.3 pJ per bit, which is a 10x improvement"; conclusion: "efficient light-evaluation attacks may become possible within a few years. This is also an issue that applies to Ethash"; the mitigation offered: raise DATASET_PARENTS from 256 to 512 (which 0.9.4 did), and "for details on the related hardware advancements, please see Bob Rao's corresponding audit report". Suggestion 5: "hardware targeting machine learning is also useful for ProgPoW mining" (the PDF at https://leastauthority.com/static/publications/LeastAuthority-ProgPow-Algorithm-Final-Audit-Report.pdf, text extracted, read 8 October 2026). Bob Rao (6 September 2019): "the only meaningful metric is Energy per Hash"; Ethash chips "about 1.6x hashrate per watt over GPUs"; "10/7 nm processes provide up to 25 Mbits per mm^2 of SRAM and 100 M transistors per mm^2"; "with sufficient on-chip memory available, ProgPOW ASICs with << 0.1x E/H over GPUs can be built"; three chip approaches costed (the whole DAG on die, "possible in 2025+"; a custom stacked memory; the cache only, "about 51 MB as of 30 August 2019", with the item recomputed, "512 MB SRAM" on the slide); the DAG-on-die economics on a three-year Moore cadence: a single die holding a 6.49 GB DAG in 2024 to 2025 at 532 mm^2 and USD 221 per good die (USD 34 per GB), or sixteen dies of 33 mm^2 at USD 6.51 each; "a die that can hold the logic and entire DAG at any point in time becomes cost effective at around 2025 and beyond"; the 16-die split "becomes cost effective today": 16 x USD 6.62 of silicon plus USD 16 of package plus USD 25 of PCB plus USD 25 of heatsink and interface, "about USD 172 total", against "about USD 240" for a GPU board with "8 GB GDDR6 about USD 150"; a 10 nm-class chip "USD 20 M+" and "1+ year to develop, can be done if there is a 150-day ROI to miners" (the PDF at https://github.com/ethcatherders/progpow-audit, text extracted, read 8 October 2026).
|
||||
|
||||
**The exploit.** Kik, 4 March 2020: the 64-bit seed carried between the two keccak passes is too small; fix a seed and compute its mix once, grind an extra-nonce in the header to meet the difficulty on the final keccak, then scan nonces until keccak_progpow_64(header_hash, nonce) equals the seed; the memory path runs once per 2^64 nonces and the rest is keccak, "ASICs benefit most when network difficulty exceeds 2^50"; 0.9.4 widened the carried state from 64 to 256 bits (the digest of the first keccak plus the mix plus padding) (https://github.com/kik/progpow-exploit ; https://github.com/ifdefelse/ProgPOW ; read 8 October 2026).
|
||||
|
||||
**Linzhi's claim.** 8 January 2019: "shocked" by ProgPoW with USD 4 M invested, and a stated intention "to study the feasibility, and then build, ProgPoW ASICs"; the repository recording their claim puts a ProgPoW chip at 3x to 8x (https://github.com/Souptacular/linzhi ; https://forklog.com/proizvoditel-majnerov-linzhi-vystupil-protiv-realizatsii-predlozheniya-progpow/ ; read 8 October 2026). No ProgPoW chip was ever shown.
|
||||
|
||||
**The timeline and the adopters.** EIP created 2 May 2018; a 93 percent vote of 2.93 M ETH in April 2019; both audits September 2019; "accepted" on the 21 February 2020 call; EIP-2538's opposition 25 February; the 6 March 2020 call with "frustration but little progress"; stagnant since; the Merge 15 September 2022. KawPow (Ravencoin, 6 May 2020), FiroPoW (26 October 2021), ProgPowZ (Zano), Sero and Quai (January 2025) run ProgPoW variants; no chip is listed for any of them on WhatToMine or asicminervalue as of 8 October 2026 (https://whattomine.com/coins/234-rvn-kawpow/gpus ; https://www.asicminervalue.com/), on prizes that never reached the market caps at which the 2018 chips appeared (the 5 October file, section 2.5).
|
||||
|
||||
**The mapping to v6.** ProgPoW is class D (a sequencer over eleven ops reads the per-period program as configuration) and class E (Kik). Its review is the one piece of the record that priced Igneum's own chips before Igneum did: the light-evaluation attack is the f = 0 recompute chip (M16, 0.92x at the op budget with the mixer at x8), and Rao's 16-die DAG holder at USD 172 is the f = 1 chip at USD 470 of memory and board. Does v6 close it: the class D half yes (layers 1 and 3 are ProgPoW's period change made an era draw, with no fork), the class E half yes (Igneum's seed is 256 bits through the VDF; layer 4 is the acceptance-side test the audits said to add), and the Rao half no (class C, section 2.1). The number: ProgPoW claimed 1.1x to 1.2x against a conventional compute chip and never priced the memory-system chip; Igneum's model gives that chip 5.1x.
|
||||
|
||||
### 2.4 Cuckoo Cycle (Grin, January 2019): the GRN1, the G32, the iPollo G1 and the 2025 bounty
|
||||
|
||||
**The mechanism of the hash.** Find a 42-cycle in a random bipartite graph of 2^31 or 2^32 edges from siphash; the lean solver keeps "1 bit per edge and 1 bit per node in one partition", bottlenecked by random node-bit access, which "requires tons of SRAM, which is lacking on CPUs and GPUs, but easily implemented in ASICs"; the mean solver keeps 33 bits per edge and is bandwidth-bound, about 4x faster; Tromp: "our primary PoW of Cuckatoo31+ is intended to be mined by ASICs"; the family is "a Proof of SRAM" (https://github.com/tromp/cuckoo ; https://forum.grin.mw/t/cuckatoo31-im-mutability/2442 ; read 8 October 2026). The memory geometry a chip needs (the 13 November 2018 feasibility thread): the 512 MB edge bitmap is accessed sequentially and can sit in external DRAM (96 GB/s with 128 MB on chip); the node bitmap must be SRAM; Cuckatoo31 fits one die at "256 + 64 = 320 MB of on-chip memory", Cuckatoo32 needs "at least 640 MB" or 512 MB of SRAM plus 512 MB of serial DRAM; "trimming is over 99 percent of the effort" (https://forum.grin.mw/t/cuckatoo32-feasibility/1199 ; https://forum.grin.mw/t/advice-on-cuckatoo-hardware-implementation/12042). The original "several orders of magnitude" time-memory claim fell to Andersen's edge trimming on 31 March 2014, two months after publication, and the design took it as its baseline.
|
||||
|
||||
**The chips.**
|
||||
|
||||
| Chip | Dates | Mechanism | Rate, watts, price | Against a GPU | Source (read 8 October 2026) |
|
||||
|---|---|---|---|---|---|
|
||||
| Obelisk GRN1 (Cuckatoo31) | announced 17 January 2019; chip details 20 March; sale 9 April (Mini 70 GPS at 400 W for USD 2,000; GRN1 420 GPS at 2,200 W for USD 10,000; Immersion 840 at 4,400 W for USD 20,000; shipping October 2019); CANCELLED 19 July 2019 with full refunds | one die, TSMC 16 nm, "a full 512 MiB of memory on board" (SRAM), 150 GPS at 800 W per chip, "thousands of hashing cores and memory banks", siphash plus blake2b, two sorter types; cancelled for the Cuckatoo31 phase-out, Grin under USD 2 in May 2019 and funding | 420 GPS at 2,200 W planned | about 50x per joule against a GTX 1080 Ti at about 0.9 GPS and 250 W on C31 (approximate), planned, never built | https://forum.grin.mw/t/obelisk-grn1-chip-details/4571 ; https://forum.grin.mw/t/obelisk-grn1-full-sale/4773 ; https://forum.grin.mw/t/grn1-cancellation-announcement/5624 |
|
||||
| Innosilicon G32 (C31+ and C32+) | announced 17 April 2019 (G32-Mini 21.5 GPS at 140 W for USD 788; G32-1800 328 GPS at 1,800 W for USD 9,388; delivery from August 2019); CANCELLED 16 January 2020 citing foundry delays | about 100 chips at about 1.8 to 1.9 GPS each on C32 (an investor's figure) | never shipped | | https://forum.grin.mw/t/innosilicon-grin-miner-g32-preliminary-specification/4842 ; https://forum.grin.mw/t/innosilicons-grin-asics-canceled/6932 |
|
||||
| iPollo G1 (Cuckatoo32) | December 2020 | 30 chips at 12 nm; whether the node bits sit in SRAM or the edge bitmap in DRAM is not published; Tromp doubts it is multi-chip in Innosilicon's sense | 36 GPS at 2,800 W, USD 9,000 | about 3x per joule against an RTX 4060 at 0.45 GPS and 110 W | https://pool.kryptex.com/device/asic/ipollo/g1 ; https://miningboard.com/algorithms/Cuckatoo32 |
|
||||
|
||||
**The 2025 bounty.** Stephan Theisgen claimed the USD 10,000 linear time-memory trade-off bounty on 11 April 2025 (a solver at N/k bits at most 10k times slower, any k at or above 2), paid 30 April; the measured penalty about half an order of magnitude past linear; Tromp's reading: a chip with N/k bits must hash each edge "roughly (k + 1000) times" against under 6 for the lean miner, so memory can be traded for time but not for energy, and Cuckatoo "remains a Proof of SRAM" (https://forum.grin.mw/t/another-cuckatoo-bounty-succesfully-claimed/11739, read 8 October 2026).
|
||||
|
||||
**The mapping to v6.** Class B. Cuckoo's resource was SRAM size at 320 to 640 MB per die, and a 16 nm die with 512 MiB of SRAM was designed, priced and sold before the economics killed it; the one chip that shipped sat at 3x because half its working set stayed in DRAM. Layer 2 answers it the way the chip model already does: Igneum's 256 MiB cache is the GRN1's die (128 mm^2 at N5, `sram-mirror.md`), and the 2 GiB dataset above it is what the lean solver never had to hold; the time-memory curve Cuckoo got wrong by 50x and then bounded in 2025 (linear in time, not in energy) is the curve `chip-model-v3.md` section 5 draws for Igneum (monotone; the f = 0 end pays 6.3 nJ and 9,360 ops per item against 1.2 to 2.0 nJ for a stored one), and its verdict is the same as Tromp's: memory can be traded for time, not for energy. Does v6 close it: yes, and it was closed at class v3. The number: 50x planned on C31 and 3x shipped on C32; Igneum's f = 0 chip 1.86x per joule and the f = 1 chip, which Cuckoo did not have because its memory was never a DRAM-scale random-read set, 5.1x.
|
||||
|
||||
### 2.5 Equihash 200,9 (Zcash, October 2016): the Z9 and the parameter-following chip
|
||||
|
||||
**The mechanism of the hash and its claim.** Wagner's generalised birthday problem with algorithm binding; the paper's claim: a PoW needing "700 MB of RAM" that "increases the computations by the factor of 1000 if memory is halved" (https://eprint.iacr.org/2015/946, read 8 October 2026). Zcash chose (200, 9), which solvers run in about 144 MB (approximate); no trade-off-resistance bound was ever proved for Equihash (Alcock and Ren, 2017, cited through the Fudan paper below).
|
||||
|
||||
**The chips and the mechanism.** Bitmain's BM1740 (Z9 mini, announced 3 May 2018 at 10 kSol/s and 300 W, shipped June; Z9 September 2018, 42 kSol/s at 970 W on 48 chips) is "a single-chip Equihash miner", "presumably with around 128 MB of memory", eDRAM or SRAM "an open question" (Tromp, 7 June 2018, https://forum.z.cash/t/let-s-talk-about-asic-mining/27353/3332): the whole (200, 9) working set on one die, which the 1,000x claim had assumed impossible at that size. A (144, 5) solver needs over 1.6 GB and cannot fit; Tromp "physically inspected the product and did not find enough memory to handle (144, 5)". Vorick's architecture (13 May 2018) is the other route: "a basic architecture for equihash ASICs that would be able to successfully follow a hardfork that chose any set of parameters", with "massive speedups and efficiency gains over GPUs", because on a chip "you can merge the memory and computation together ... do most of your manipulating in-place" (the essay, through https://steemit.com/crypto/@waraa/the-state-of-cryptocurrency-mining). The published design of that route: Bai, Gao, Hu and Zhang, NDSS 2019, an adversary solver whose sort step is a linear-time insertion sorter of 2,048 "smartcell" flip-flop chains feeding merge stages buffered in off-chip DDR4 (list 1,600 Mib, pairs 2,016 Mib for (200, 9)), pair generation and XOR on small MCUs; simulated at SMIC 28 nm: 40.6 Sol/s at 500 MHz for 0.75 to 0.78 W, 52 to 54 Sol/J against about 4 for the best GPU software, "at least 10x" and parameter-independent (https://www.ndss-symposium.org/wp-content/uploads/2019/02/ndss2019_09-5_Bai_paper.pdf, read 8 October 2026). Later chips: Innosilicon A9 (June 2018, 50 kSol/s at 620 W, USD 9,999); Z11 (April 2019, 135 kSol/s at 1,418 W, 12 nm); Z15 (420 kSol/s at 1,510 W); Z15 Pro (June 2023, 840 kSol/s at 2,780 W). Against a GTX 1080 Ti at 735 to 785 Sol/s and 250 to 305 W (about 2.7 Sol/J): Z9 mini 12x, Z9 16x, A9 30x, Z11 35x, Z15 Pro 110x (https://www.asicminervalue.com/miners/bitmain/antminer-z9 ; https://www.asicminervalue.com/miners/bitmain/antminer-z15-pro ; https://en.wikibooks.org/wiki/ZCash_mining_GPU_Comparison/GPU_Mining ; read 8 October 2026).
|
||||
|
||||
**The timeline.** Hash live 28 October 2016; three groups mining on secret chips before the Z9 announcement (Vorick); the Z9 mini at 18 months; the Zcash Foundation's statement of 8 May 2018 asked whether chips "could handle different parameters of Equihash" and the community vote of June 2018 went 45 to 19 against prioritising resistance; no fork; proof of stake announced November 2021; the Z15 Pro at 80 months.
|
||||
|
||||
**The mapping to v6.** Class B, with a lesson for layer 1: Equihash's parameters (n, k) were the knob the forks turned (Bitcoin Gold to 144,5; Beam to 150,5; Flux to 125,4), and a chip was designed to follow "any set of parameters" by keeping the memory off die and the sort on it. A per-era draw of a parameter a chip can follow is a configuration to it; a draw of the memory SIZE is the one that forced the Z9's single die to fail on (144, 5), which is layer 2's mechanism, not layer 1's. Does v6 close it: yes by layer 2 (a 2 GiB set is not a die), and the parameter-following chip is the honest warning for layer 1's draws. The number: 12x at the first chip, 110x by 2023, against a hash whose 1,000x penalty claim never had a proof; Igneum's claim for its curve rests on a drawn curve (`chip-model-v3.md` 5.4) and the in-house pass's exact pebbling optimum (adv-cache-3), and still has no proof.
|
||||
|
||||
### 2.6 Scrypt and Argon2: the Litecoin chips, the lookup gap, and MTP
|
||||
|
||||
**Scrypt (Tenebrix and Litecoin, 2011; N = 1,024, r = 1, p = 1: a 128 KB scratchpad).** The mechanism of every scrypt chip is one 128 KB of on-die SRAM per hashing core and many cores per die: Watkins (2014) "there only needs to be 128 KB of memory per processor ... one core driving a 128 KB cache", SRAM chosen over every other memory as fastest, salsa20/8 about 60 percent of the runtime and memory access 38 percent (https://arxiv.org/pdf/2208.02160); the BM1485 of the L3+ (June 2017, 504 MH/s at 800 W): 12 cores per chip, "every BM1485 integrates on-die SRAM to hold that scratchpad", 28 nm, 288 chips per unit, about 1.7 MH/s per chip (so about 1.5 MB of SRAM per chip, arithmetic) (https://d-central.tech/mining-glossary/bm1485/ ; https://www.asicminervalue.com/miners/bitmain/antminer-l3-504mh); the L7 (November 2021, 9.5 GH/s at 3,425 W, USD 15,000, 0.36 W per MH against the L3+'s 1.58): the BM1489 at TSMC 7 nm, 480 chips (https://d-central.tech/mining-glossary/bm1489/ ; https://cryptoage.com/en/2550-bitmain-antminer-l7-is-a-new-asic-miner-for-litecoin-and-dogecoin.html); the Innosilicon A2 (21 April 2014, 28 nm, 1.6 to 1.8 MH/s per chip at 10 W, about 150 MH/s per box at 1 kW: https://www.design-reuse.com/news/34403/innosilicon-28nm-litecoin-asic-reference-miner.html); the KnC Titan (March 2014, 250 MH/s at 800 to 1,000 W, USD 9,995, "4 chips x 2,284 cores": https://www.coindesk.com/markets/2014/03/28/kncminer-updates-titan-spec-promises-250mhs/), whose 2,284 cores cannot each hold 128 KB on a 2014 die, so it shared scratchpads or took the time-memory trade-off (not confirmed). The trade-off itself is in the designer's record: Percival (18 November 2012) on storing every other scratchpad entry: memory halved for about 25 percent more BlockMix work, area-time about 0.625x, the trade favouring the attacker at 2x to 4x reductions, "already in the paper's cost estimates" (https://mail.tarsnap.com/scrypt/msg00092.html; all read 8 October 2026). Against an R9 280X at 700 to 740 kH/s and 340 to 450 W at the wall: A2 about 70x, L3+ about 300x, L7 about 1,300x per joule (derived, approximate). Scrypt-N (Vertcoin 2014: N doubling by timestamp up to 2^30) was dropped on 13 December 2014 for Lyra2RE "as a proactive defense against emerging Scrypt-N capable ASICs", because raising N "simply involves doing more iterations" and more SRAM or a larger lookup gap (https://vertcoinproject.org/vertcoin_whitepaper.pdf ; https://coincentral.com/what-is-vertcoin-a-beginners-guide/).
|
||||
|
||||
**Argon2 as a proof of work (MTP, Zcoin, 10 December 2018).** Argon2d over 4 GB with a Merkle tree; Dinur and Nadler (2017): malicious proofs with under 1 MB, 1/3,000 of the honest memory, at a computation penalty of 170, "more than 55,000 times faster than what is claimed by the designers", with a 2^64 one-time precomputation, by injecting chosen blocks that steer Argon2d's data-dependent addresses (https://eprint.iacr.org/2017/497); MTP 1.2 patched it before launch; no Argon2 chip was ever built; Firo replaced MTP with FiroPoW on 26 October 2021 (https://firo.org/2021/10/01/firopow-and-instantsend-release.html). Yescrypt and yespower (GlobalBoost-Y 2014; Yenten, Cranepay, Tidecoin on yespower from 2018; L2-latency-bound sequential work: https://www.openwall.com/yespower/): no chip found, small prizes.
|
||||
|
||||
**The mapping to v6.** Class B throughout, and the parameter-growth lesson for layer 2 in its oldest form: Scrypt-N's automatic growth was abandoned because a chip follows a scratchpad that grows by doubling the SRAM it already has, and Percival's own 2012 note says the time-memory trade favours the chip at 2x to 4x. Does v6 close it: yes by layer 2 (no die holds 2 GiB; the curve is monotone against partial stores); the lookup-gap lesson is the reason the dataset's chained cache has a drawn pebbling optimum (adv-cache-3) rather than a claim. The number: 1,300x for scrypt by 2021; Igneum's f = 0 chip at 1.86x per joule. MTP is class E (section 4.4).
|
||||
|
||||
### 2.7 to 2.9 KawPow, Autolykos, Octopus: the no-chip hashes, and why
|
||||
|
||||
| Hash | Live | Mechanism | Chip status, 8 October 2026 | Why no chip (the honest reading) | Source |
|
||||
|---|---|---|---|---|---|
|
||||
| KawPow (Ravencoin; Neoxa, Clore, Meowcoin, Neurai) | 6 May 2020 | ProgPoW 0.9.4 with a per-block program; "no additional future algorithm forks are envisaged" | none listed on WhatToMine or asicminervalue | class D on a small prize: Ravencoin's cap never reached the 2018 cluster's | https://whattomine.com/coins/234-rvn-kawpow/gpus ; https://github.com/RavenProject/Ravencoin/blob/master/roadmap/README.md |
|
||||
| Autolykos v2 (Ergo) | February 2021 (v1 July 2019) | a k-sum (k = 32) over a Blake2b table of 2^26 elements of 31 bytes (2.08 GB) growing about 5 percent per 51,200 blocks from block 614,400 to a cap of 2,143,944,600 elements at block 4,198,400; v1's non-outsourceable puzzle removed because "large players could bypass this resistance using smart contracts" | none | class C territory (a table read per hash) on a small prize; its growth rule is the one automatic schedule in the record untested by a chip; f2pool and Ergo's own docs call it resistant with no chip named | https://docs.ergoplatform.com/mining/autolykos/ |
|
||||
| Octopus (Conflux) | October 2020 | Ethash-style DAG (the "dense matrix step" unverified in the source) | none | as above; f2pool: "cannot be efficiently mined with FPGAs or ASICs" | https://f2pool.io/mining/guides/how-to-mine-conflux/ |
|
||||
| Verthash (Vertcoin), FishHash (Iron Fish from April 2024, Karlsen) | January 2021; April 2024 | a 1.2 GB table from the chain's headers; a 4,608 MB constant dataset with Blake3 and 512 iterations | none | the same class as Ethash's chips, on prizes under the 2018 cluster | https://fips.ironfish.network/fips/fip-3-memory-hard-mining-algorithm |
|
||||
|
||||
The reading for v6: "no chip" on a DRAM-scale random-read hash is an economic fact, not a design one (the 5 October file, section 2.5: compute-bound hashes got chips at USD 20 K to 30 K of daily issuance, Ethash at USD 7.6 M). Every hash in this table is class C and none of them has been tested at a prize that pays for a controller project; the Ethash record is the test, and it read 1x to 5x.
|
||||
|
||||
### 2.10 kHeavyHash (Kaspa, November 2021): the KS chips
|
||||
|
||||
**The mechanism.** cSHAKE256 of the header and nonce, a 64 x 64 matrix of 4-bit values generated from the pre-PoW hash, a nibble-wise matrix-vector multiply, XOR, a final cSHAKE (https://github.com/kaspanet/rusty-kaspa/blob/master/consensus/pow/src/lib.rs, read 8 October 2026); designed for optical and specialised hardware; the chip wires the multiply as a fixed pipeline. IceRiver KS0 (September 2023, 100 GH/s at 65 W), KS1 (1 TH/s at 600 W), Antminer KS3 (August 2023, 9.4 TH/s at 3,550 W), KS5 Pro (March 2024, 21 TH/s at 3,150 W), KS5L (April 2024, 12 TH/s at 3,400 W); against an RTX 4090 at 2.08 GH/s and 226 W: KS0 about 170x, KS5 Pro about 720x per joule (https://www.asicminervalue.com/miners/bitmain/antminer-ks5-pro-21th ; https://www.kryptex.com/overclocking/nvidia-rtx-4090-micron-24gb-medium-overclock ; read 8 October 2026). Timeline: 17 to 20 months to the first chip; the GPU share negligible by late 2023; seven forks left Kaspa to re-resist (the 5 October file, row 23). Node: not found.
|
||||
|
||||
**The mapping to v6.** Class A. The matrix multiply is a warning for the reserve's mm8 family, not for the hash: a fixed 64 x 64 nibble multiply is the cheapest thing silicon does, and the measured rows agree (the 5090's int8 MAC at 1.4 to 4.1 pJ against a 5 nm array's claimed 0.04 to 0.4, `counter-asic-4-research.md` 15.1a). Does v6 close it: yes, closed since class v2 (no fixed function to unroll); the number, 720x, is what a fixed pipeline does to compute-bound work, and the reserve's ordering (section 4.3) keeps mm8 last for exactly this reason.
|
||||
|
||||
### 2.11 CryptoNight (Bytecoin 2012, Monero 2014): the X3, the secret chips, and four forks
|
||||
|
||||
**The mechanism of the hash.** 524,288 iterations of an AES round plus an 8-byte multiply over a 2 MB scratchpad sized to a 2014 per-core L3; latency-bound at SRAM scale.
|
||||
|
||||
**The chips.** Bitmain Antminer X3, announced 15 March 2018 at 220 kH/s and 550 W (465 to 470 W measured), 180 BM1700 chips on three boards, USD 11,999 for batch 1 falling to USD 1,900; no teardown or vendor description of the BM1700 exists (node, SRAM, AES units not found). The arithmetic is the mechanism: 1.2 kH/s and about 2.6 W per chip is one or two 2 MB scratchpads in on-die SRAM with a hardware AES round per chip, and nothing else reaches that rate in that power (approximate, inference). Baikal Giant N, March 2018, 20 kH/s at 60 W. Against a Vega 64 at 2,009 H/s and about 200 W card power (about 10 H/W) the X3 is about 40x per joule; against a Threadripper 1950X at about 1,000 H/s and 185 W, about 75x (approximate) (https://www.asicminervalue.com/miners/bitmain/antminer-x3-220kh ; https://www.asicminervalue.com/miners/baikal/bk-n ; https://hothardware.com/reviews/monero-mining-with-amd-ryzen-threadripper ; read 8 October 2026).
|
||||
|
||||
**The secret chips.** Monero's own 2018 review: by early 2018 "it was estimated that 80 to 90 percent of the network was specialized hardware" (https://web.getmonero.org/2019/02/12/2018-year-in-review.html); about half the hashrate (about 500 MH/s of 1,000) left at the v7 fork on 6 April 2018; Krawiec-Thayer's nonce study (24 November 2018) found half of all blocks with nonces in the lowest 0.002 percent of the space, patterns that "evaporated abruptly" at the fork (https://www.hackernoon.com/utter-noncesense-a-statistical-study-of-nonce-value-distribution-on-the-monero-blockchain-f13f673a0a0d). Vorick (13 May 2018, through secondary coverage): secret Monero ASIC mining "since early 2017, making up 50 percent of the hashrate". The timeline from the hash to the first secret chip is therefore about 33 months (April 2014 to early 2017), not the 43 the 5 October file gives (which counted to the fork); the announced chip came at 47.
|
||||
|
||||
**The four forks and what each cost a chip.** v7 (6 April 2018): a one-byte tweak to the main loop; half the hashrate left; "a precaution and deterrent". v8 (18 October 2018, height 1,685,555): a whole-cache-line shuffle (4x the bandwidth demand) plus a 64:32 division and a 64-bit square root per iteration, 5 to 10 percent off CPU rate; the hashrate went from about 320 MH/s to just under 1,000 MH/s before March 2019 with chip nonce patterns visible from December: chips back inside two months, dominant inside four (https://decrypt.co/14421/ ; https://en.cryptonomist.ch/2019/05/08/mining-monero-hashrate-pow-change/). CryptoNight-R (9 March 2019, brought forward from April after the detection): a per-block random sequence of 60 to 69 integer instructions (63 on average; MUL 40 percent, XOR 23, SUB 12, ADD 12, ROR 8, ROL 6) over 9 registers, seeded by height so miners compile ahead; SChernykh's claim is a chip's minimum latency for the random math "at least 2.5 times higher" than the DIV plus SQRT it replaced (a chain of 15 multiplies against 6), with up to 1.5x more for an out-of-order chip; a hardware engineer in the PR thread estimated a chip could still do about 18 ns per iteration, comparable to a CPU (https://github.com/SChernykh/CryptonightR ; https://github.com/monero-project/monero/pull/5126). The hashrate fell from about 1 GH/s to 140 MH/s and settled at 300 to 350 MH/s; no CN-R chip is documented in its nine months. RandomX followed on 30 November 2019.
|
||||
|
||||
**The mapping to v6.** CryptoNight is class B (SRAM-scale memory: layer 2 closes it, the 2 GiB dataset is 1,000 mm^2 of SRAM even at N5) and class D (the forks: v7 and v8 kept the machine's shape and the chips returned; CN-R changed what the machine had to be, a per-block random program, and no chip came in nine months, which is the per-epoch random program Igneum ships). The number: 40x per joule for the X3 against a GPU; the Igneum analogue, the f = 0 recompute chip that holds the 256 MiB cache on die, reads 0.92x at the op budget and 1.86x per joule (`chip-model-v3.md` 5.4), and CN-R's 2.5x latency claim is the fixed-shape mixer's 3x factor in the other direction. The honest residue: Monero's chips were found by nonce pattern four months after a fork at 85 percent of the hashrate; Igneum has no detector yet.
|
||||
|
||||
### 2.12 X16R (Ravencoin, January 2018): a drawn order over fixed functions
|
||||
|
||||
**The mechanism and the chips.** Sixteen hash functions in an order set by the previous block hash, a per-block automatic change with no fork. The sequencing changed; the sixteen primitives did not, so one large FPGA holding all sixteen cores needs only per-block routing: BittWare and SQRL's CVP-13 (Xilinx VU13P) was announced on 7 September 2018 naming "X17r, X16r and TimeTravel10" (https://www.cryptoninjas.net/2018/09/07/squirrels-research-labs-and-bittware-launching-new-fpga-crypto-mining-hardware/ ; https://www.bittware.com/cvp-13 ; read 8 October 2026). An unknown pool held 10 to 20 percent of blocks in February 2019, 30 to 40 in March, 45 by 11 July; the OW Miner OW1 (September 2019, 182 MH/s at 1,500 W, about USD 500) and SKC Turing R1 (680 MH/s at 800 W, about USD 1,500) were sold as ASICs, their insides unconfirmed; against a P102-100 at 35 MH/s and 219 W the OW1 is 0.75x and the R1 about 5x per joule (https://cryptoage.com/en/1782-asics-ow-miner-ow1-and-skc-miner-turing-r1-for-the-x16r-algorithm-exist.html ; https://miningboard.com/algorithms/X16R). X16Rv2 (1 October 2019) swapped one hash in; on 30 January 2020 Tron Black called the chips' return "evident"; KawPow followed in May 2020; Ravencoin's roadmap records "ASICs have been developed for X16R (and X16Rv2)" (https://cointelegraph.com/news/ravencoin-community-clash-over-mining-algorithm-continues ; https://github.com/RavenProject/Ravencoin/blob/master/roadmap/README.md).
|
||||
|
||||
**The mapping to v6.** Class D in its purest form, and the warning for layer 1: a draw over a FIXED set is a configuration to a chip that holds the set. Igneum's op-mix draw is over twelve families a chip holds from genesis; what the draw does cost a chip is nothing, and what it costs the honest card is the per-vendor energy table. Does v6 close it: the fixed-function lane is closed by the per-epoch program (there is no sixteen-core pipeline to route), and the draw itself is a governance device. The number: 5x for the one X16R box with a plausible chip inside; the GPU-without-graphics sequencer's gain on Igneum's program side is bounded by that kind of figure, and its memory side by class C's 5.1x.
|
||||
|
||||
### 2.13 Lyra2REv2 (Vertcoin, August 2015): FPGA first, then the Zig Z1
|
||||
|
||||
A memory-hard sponge (Lyra2 at T = 1, R = 8, C = 256, p = 1: a matrix small enough for on-die SRAM per core, on the order of 200 KB, approximate) inside a chain of hashes. The FPGA came first: an academic Lyra2 core on 16 July 2018 and a full FPGA miner at 2.6 to 3.7 MH/s and 323 to 432 nJ per hash, "significantly more energy efficient than both a GPU and a commercially available FPGA-based miner", which confirms commercial bitstreams before the chip (https://arxiv.org/abs/1905.08792); the Dayun Zig Z1 on 19 September 2018: 6.8 GH/s at 1,200 W, 28 nm, USD 8,000, "equivalent to 100 GeForce GTX 1080 Ti", about 20x per joule against a 1080 Ti at about 68 MH/s and 250 W (https://cryptoage.com/en/1231-first-asic-miner-lyra2rev2-dayun-zig-z1.html; read 8 October 2026). Vertcoin 0.14.0 forked at block 1,080,000 (1 February 2019) "to rid the network of the current generation of Lyra2REv2 ASICs and FPGAs" with Lyra2REv3 (R = 32, p = 4: 16x the memory), then Verthash in January 2021 (https://github.com/vertcoin-project/vertcoin-core/releases/tag/0.14.0). The 22 reorgs of October to December 2018 and the December 2019 attack came through rented hash on a hashrate the forks had reset (the 5 October file, row 7). Mapping: class B (layer 2 closes it) and lesson 5 (the fork reset the hashrate to a rentable size, which v6's layers 1 and 3 never do). The number: 20x; Igneum's f = 0 chip 1.86x.
|
||||
|
||||
### 2.14 Eaglesong (Nervos, November 2019) and Blake3 (Alephium, November 2021): compute, embraced
|
||||
|
||||
Eaglesong: a new sponge; the Toddminer C1 in February 2020 at 4 months, the Antminer K5 (April 2020, 1.13 TH/s at 1,580 W), the K7 at 63.5 TH/s and 3,080 W; about 100x per joule against an RTX 2080 Ti at about 1.5 GH/s and 220 W (approximate) (https://www.asicminervalue.com/miners/bitmain/antminer-k5-1130gh ; https://miningboard.com/algorithms/Eaglesong). Blake3: double Blake3, chosen as chip-friendly; the Goldshell AL-BOX (May 2024, 360 GH/s at 180 W), Antminer AL1 (15.6 TH/s at 3,510 W) and AL1 Pro (August 2024, 16.6 TH/s at 3,730 W), AL3 (8 TH/s at 3,200 W); about 100x to 220x per joule against an RTX 4090 at 6.0 GH/s and about 300 W (https://www.asicminervalue.com/miners/goldshell/al-box ; https://whattomine.com/asics/294-bitmain-antminer-al1-pro). Blake2s on Kadena: the Goldshell KD5 (March 2021, 18 TH/s at 2,250 W) and Antminer KA3 (166 TH/s at 3,154 W) against a GTX 1660 Super at 633 MH/s and 79 W: about 1,000x and 6,500x (https://www.asicminervalue.com/miners/goldshell/kd5 ; https://miningboard.com/algorithms/Blake%20%282s-Kadena%29). NexaPow (SHA-256 plus a secp256k1 Schnorr signature per nonce, "useful ASICs"): the DragonBall A21 (December 2024, 3.4 GH/s at 1,800 W, USD 6,999) is only about 2.2x per joule against an RTX 4090 at 320 MH/s and 380 W, because big-integer elliptic-curve arithmetic leaves a fixed pipeline little to strip (https://spec.nexa.org/mining/NexaPOW/ ; https://www.asicminervalue.com/miners/dragonball-miner/a21 ; all read 8 October 2026). Mapping: class A, closed since class v2; the numbers (100x to 6,500x) are what a fixed function costs, and NexaPow's 2.2x is the one compute-bound row where the chip's edge stayed small, because the work was already a wide multiplier chain, which is the shape of the ALU shadow's k band (0.3 to 0.8) in another chain's numbers.
|
||||
|
||||
## 3. The three lessons, with the evidence
|
||||
|
||||
**Lesson 1. The chip that stores the dataset is firmware-immune to every draw; only joules and memory growth move it.** Evidence: the five Ethash chips (section 2.1) never touched Ethash's compute and never needed to; Rao's audit said in 2019 that "the energy expended to move data from DRAM to compute are the same for GPU or ASIC" and that the only lever a chip has is the memory's own energy per bit, which Jasminer took by bonding the DRAM to the die; the Least Authority audit's conclusion that "the random math core likely prohibits the build of a light-evaluation based ASIC" was about the f = 0 chip and said nothing about the f = 1 chip, which is the one that shipped on Ethash in three forms. On Igneum's side the identity of `counter-asic-4-research.md` section 2 says it in one line: at zero premium the edge is E_card over E_mem and no hash change touches it. What v6 inherits: 5.1x per joule on GDDR7 at zero premium against the 5090 unlocked, 3.6x at its 1,300 MHz knee, 2.1x with the class v4 shadow at k = 1, and USD 2.8 against 14.7 per MH/s. What binds on v6: every per-era draw of layer 1 and every family epoch of layer 3 must be priced against this chip as a configuration change (a recompile per epoch, a new mapping per era) and never claimed as a cost to it; the public text's "under 2x" stays worded against the recompute chip, as the 6 October verdict already requires.
|
||||
|
||||
**Lesson 2. Automatic change beats the human fork only where it costs the chip a redesign, and the one parameter that does is the memory.** Evidence: Grin's three Cuckaroo tweaks (17 July 2019, 15 January 2020, 16 July 2020) each changed the edge function and no chip ever shipped for the lane, but each was a hard fork with a new solver and the lane was scheduled to die; Monero's v7 and v8 kept the machine's shape and the chips were back inside four months, CN-R changed the machine and no chip came in nine months, RandomX changed it again and the X5 took 46 months; X16R's per-block order cost the FPGA nothing; Scrypt-N's public, slow growth was abandoned before a chip because the chip could be sized for years of it; Ethash's DAG growth is the one automatic rule in the record that killed a shipped chip, and it killed the one chip whose memory was sized to the card fleet's own limit (4 GB), 20 to 27 months after shipping. The compile and design cycles bound the race: Bitmain built the A3 in about 5 months and Halong the B52 in 9 (Vorick), a full Vivado compile on a mid-size part runs 42 to 160 minutes and hours on a large one (PRflow, FPT 2019), so an hourly program outruns every compile and a six-monthly change outruns no chip. What binds on v6: layers 1 and 3 close the governance failure (no fork, no hashrate reset to a rentable size, which cost Vertcoin two 51 percent attacks) and tax a sequencer chip die area, not architecture: Rao's own figure is about 1 M gates and 0.025 mm^2 at 10 nm for ProgPoW's whole inner loop, so a lane array carrying every reserve family is the class v4 shadow core's 30 mm^2 of N5 and USD 25 to 40, not a wall. Layer 2 is the one real lever, and its value is its floor and ceiling, not its tracking: the floor keeps class B closed (2 GiB is 1,000 mm^2 of SRAM at N5), and a ceiling under the honest tiers' memory is a requirement, because any rate that ages out a 32 GB chip board retires the 8 GB card first.
|
||||
|
||||
**Lesson 3. A steered or biased address pattern is always found after launch unless the test lives in the acceptance rule, and every new draw needs its own null.** Evidence: Kik's exploit came five months after two audits that named the seed's keccak as a thing to scrutinise and three days after the EIP was declared dead; Dinur and Nadler found MTP's under-1 MB proof before launch only because the construction was published and reviewed, and the fix was a construction change; AP-F8-1 was found by the attack-pass lane one day after class v4 reached the devnet, in 96.6 percent of the class's programs, and took three sub-versions and class v5's floor to close; the in-house pass then found a program that passed every part of the rule and still read a live hot set, which is why the floor sits at 0.995 and not 0.98. What binds on v6: layer 4's test is a per-site ratio against the window model, and the window model is a function of the dataset size, the windows, the era stride and the read width, so a draw of any of those changes the null and the census must be re-derived per era (2.2 s per candidate at 2^20 on one box core; 0.7 percent of candidates refused at the floor); the residue the floor cannot reach without refusing most clean programs (the shadow-written concentrations at 0.9992 to 0.9997, about 1.0004x) moves with any draw of the shadow placement and needs its own ceiling per era, with the F8 gate's 1.2x-of-window shape.
|
||||
|
||||
## 4. The four layers against the history, layer by layer
|
||||
|
||||
### 4.1 Layer 1: per-era draws of the class parameters
|
||||
|
||||
What is declared: the parameters now fixed by release (the mixer round count within the tested margin, the op-mix weights within the measured safe band, the read width, the program length, the shadow placement) are drawn per era from chain state like the program. What the history says about each:
|
||||
|
||||
| Parameter drawn | The precedent | What the draw costs a chip | What it costs the honest card and the verifier | Reading |
|
||||
|---|---|---|---|---|
|
||||
| Mixer round count (within the tested margin) | RandomX made the item derivation itself a random program so a chip could not hard-wire it (SuperscalarHash); CryptoNight-R's random math raised chip latency 2.5x | nothing on the f = 1 chip (it derives no item); on the f = 0 recompute chip the fixed shape is the 3x factor, and a drawn ROUND COUNT keeps the shape: the chip builds the widest count and gates the rest | the verifier's 10 ms gate caps the count (x8 is 2.1 ms per warp on the reference core, x16 about 3.7); the daily build 23 to 77 ms at x8 | a draw of the count within a margin the chip already covers is firmware; the lever against the recompute chip is a drawn SHAPE (the 5 October addition 2, reserve), and the recompute chip is not the one anyone builds (chip-model-v3 5.6) |
|
||||
| Op-mix weights (within the measured safe band) | X16R drew the ORDER of sixteen fixed hashes per block and an FPGA served it at 1.3x within 20 months; ProgPoW drew the math per period and no chip exists on its adopters in eight years, on small prizes | a sequencer chip over the twelve families covers any weight table; the measured GPU cost per family is the real constraint (shfl 55.8 pJ against add 11.3 on the 5090: a shuffle-heavy draw taxes the card up to 5x per instruction with no better k) | the per-program hash-rate spread must stay under the 5 percent rule on every vendor across the band (the six-era spread was 1.3 to 3.2 percent on the era layout) | right as a governance device (no fork), neutral as a chip device; the band must be bounded by the per-vendor cost table of `counter-asic-4-research.md` 15.1a, not only by the rate spread |
|
||||
| Read width | w16 moved the honest denominator 2.7 percent and the chip's cost not at all; w64 made the 5090 bandwidth-bound (71.9 MH/s); the 9070 XT pays a 64-byte line at every width | the chip pays the same 32-byte atom at w4 and w16; wider reads hand a custom controller the Ren-Devadas bandwidth lever (the Ethash chips' whole edge) | a 47 percent loss on the 5090 at w64 | the one parameter whose draw can move the memory physics the wrong way: keep the allowed set at {1} (as 1.13.1 already does) unless a wider width is measured latency-bound on all three vendors; a draw over {4 B, 16 B} is harmless and worthless |
|
||||
| Program length | ProgPoW's loop count and Ethash's 64 accesses were fixed; RandomX's 8 chained programs of 256 instructions fixed; no chain drew its program length | a longer program is more shadow work per hash: the class v4 lever (the latency ladder) priced at 2.1x at k = 1; a chip builds the longest rung's core and idles it on short eras | the verifier rung 3 is inadmissible on the reference core (latency-ladder section 5); the card's premium per op 6.2 to 11.3 pJ measured | the draw must stay inside the admissible rungs (0 to 2); its value is the governance one (the ladder stepped by draw instead of by 90 percent signal), and the honest card pays the premium on every era |
|
||||
| Shadow placement | no precedent in any chain; the per-load placement (16 blocks of 16 after every load) was DEAD as drawn on 7 October (acceptance in execution order accepts 1.4 percent of candidates; `counter-asic-4-research.md` 20.2a-close) | the per-load form would force the chip's ALU core inside every read's dependency (the USD 200 M break-even row, 16.2) if a sound form existed | compile-ahead at 16 sites; a class change | draw only over placements shown sound (today: the one block after the loads); the per-load form is the research item, not a draw value |
|
||||
|
||||
### 4.2 Layer 2: the dataset's size tracking chain-state growth with a floor
|
||||
|
||||
What is declared: the state-derived dataset's size tracks chain-state growth, with a floor, so fixed-memory silicon ages out. The history has exactly two scheduled memory-growth rules that ran against shipped hardware, and one of them killed a chip:
|
||||
|
||||
| Precedent | The rule | What it did to chips | What it did to honest cards | Source |
|
||||
|---|---|---|---|---|
|
||||
| Ethash DAG growth | +8 MB per epoch of 30,000 blocks (about 0.7 GB a year; Rao's audit, slide "DAG size"); 1 GB at launch (July 2015), 3.0 GB by July 2019, 3.94 GB by November 2020 | the Antminer E3 (shipped July 2018, 4 GB of DDR3) ran out of DAG room on Classic at epoch 328 (about 3.56 GB, March 2020) and on Ethereum at about block 11.4 million (about October 2020) after a 30 March 2020 firmware stretched its DDR use: 20 to 27 months after shipping, 57 to 63 months after the hash went live; the A10 Pro (6 GB) and every later chip carried more memory than any card of its year and never aged out | the same rule retired 3 GB cards in 2018 and 4 GB cards by December 2020; Ethereum Classic cut the DAG to 2.47 GB (Thanos, ECIP-1099, block 11,700,000, 28 November 2020) to keep the 4 GB cards after the August 2020 51 percent attacks, and its own text says the fork kept "competitive mining across both GPU and ASIC hardware" | https://ethereumclassic.org/blog/2020-11-27-thanos-hard-fork-upgrade/ ; https://coingeek.com/memory-limitations-prompt-bitmain-antminer-e3-to-halt-etc-support/ ; https://cointelegraph.com/news/bitmains-antminer-e3-to-continue-mining-ether-with-new-update (all read 8 October 2026); Rao's audit, the DAG-size slide (https://github.com/ethcatherders/progpow-audit) |
|
||||
| Autolykos v2 table growth | N = 2^26 elements of 31 bytes (2.08 GB) until block 614,400; then about 5 percent every 51,200 blocks (N doubles every 102,400 blocks, about 142 days at Ergo's 2-minute block) to a cap of 2,143,944,600 elements at block 4,198,400 (about 66 GB) | no chip has shipped for Autolykos as of today, on a small prize; the rule has never been tested against one | the table passes 8 GB in about 2 years of growth and 16 GB a year later (arithmetic on the rule); Ergo's GPU fleet thins by card memory on a schedule it chose | https://docs.ergoplatform.com/mining/autolykos/ (read 8 October 2026) |
|
||||
|
||||
The arithmetic that binds. A chip's memory is bought by the board, and today's prices are the chip model's: GDDR7 about USD 20 per 2 GB device, so 32 GB on a 512-bit board is USD 320; one HBM3 stack 24 GB about USD 200 (`chip-model-v3.md` 5.1, September to October 2026 prices). Igneum's schedule as specified (2 GiB plus 0.5 GiB a year, doubling steps at years 4, 12, 28; spec 1.13.3) reaches 4 GiB at year 4 and 8 GiB at year 12. Against that schedule:
|
||||
|
||||
| Memory the chip or card holds | Years until the dataset passes it | Who it is |
|
||||
|---|---|---|
|
||||
| 8 GB | 12 | the honest 8 GB card (the first tier out, `card-lifetime-2026-10-05.md`) |
|
||||
| 12 GB | 20 | the honest 12 GB card |
|
||||
| 16 GB | 28 | the 9070 XT class |
|
||||
| 24 GB | 44 | one HBM3 stack; the 4090 and the M5 Max class |
|
||||
| 32 GB | 60 | the f = 1 GDDR7 chip's board; the 5090 |
|
||||
|
||||
So layer 2 as a rate "tracking chain state" ages out fixed-memory silicon only if the dataset grows faster than a chip generation's memory headroom, and every rate that does that retires the honest small cards first by the same table. The E3 is the only case in the record where a growth rule beat a chip, and it beat a chip that had under-provisioned memory by a factor the card fleet also hit (4 GB). The rule that would hurt the f = 1 chip is one that keeps the dataset above what one board of commodity DRAM holds at the chip's price point, and that rule is unaffordable for the honest fleet. The honest reading: layer 2 is the right lever class (the memory is the one parameter a stored-dataset chip cannot read as firmware), and its value is set by the floor and the ceiling, not by the tracking: a floor keeps the dataset above every SRAM die (class B stays closed: 2 GiB is 1,000 mm^2 of SRAM even at N5), and a ceiling keeps it under the honest tiers' memory. Between those two lines the chip's board holds whatever the card holds, and the growth rate changes nothing for it. What "tracking chain state" adds over the fixed schedule is governance (no release decides the size) and the class v5 link (the dataset is built from the state, so the size follows the state's record count naturally); it is not an anti-chip rate. Resolved by the synthesis lane (11:2x UK, `docs/design/class-v6-rotating-family.md` section 7b on `counter-asic-4`): layer 2's rule carries a per-year ceiling as its first constant, the fixed schedule's power-of-two step for that year, so the chain's state can bring a step forward and never add one; "retires cards before chips" is recorded as the reason the ceiling exists. Under that rule the table above is the ceiling's own schedule, and the honest 8 GB tier's year-12 line stands whatever the state does. What this file adds for the record: if the chain's state grew the way Ethereum's did (approximate, from memory: the account and storage state passed 100 GB in its eighth year), a dataset tracking it with no ceiling would have outgrown every consumer card inside the first decade; the ceiling is what makes layer 2 a governance rule and not a fleet-retirement rule.
|
||||
|
||||
### 4.2a One schedule, priced (main's ask of 11:2x UK, for the 20:00 reading)
|
||||
|
||||
Main asked for one dataset-floor schedule priced per tier and against the chips, so the 20:00 reading carries a decision: 6 GiB at the v6 epoch, 10 GiB two years on, 14 GiB at four years, each step by height like a class epoch, the schedule a consensus field. The method is `card-lifetime-2026-10-05.md`'s: a card's room for the dataset is its usable memory (75 percent of card memory, the standing rule "the whole working set under 6 GB on an 8 GB card"; 50 percent of Apple unified memory) less the non-dataset working set (best: 32 KiB scratch, the cache freed after the build, 254 to 479 MiB by tier; worst: 128 KiB scratch, the cache resident, 600 to 1,500 MiB). The population is the bench table's measured cards (`site/miner-bench.json`, 8 October 2026: 32 distinct consumer cards, one Apple part, eight datacentre parts); the fleet's own card census is not a file this lane could find and is owed, so the shares below are by count of distinct measured cards, not by hashrate.
|
||||
|
||||
**What the memory arithmetic says about main's three steps.** A step fits a tier when the dataset plus the working set is under the tier's usable memory.
|
||||
|
||||
| Step | 8 GB (usable 6,144 MiB) | 10 GB (7,680) | 11 GB (8,448) | 12 GB (9,216) | 16 GB (12,288) | Apple 16 GB unified (8,192) | 24 GB (18,432) | 32 GB (24,576) |
|
||||
|---|---|---|---|---|---|---|---|---|
|
||||
| 6 GiB (6,144 MiB) | **does not fit the rule**: 6,398 best, 6,744 worst, 78 to 82 percent of the card; fits only if the budget rule moves to about 85 percent (a headless rig with no display) | fits (6,404 best, 63 percent) | fits | fits | fits | fits (6,432 MiB, 79 percent of its usable half) | fits | fits |
|
||||
| 10 GiB (10,240 MiB) | out | out | out | **out**: 10,506 best, 10,888 worst, 86 to 89 percent | fits (10,518, 64 percent) | out | fits | fits |
|
||||
| 14 GiB (14,336 MiB) | out | out | out | out | **out**: 14,614 best, 15,032 worst, 89 to 92 percent | out | fits (14,752, 60 percent) | fits |
|
||||
|
||||
So main's schedule as stated retires, under the standing budget rule: at 6 GiB the 6 GB tier and, unless the rule is loosened to about 85 percent, the 8 GB tier (22 percent of the measured consumer cards: the RTX 3070, 3070 Ti, 3060 Ti, 4060, 4060 Ti 8 GB, 5060, 2070 Super) on day one; at 10 GiB the 10, 11 and 12 GB tiers and Apple 16 GB (another 31 percent: the RTX 3080, 1080 Ti, 2080 Ti, 4070, 4070 Ti, 4070 Super, 5070, 3080 Ti, 3060, Arc B580) at year 2; at 14 GiB the 16 GB tier (28 percent: the RTX 5060 Ti, 5070 Ti, 5080, 4080, 4080 Super, 4070 Ti Super, 4060 Ti 16 GB, RX 9070 XT, RTX A4000) at year 4, leaving 24 GB and above (16 percent of the measured consumer cards, plus every datacentre part). That is not the tier order main's note describes, so the schedule that drops the tiers in that order is priced beside it:
|
||||
|
||||
| Step | Dataset | Year | Who falls off (share of the 32 measured consumer cards) | Who holds, and at what share of card memory (best / worst) |
|
||||
|---|---|---|---|---|
|
||||
| v6 epoch | 5.5 GiB (5,632 MiB) | 0 | the 6 GB tier (RTX 2060: 3 percent) | 8 GB at 72 / 76 percent (the worst case one point over the rule); 10 GB 77 percent; Apple 16 GB unified at 72 percent; everything larger |
|
||||
| +2 years | 8 GiB (8,192 MiB) | 2 | the 8 GB tier (22 percent), the 10 GB RTX 3080 (3 percent: 8,452 of 7,680), Apple 16 GB unified (8,480 of 8,192) | 11 GB at 100 percent of usable (the 1080 Ti and 2080 Ti: out in practice, 6 percent); 12 GB at 69 / 72 percent; 16 GB; 24 GB; 32 GB; Apple 32 GB at 52 percent of its usable half |
|
||||
| +4 years | 11 GiB (11,264 MiB) | 4 | the 12 GB tier (22 percent) | 16 GB at 70 / 73 percent; 24 GB at 48 percent; 32 GB; Apple 32 GB at 71 percent of its usable half |
|
||||
| the fixed schedule's own steps beyond | 16 GiB | the year the state brings it forward, else year 28 | the 16 GB tier (28 percent); Apple 32 GB | 24 GB at 68 percent; 32 GB |
|
||||
|
||||
Reading, per tier, in the form main asked for (the year each falls off, and the share of today's measured cards that is): on the priced schedule the 6 GB tier falls at the v6 epoch (3 percent), the 8 GB tier and the 10 GB RTX 3080 and the Apple 16 GB laptop at year 2 (25 percent of the consumer cards plus the base Apple laptop), the 11 GB Pascal and Turing parts in practice at year 2 (6 percent), the 12 GB tier at year 4 (22 percent), the 16 GB tier at the 16 GiB step (28 percent), and 24 GB and above hold through every step priced. On main's schedule as stated the same tiers fall two years earlier each, and the 8 GB tier falls on day one unless the 75 percent rule moves. Either way this is the fleet-retirement rule the ceiling exists to bound (section 4.2): a step every two years retires a quarter of today's measured consumer cards each time.
|
||||
|
||||
**Against the chips, with the number.** Three chips, by what the step does to each:
|
||||
|
||||
| Chip | What a step costs it | The number |
|
||||
|---|---|---|
|
||||
| The hybrid-bonded DRAM chip sized at launch (the Jasminer X4's shape: DRAM dies bonded to the logic at tapeout, 5 GB per unit in 2021; the E3's shape in commodity form, 4 GB of DDR3 soldered to the board) | its memory is fixed at tapeout, so it dies at the first step it cannot carry, as the E3 did 20 to 27 months after shipping. On main's schedule a chip sized to the 6 GiB floor with 8 GB of bonded DRAM dies at the 10 GiB step (year 2); on the priced schedule a chip sized to 5.5 GiB with 8 GB dies at the 8 GiB step (year 2); a chip sized with 16 GB holds through year 4 on both and dies at the 16 GiB step. But the schedule is a consensus field read at genesis, so a maker sizes to the step it wants to survive: the X4's 5 GB was Ethash's DAG plus a year, chosen off a public schedule; the E3 died because its memory was sized to the CARD FLEET's limit, not to the schedule | kills only the chip that under-sizes; sizing to 16 GB costs the X4 shape about 3x its 2021 memory die area (approximate) and the E3 shape USD 160 more of GDDR7 (8 x USD 20, chip-model-v3 5.1) on a USD 470 part |
|
||||
| The f = 1 GDDR7 chip on a board (the record's class C; 16 x 2 GB devices, 32 GB) | nothing until the dataset passes 32 GB: every step priced here fits its board; a bigger step buys more devices at USD 20 per 2 GB | USD 0 per step through 16 GiB; its 5.1x per joule and USD 2.8 per MH/s stand at every step |
|
||||
| The SRAM store (the f = 0 recompute chip holding the cache on die) | the dataset's size costs it nothing (it derives every item); the CACHE's doubling under option C costs it capex only: 128 mm^2 and USD 46 per good die at 256 MiB, 255 mm^2 and USD 111 at 512 MiB (year 4 on the fixed schedule, or the year the state brings the doubling forward), 510 mm^2 and USD 306 at 1 GiB; and the mirror's size is what forces it onto a 7 nm or better node (the 5 October file, section 2.5) | USD 46 to 111 per die at the year-4 doubling; its edge stays 0.92x at the op budget and 1.86x per joule (`chip-model-v3.md` 5.4), unmoved by the dataset's steps |
|
||||
|
||||
The honest sentence for the 20:00 reading: the dataset-floor schedule is a fleet-retirement rule with a chip tax of USD 0 to 160 per unit on the chips that matter (classes C and B), and it kills only a chip whose maker ignores a public consensus field; the one precedent of a growth rule killing a chip (the E3) is a precedent of a maker sizing to the fleet, not to the schedule. If the schedule is adopted, the 75 percent budget rule and the 6 GiB floor cannot both stand for the 8 GB tier; 5.5 GiB keeps the 8 GB card inside the rule in the best case and one point over in the worst, and the headless-rig reading (about 85 percent) is what makes 6 GiB fit. The fleet's hashrate-weighted census is owed before the share column is read as a hashrate share.
|
||||
|
||||
### 4.3 Layer 3: scheduled family epochs by height, every 180 days, no release
|
||||
|
||||
What is declared: a new instruction family goes live on a height schedule, every 180 days by default, with no release (the reserve of spec 1.13.2, ordered at genesis). The record of scheduled change against chips:
|
||||
|
||||
| Chain | The change and its cadence | Human release needed | What it cost the chip | Outcome | Source |
|
||||
|---|---|---|---|---|---|
|
||||
| Grin, Cuckaroo lane | a new tweak of the edge function every six months (Cuckarood July 2019, Cuckaroom January 2020, Cuckarooz July 2020), each a hard fork; the lane's reward share scheduled from 90 percent to zero by January 2021 | yes, every time | a new edge function per tweak: a redesign, not a configuration | no chip ever shipped for the tweaked lane; the chip lane (Cuckatoo31+) got the iPollo G1 at about 4x in 23 months | the 5 October file rows 18 and 19, [S61] to [S66] |
|
||||
| Monero | four algorithm forks in 20 months (v7 April 2018, v8 October 2018, CN-R March 2019, RandomX November 2019) | yes, every time | v7 and v8: a re-spin (85 percent of the hashrate vanished at v7 and chips were back at 85 percent four months after v8); CN-R: random math per block, chip latency up 2.5x; RandomX: a new class of machine, parity hardware after 46 months | the forks were events; the chips survived the ones that kept the shape and died on the one that changed the machine | rows 16 and 17; Vorick on a fork-surviving chip, [S47] |
|
||||
| Ravencoin X16R | the ORDER of sixteen fixed hashes drawn per block from the previous block hash; no fork needed | no | nothing: a sixteen-core sequencer reads the order as a configuration | an FPGA at 1.3x within 20 months; the X16Rv2 fork (one hash swapped) was answered by bitstreams within weeks | row 9 |
|
||||
| Ethereum ProgPoW | the random math re-drawn every PROGPOW_PERIOD (50 blocks in 0.9.2, 10 blocks in 0.9.3, about 2 minutes); the op set fixed (add, mul, mulhi, min, rotl, rotr, and, or, xor, clz, popcount) | no | a sequencer over the eleven ops and a 32-register file; the audit priced the conventional compute chip at little gain and the on-die cache chip at "<< 0.1x" energy per hash | never deployed on Ethereum; no chip on KawPow or FiroPoW in five to six years on small prizes | https://eips.ethereum.org/EIPS/eip-1057 and https://github.com/ifdefelse/ProgPOW (read 8 October 2026) |
|
||||
| Igneum class v2 to v6 | a new program every epoch; era draws every 180 days; one reserve family per era | no | a recompile per epoch; the reserve families are in the shipped generator from genesis, so a chip that reads the reserve at genesis carries every family's datapath from day one | the governance failure is closed; the chip is not | this file |
|
||||
|
||||
The clocks that bound the race (all read 8 October 2026): Bitmain built the A3 "in about 5 months" and Halong the B52 "in about 9" (Vorick, through https://www.nextbigfuture.com/2018/05/obelisk-explains-the-state-of-asics-and-crypto-mining.html); KnC taped out a 20 nm part "only 3 months after starting the project" in 2014 (https://www.design-reuse.com/news/34090/20nm-asic-for-bitcoin-mining.html); ASICMiner went from founding in July 2012 to 64-chip boards on 31 January 2013 (Taylor, IEEE Computer 2017, https://michaeltaylor.org/papers/Taylor_Bitcoin_IEEE_Computer_2017.pdf); Linzhi from founding (February 2018) to tested boards (December 2020) took 27 months; Rao's 10 nm-class project "1+ year". A full Vivado compile on a mid-size Xilinx part (ZCU102) runs 42 minutes typical and 160 worst (PRflow, FPT 2019, https://ic.ese.upenn.edu/abstracts/prflow_fpt2019.html) and "several hours" on a large device (a 2021 Paderborn talk); the Least Authority audit called a 2-minute period "impractical" for a bitstream; the one KawPow FPGA on record is an academic VU35P build at 5.6 MH/s (NTU 2022, https://tdr.lib.ntu.edu.tw/handle/123456789/84103?locale=en), under an eighth of a 2022 GPU. So an hourly program outruns every compile and every design cycle; a 180-day family epoch outruns no chip's design cycle and does not need to, because the family is in the generator from genesis.
|
||||
|
||||
Reading. Scheduled change beat chips in exactly one shape: Grin's, where each change was a new function nobody could know in advance, and even then only because the lane was built to die. Every change a chip could read at genesis (X16R's order, ProgPoW's period, Igneum's reserve) became firmware. Layer 3 as declared is X16R's and ProgPoW's shape, automated and spaced at 180 days: it removes the fork (lesson 5 of the 5 October file, and the one thing that cost Vertcoin two 51 percent attacks), and it taxes a sequencer chip die area for families not yet live. The honest number for that tax is small: the reserve's candidates are integer ALU operations (shifts, bit-field extract, andn, byte permute, popcount, select, the second shuffle form; mm8 last), each a few thousand gates per lane; against the f = 1 chip's USD 470 of memory and board, a lane array carrying every reserve family is the same 30 mm^2 of N5 the class v4 shadow already forces (`counter-asic-4-research.md` 16.1: USD 25 to 40 of die). The one family that is not cheap for a chip to carry idle is one whose unit is large (mm8's tile engine), and that is exactly the family the measured rows say not to use for forcing (the 5090's int8 MAC at 1.4 to 4.1 pJ against a 5 nm array's claimed 0.04 to 0.4: `counter-asic-4-research.md` 15.1a). So layer 3 is right for governance and neutral for the chip; what would make a family epoch cost a chip a redesign is a family whose semantics are not knowable at genesis, which is the random item-derivation program of the 5 October addition 2 (a per-day SuperscalarHash-style derivation), the one RandomX idea Igneum has not taken, and it acts on the f = 0 chip only.
|
||||
|
||||
### 4.4 Layer 4: the (c''') floor and the F8-form uniformity test per era draw
|
||||
|
||||
What is declared: the (c''') acceptance floor (the per-site distinct-index ratio at or above 0.995 against the window model, spec 1.4.7.2) and the F8-form uniformity test generalised to each era's parameter draw, with a redraw on failure. The history has three attacks of this one class, and in every case the test that would have caught it lived outside the acceptance rule:
|
||||
|
||||
| Attack | The steer | Found when | What the fix was | Source |
|
||||
|---|---|---|---|---|
|
||||
| Kik's ProgPoW exploit (4 March 2020) | the 64-bit seed between the two keccak passes: fix a seed, compute its mix once, then grind nonces until keccak_progpow_64(header, nonce) equals the seed; the memory path is run once per 2^64 nonces, so a chip that never touches the DAG wins once the difficulty passes 2^50 | after two tentative approvals and five months after both audits (September 2019) | ProgPoW 0.9.4 widened the carried state from 64 to 256 bits (the digest of the first keccak, plus the mix, plus padding) | https://github.com/kik/progpow-exploit and https://github.com/ifdefelse/ProgPOW (read 8 October 2026) |
|
||||
| Dinur and Nadler on MTP (2017) | the prover controls the memory's contents, so by injecting blocks it steers Argon2d's data-dependent addresses into a set it can hold in under 1 MB at a 170x compute penalty, in place of 2 GB | before launch, by cryptanalysis, not by the design's own test | MTP 1.2 patched the construction | the 5 October file [P18] [S38] |
|
||||
| AP-F8-1 on class v4 (7 October 2026) | a load site whose source register was last written by a lossy op (or, mul, mulhi) saturates to all-ones or zero at a known rate, and the era map sends the constant to one item; 96.6 percent of class v4 programs carried a lossy-sourced load; the worst seed read 29x the window model on one item | in the attack-pass lane's census, one day after the class shipped to the devnet | sub-versions 1 to 3 (the freshness fixpoint, the executed shadow block, the (c'') ratio at 0.98), then class v5's (c''') at 0.995 | `docs/plans/counter-asic-3-status.md` section 7c; spec 1.4.7.2 |
|
||||
|
||||
Reading. Layer 4 is the right answer to this class and the only one of the four layers that acts on a mechanism the record shows beating hashes after launch. Two things bind on it. First, the test can only see what its null models: (c''') measures distinct-index ratios against the window model, which is a function of the dataset size, the per-site windows, the era stride and the read width; a draw of the read width or the program length changes the null, so "generalised to each era's draw" means the window model is re-derived per era and the census re-run per draw, not one floor reused. The cost is known: 2.2 s per candidate at 2^20 on one box core, once per epoch draw on a node, and 0.7 percent of candidates refused by the floor (spec 1.4.7.2). Second, the residue the floor cannot reach without refusing most clean programs is the shadow-block-written concentrations at 0.9992 to 0.9997, worth about 1.0004x to a chip (spec 1.4.7.2), and a per-era draw of the shadow placement moves that residue, so the redraw rule needs its own ceiling stated (the 1.2x-of-window gate of F8 is the right shape; the number per era is the census's to set). The Kik lesson is separate and already closed: Igneum's seed is 256 bits through the VDF and the program is the epoch's, so there is no 64-bit state to grind; the header-locality search (the 5 October check 1) remains the nearest analogue and was measured by adv-accept-2 in the in-house pass.
|
||||
|
||||
## 5. What to add, optimise or invent, ranked (first cut; the full report re-ranks with the other lanes' findings)
|
||||
|
||||
| Rank | What | Why the history says so | Cost to the honest card | Where |
|
||||
|---|---|---|---|---|
|
||||
| 1 | **State layer 2's floor and ceiling in gigabytes per tier, before its rate.** The floor above every SRAM die (today's 2 GiB holds); the ceiling under the honest tiers' memory on a stated glide (the 8 GB tier's life is the first number) | the E3 is the only chip a growth rule ever killed and it was the chip with the fleet's own memory limit; Scrypt-N was abandoned because its growth was public and slow; Autolykos's growth is untested; a dataset that tracks chain state literally outgrows every card if the state grows the way Ethereum's did (approximate) | none at the floor; everything at the ceiling | genesis rule, with the card-lifetime table |
|
||||
| 2 | **The clock and the detector**, unchanged from the 5 October ranking and still unbuilt: the per-program rate spread and nonce pattern on the observer (the method that found Monero's chips at 85 percent), plus a share-by-key-and-template instrument (what found Qubic until it randomised), plus the issuance trigger at about USD 50 K a day | every chip in the record was on its chain before it was announced (Monero 2017, Zcash's three groups, SChernykh's 2021 reading of the X5) | none | before the public testnet |
|
||||
| 3 | **The read width's draw band stops where the honest card stops being latency-bound**: the synthesis lane keeps {4 B, 16 B} on the measured warrant (w16 latency-bound within 2.7 percent on the 5090 and the 9070 XT, within 1 percent on the M5 Max); w64 is out (the 5090 bandwidth-bound at 71.9 MH/s); the draw costs every chip nothing (the same 32-byte atom at either width) and is a governance value only | the Ethash chips' whole edge was the bandwidth lever Ren and Devadas name; a width that makes the card bandwidth-bound hands the chip that lever | within 2.7 percent at w16; 47 percent at w64 | the band {4 B, 16 B} in the class v6 spec; nothing wider without a per-vendor latency-bound measurement |
|
||||
| 4 | **Bound the op-mix draw by the per-vendor energy table, not only by the rate spread**: the 5090 pays 55.8 pJ per shuffle against 11.3 per add, so a shuffle-heavy era taxes the honest card up to 5x per instruction for no better k | X16R's drawn order cost the chip nothing and the fleet nothing; Igneum's draw can cost the fleet watts | up to 2x the premium per instruction at the band's edge | the band's definition in the class v6 spec |
|
||||
| 5 | **Order the reserve by what a sequencer cannot fold into firmware**, mm8 last; and name the random item-derivation program (the 5 October addition 2) as the one reserve item whose semantics are not knowable at genesis | the kHeavyHash chips and the 5090's own 1.4 to 4.1 pJ per int8 MAC; RandomX's SuperscalarHash is the one idea Igneum has not taken, and it acts on the f = 0 chip only | none at launch | reserve ordering, genesis |
|
||||
| 6 | **Generalise layer 4 with a null per drawn parameter**: the window model re-derived per era, the census per draw, and a stated ceiling for the shadow-written residue per shadow placement | lesson 3 | 2.2 s per candidate once an epoch on a node | the class v6 acceptance rule |
|
||||
| 7 | **The per-load shadow placement as a research item, not a draw value**, until a sound construction is drawn (the 16 x 27 form accepted 1.4 percent of candidates) | it is the one placement that would force the chip's ALU core inside every read's dependency (the USD 200 M break-even row) | compile-ahead at 16 sites | `counter-asic-4-research.md` 20.2a |
|
||||
|
||||
## 6. Consequences per user tier
|
||||
|
||||
| Tier | What this history means for it | What is being done |
|
||||
|---|---|---|
|
||||
| Home miner, one 8 GB card | Layer 2 is the one layer whose rate reaches this tier first: at 0.5 GiB a year the 8 GB card is out at year 12, and any rate fast enough to age out a 32 GB chip board is out of this card's life inside two years. No chip of class A, B or E touches this miner under v6; the class C chip (the memory system without the GPU) reaches it as it reached Ethash's 4 GB miners: by price per MH/s, 5x | the layer 2 ceiling stated per tier (section 4.2) before the rate; the issuance clock and the detector (section 5) |
|
||||
| One 12 GB or 16 GB card | as the 8 GB tier with 20 and 28 years on the schedule; the 9070 XT's 10.6 microjoules per hash is 23x behind the GDDR7 chip per joule on the model, so this tier's card is the first the class C chip displaces | nothing in the hash fixes AMD's dependent-read rate; the vendor-share metric is the warning |
|
||||
| One 24 or 32 GB card (5090, M5 Max) | the honest best: 1.69 microjoules at the 5090's knee against the chip's 0.47; 3.6x at zero premium, 2.1x with the shadow at k = 1; the M5 Max at 0.78 microjoules is 1.7x behind the GDDR7 chip with no shadow at all | the operating point as the shipped default (Ember); the shadow's rung |
|
||||
| A rig | the Ethash precedent in full: chips at 2x to 5x per joule and 5x per dollar took the hashrate over four years, and the ASIC share stayed small only while the chips were not cheap enough at scale; the model says this chip is (USD 2.8 against 14.7 per MH/s) | the break-even cap row (USD 100 M in years 1 to 2 with the N5 shadow core) is the real wall; the clock |
|
||||
| A pool user | MoneroCrusher found chips at 85 percent of Monero's hashrate by the share pattern, four months after a fork; Igneum's detector is the same method on the observer, unbuilt | the detector before the public testnet (section 5) |
|
||||
| Every tier, on governance | no fork, ever, for a draw or a family: the history's clearest lesson (Vertcoin's two 51 percent attacks after forks, Monero's four, Ethereum's two-year ProgPoW fight) is the one v6's layers 1 and 3 close outright | nothing further |
|
||||
|
||||
## 7. Unverified and owed
|
||||
|
||||
- The research lanes' returns for the chip mechanism columns (section 1 and 2) are the first cut's owed content; where a lane reports "not found" the row says so and carries the 5 October file's figure.
|
||||
- The Vorick post (13 May 2018) is read through secondary coverage (davidgerard.co.uk, zycrypto.com, nextbigfuture.com, a steemit copy; read 8 October 2026): the secret-Monero-ASIC claim ("since early 2017, making up 50 percent of the hashrate"), the three Zcash groups, the Equihash fork-following architecture, "about 5 months" for Bitmain's A3 and "about 9 months" for Halong's B52, the A3 under USD 10 M with USD 20 M of orders in eight minutes, the manufacturer withdrawal that cost Obelisk "north of USD 2 million". The 5 October file's "13 months for a startup" and "a chip able to survive Monero's forks at under a 5x hit" were NOT found on any fetched page and are carried here as unverified; the Monero fork-survival fact that is verified is the record itself (chips back inside four months of v8).
|
||||
- The KawPow fork block and its 3-block period are approximate (the minerstat and Tron Black pages answered 403).
|
||||
- The Ethereum DAG date of passing 4 GB on the main chain (about December 2020) is approximate; the Classic figures (3.94 GB at epoch 376, 27 November 2020) are cited.
|
||||
- The Ethereum state-size figure in section 4.2 is from memory, approximate, and is the open question handed to the synthesis lane.
|
||||
- Every per-joule ratio for a chip against a GPU is arithmetic on the cited rate and watt figures of both and is approximate by construction.
|
||||
- Nothing here is a measurement; the Igneum figures are the repo's measured rows as cited, and the chip figures are the chip model's, modelled.
|
||||
|
||||
## 8. Sources
|
||||
|
||||
Every URL is cited inline at the row that uses it, with "read 8 October 2026" at the row or the section; the 5 October file's [S], [P], [E] and [L] lists are cited by their tags and not repeated. The primary documents read in full by this lane (text extracted where the page is a PDF): EIP-1057 (https://eips.ethereum.org/EIPS/eip-1057); the ifdefelse ProgPOW README (https://github.com/ifdefelse/ProgPOW); the Least Authority audit (https://leastauthority.com/static/publications/LeastAuthority-ProgPow-Algorithm-Final-Audit-Report.pdf, report version 9 September 2019); Bob Rao's hardware audit (https://github.com/ethcatherders/progpow-audit, 6 September 2019); Kik's exploit (https://github.com/kik/progpow-exploit); RandomX design.md, design_v2.md, specs.md, PR 317, release v2.0 and issue 11 (https://github.com/tevador/RandomX); Tromp's README and the Grin forum threads named in 2.4 (https://github.com/tromp/cuckoo ; https://forum.grin.mw); the Ergo Autolykos docs (https://docs.ergoplatform.com/mining/autolykos/); the Thanos post (https://ethereumclassic.org/blog/2020-11-27-thanos-hard-fork-upgrade/); the TechInsights Jasminer notes (https://www.techinsights.com/ko/node/51986 and /52149); the Fudan NDSS 2019 paper (https://www.ndss-symposium.org/wp-content/uploads/2019/02/ndss2019_09-5_Bai_paper.pdf); Percival's lookup-gap note (https://mail.tarsnap.com/scrypt/msg00092.html); Lee and Kim on Qubic (https://arxiv.org/html/2512.01437v2); PRflow (https://ic.ese.upenn.edu/abstracts/prflow_fpt2019.html). Papers of 2024 to 2026 found: Blocki and Smearsoll, "Provably memory-hard proofs of work with memory-easy verification", ePrint 2025/1456 (Omega(N^2 / log N) cumulative memory with polylog verification: https://eprint.iacr.org/2025/1456); Condrey, PoSME, arXiv 2604.15751; Yang et al., PHICOIN, arXiv 2412.17979 (a resistance claim with no algorithm in the abstract). Pages that refused every lane (403, 404, DNS): Vorick's original post on Medium and sia.tech and its archive copy; Linzhi's and ifdefelse's Medium posts; MoneroCrusher's Medium post (figures taken from criptonoticias coverage); bitmain.com's product list; support.bitmain.com's Z9 page; minerstat; Tron Black's posts; innosilicon.global; jasminer.com (an empty shell); cryptomining-blog.com; the Yole DBI report. The session's web-search budget ran out at 11:0x UK; everything after that is direct fetches of known URLs, and "not found" in this file means not found on a fetched page.
|
||||
256
docs/analysis/class-v6/invention.md
Normal file
256
docs/analysis/class-v6/invention.md
Normal file
|
|
@ -0,0 +1,256 @@
|
|||
# Class v6 invention lane: layers beyond the four, each priced against the chip that stores the dataset
|
||||
|
||||
8 October 2026, first cut 11:1x to 13:xx UK (BST, the Mac's clock; the boxes print CEST, one hour ahead, and nothing below is stated in box time), branch `class-v6-invention` from the mirror's master at 17d61d52, research lane C under the Counter ASIC coordinator. The founder's word of 11:1x UK: class v6 is declared with four layers as its spine (per-era draws of the released parameters; the state-derived dataset's size tracking chain state with a floor; scheduled family epochs every 180 days with no release; the acceptance floor and the F8-form uniformity test generalised to each era's draw), and deep research opens: "see if anything can be optimised, added or invented". This file is the invention lane's answer: every candidate layer beyond the four as one paragraph, one known-failed test stated as a harness run, and one chip-model row, then the ranked list of what v6 should add. The synthesis is the research lane's `docs/design/class-v6-rotating-family.md` (branch `counter-asic-4`), which reads this file.
|
||||
|
||||
Status: a research document and a gate plan. No consensus code this week; nothing here touches the devnet, the testnet object, the spec or any served page. Every number carries a label: **measured** (a run on a named box or card, the log named), **modelled** (arithmetic on the chip model's cited figures, `docs/analysis/chip-model-v3.md` section 5), **claimed** (a vendor's or an author's figure, URL and date), **approximate** (from memory or a scaling). The rule every candidate is held to: **reject what costs GPUs more than it costs chips, and say so with the number; keep what raises a chip's k or capex or shortens its useful life more than it raises every GPU tier's cost.**
|
||||
|
||||
## 0. One page
|
||||
|
||||
The frame is last night's identity (`docs/analysis/counter-asic-4-research.md` section 2): against the chip anyone builds, a GPU's memory system without the GPU (chip-model-v3 section 5.5, the `f = 1` chip), the per-joule edge is `(E_card + F) / (E_mem + k F)`, with `F` the premium per hash the card pays for forced work and `k` the chip core's energy per forced op over the card's. Zero premium is zero forcing. No hash-side design reaches a chip edge of about 2x at zero premium; the premium-free floor is the card's own whole-card energy over the chip's memory energy, 3.6x on a 5090 at its knee (measured card, modelled chip), and the class v4 shadow buys 2.1x at `k = 1` for 82 to 90 W on a 5090. The four layers of v6 render a fixed-function chip useless on its release day and move nothing in the identity for the GPU-like chip. So an invented layer can do one of four things, and only four: raise `k` (nothing on measured rows reads `k` above 1, section 15.1a of the research file); raise the chip's capex or project cost (the one lever the identity does not see); shorten the chip's useful life (layers 1 and 3 already do this for fixed silicon); or cost the honest cards less at the same `F`. Every candidate below was read against those four.
|
||||
|
||||
What was measured today (all on igneum-build-1, the counter-asic-4 crate at 5984ffab, logs under `/srv/builds/v6-invention/`):
|
||||
|
||||
| Reading | Number | Label |
|
||||
|---|---|---|
|
||||
| The sound per-load shadow (one pass of a 256-instruction sub-block after every load, `mx8+shl4096x1`), the form 20.2a-close named and never drew | 234 of 256 seeds accepted within the 32-attempt cap, 0.927 rejection per candidate, mean accepted attempt 9.7; the iterated 16 x 27 form on the same seeds 76 of 256, 0.989 per candidate | measured (section 3.1) |
|
||||
| The same at class v4's instruction count (`mx8+shl2304x3`: 16 sub-blocks of 144, three passes, 55,296 shadow instructions per hash) | 224 of 256 seeds, 0.935 per candidate | measured |
|
||||
| The verifier on the sound forms, cold warp on core 40 with core 88 loaded (the ladder's method) | shl4096x1 8.28 to 8.55 ms; shl2304x3 8.44 to 8.82; class v4's shape 8.33 to 8.63 on the same core in the same minutes; all under the 10 ms gate | measured (section 3.2) |
|
||||
| The per-load prototype's acceptance under a drawn era | 0 of 256 seeds on every per-load form: 5,536 of 7,862 bias rejections name index bit 26 or 27 "set in 0 or 16,384 of 16,384", the era WINDOW's fixed top bits, an instrument fault; so 20.2a-close's "1.4 percent accepted, 42 of 64 seeds exhaust" (run across drawn eras) measured the instrument, not the construction | measured; a correction for the research file (section 3.3) |
|
||||
| The two packs for the card row | `mx8_shl4096x1` (id 75ca9547da21b200) and `mx8_shl2304x3` (id bbfdfc1dcdda0b46), OVERALL PASS, in the hash lane's PC 1 job after the AMD grid (about 12:45 UK) | exported; the card row owed |
|
||||
|
||||
**The ranked list of what v6 should add beyond the four** (section 4 has every column):
|
||||
|
||||
| Rank | Layer | What it does to the chip | What it costs the cards (5090 / 5070 Ti / M5 Max) | Status |
|
||||
|---|---|---|---|---|
|
||||
| 1 | **Layer 5: the shadow placed per load, one pass of a long sub-block** (the capex lever: the chip's core must sit inside every read's dependency, so controller, lanes and PHY share one N5-class die or an interposer) | energy edge unchanged (`k` is `k` whichever die the core sits on); project cost about USD 30 M to about 60 M, the break-even market cap about USD 100 M to about 200 M (the mission lane's model, modelled); capex per MH/s 3.0 to 4.3 USD (modelled) | 5090: the 16 x 27 form measured 13 to 14 W UNDER the whole block at the same instruction count (448 against 462 W unlocked; 283 against 296 at the 1,300 lock), rate within 1.2 percent; the 256 x 1 form's row in today's PC 1 job / no row, the 4070's 30 W premium at its tune point as the proxy / the 16 x 27 form -0.5 percent of rate measured; the 256 x 1 form's Metal footprint OWED | acceptance measured today (0.927 per candidate, P(exhaust at 256) about 4 x 10^-9); the sub-version 3 dataflow rule in execution order is the fix that brings it toward v4's 0.68 (gate plan, section 2.1) |
|
||||
| 2 | **Layer 6: register-file width drawn per era (8 to 32 registers per lane)**, the link tax on layer 5 | with layer 5, the lane state crossing the controller twice per read grows from 64 B to 128 to 256 B: 2.2 to 9 TB/s of die-to-die traffic at the 5090's read rate, past any one-stack interposer, which closes the "or an interposer" branch and forces the single N5 die (modelled); alone, nothing | 0 rate on every card while latency-bound (a GPU lane holds up to 255 registers; 7,262 lanes x 256 B is 1.9 MB against the 5090's 43 MB of register file, approximate); the verifier's register-major arrays 4x (unmeasured, under 0.1 ms by the op law); no pack form today (the register count is a generator constant) | modelled; the pack form is a generator change with its own census (gate plan) |
|
||||
| 3 | **Layer 7: warp-uniform data-dependent block selection** (which of B shadow sub-blocks runs next is chosen by a warp-reduced register value, uniform across the 32 lanes, so no divergence) | nothing for the GPU-like chip (a sequencer already); an FPGA overlay or a fixed pipeline must hold all B blocks for one block's throughput: B x the shadow's LUT area (approximate); shortens a per-epoch bitstream's worth | one uniform indirect branch per iteration: about 0 (the `sel` register already does this for the immediates); verifier 0 | modelled; a generator change behind a pack (gate plan); rank 3 because it moves the FPGA lane only |
|
||||
| 4 | **The reserve ordered by hardware orthogonality** (layer 3 as it stands, with the order fixed: shuffle-crossbar families, then byte-permute, then popcount and priority encoder, the int8 tile last) | a chip pre-wires every family for about USD 4 of N5 (modelled); the order makes the first unlocks the ones a 12-op datapath lacks most | 0 at 4 points (measured step costs under 1 percent of ALU time on every vendor) | an ordering rule inside layer 3, not a new layer; the history's addition 6 |
|
||||
|
||||
Rejected with the number, each in section 2: per-lane data-dependent branches (divergence costs the card, a chip nothing); reads tied to the shard proof per block (a refresh per block is 0.3 to 1 W on a chip, 1.3 percent of a 4090's hash time); randomised memory topology (a chip's address decoder permutes its lines for nothing; the stride and interleave are already drawn); the VRAM-size ratchet as a lever (a chip buys 24 to 32 GB that the 8, 12 and 16 GB tiers cannot: it retires cards first); proof-carrying hashes sampled by the pool (the chip holds everything the witness proves); prover-gated eligibility (proving is 1.6 kW network-wide at any hash rate, 0.7 percent of the hash's energy at 100 GH/s); time-locked parameter commitments beyond the era VDF (the drawn band is firmware; the 2-hour lead already denies the fixed chip 180 days); a fraction of reads derived from the cache (the 5090 loses about 30 percent of rate, the chip 7 percent of energy); row-straddling reads (the w64 regime, 47 percent of the 5090's rate); a refresh per block (dead by arithmetic, the research file's row 7).
|
||||
|
||||
Per tier, in one line each: a home miner on any card sees no change from anything here today (nothing ships; the devnet pays nothing); the 5090 tier's one number is that the per-load placement costs it LESS than class v4's whole block at the same work (13 to 14 W measured on the 16 x 27 form, the 256 x 1 form's row due about 12:45 UK); the 5070 Ti has no measured row in this lane (the 4070's rows are the proxy, approximate); the Apple tier's open question is the inline footprint of a 4,096-line block per iteration (the 1,024-line block cost the M5 Max 17 percent on 6 October, measured), which decides whether rank 1 needs a block-shape cap for Apple; a pool user sees nothing; a node verifies the per-load forms in the same 8.3 to 8.8 ms as class v4 (measured); a chip maker sees its project forced onto one advanced die by rank 1 and its interposer escape closed by rank 2.
|
||||
|
||||
## 1. The frame, and what a candidate must do
|
||||
|
||||
| Term | Value, 5090 at the 1,300 MHz knee | Label | Source |
|
||||
|---|---|---|---|
|
||||
| `E_card`, class v3 | 1.67 microjoules (127.3 MH/s at 213.0 W; 134.6 at 223.3 on the efficiency pass) | measured | research file 20.3 and the status file's efficiency pass |
|
||||
| `E_mem`, the `f = 1` GDDR7 chip | 0.466 microjoules (16 devices, 166 MH/s at 78 W); one HBM3 stack 0.321 | modelled | chip-model-v3 5.4 |
|
||||
| `F`, the class v4 shadow's premium | 0.652 microjoules (82.8 W over 126.9 M hashes x 102,100 ops: 6.4 pJ per counted op) | measured | research file 20.3 |
|
||||
| The edge at zero premium | 3.6x (GDDR7), 5.2x (one HBM3 stack) | measured card, modelled chip | section 2 of the research file |
|
||||
| The edge with the shadow | 2.1x at `k = 1`, 2.9x at `k = 0.5`, 3.5x at `k = 0.3`; the honest `k` band for an ALU-shaped core 0.3 to 0.8 | modelled on measured rows | 20.4 |
|
||||
| The chip's capex | USD 470 of memory, controller and board per 166 MH/s: 2.8 USD per MH/s; plus the shadow core USD 25 to 40 (3.0 to 3.1); plus an interposer USD 200 (4.3); a 5090 at MSRP 14.7, at the 2026 street price about 29 | modelled; the card price measured | 16.1 |
|
||||
| The project cost and the break-even cap | a 28 nm controller USD 5 M (cap about 17 M); plus an N5 shadow core USD 30 M (cap about 100 M); the core forced onto the controller's die or an interposer USD 60 M (cap about 200 M) | modelled (the mission lane's model, s = 0.30) | 16.2 |
|
||||
|
||||
The four doors, and the one each candidate must walk through:
|
||||
|
||||
1. **Raise `k`.** Measured on the 5090 (15.1a): the int32 ALU op 6.2 to 11.3 pJ against a 5 nm SIMD array's 2 to 5 (k 0.3 to 0.8); the shuffle 29 to 56 pJ against a crossbar's about 20 (k 0.4 to 0.7, and the card pays 5x the add per op); the int8 tile 0.8 to 4 pJ per MAC against an array's 0.04 to 0.4 (k 0.03 to 0.3); an L2 hit 1.4 to 2.4 nJ against on-die SRAM's 0.2 to 0.5 (k 0.1 to 0.3). Nothing reads above 1. A candidate that claims to raise `k` must name the block and the measured GPU cost per op it rests on.
|
||||
2. **Raise the capex or the project.** The hash's dataset is a card's worth of DRAM and its work a fraction of a card's logic, so per-unit capex cannot pass about 4.3 USD per MH/s (16.1); the project cost is the lever that moves the break-even cap, and the only mechanism found for it is forcing the shadow core into every read's dependency (16.2). A candidate here is priced by which die it forces.
|
||||
3. **Shorten the useful life.** Layers 1 and 3 kill fixed silicon at the first draw outside its wired value; a GPU-like chip's life is its memory's and its node's. A candidate here must move the GPU-like chip, or it is layer 1 again.
|
||||
4. **Lower the honest card's cost at the same `F`.** The operating point (the knee lock) is the miner's lever, not the protocol's; a protocol lever here is a shape that runs cheaper per instruction on the card (the 16-instruction block effect, 13 to 14 W measured) at the same chip cost.
|
||||
|
||||
## 2. The candidates
|
||||
|
||||
Each: the paragraph, the known-failed test as a harness run, the chip row, the verdict. The harness names: `v6inv-census.sh` is `/srv/builds/v6-invention-census.sh` on build-1 (a copy sits in this lane's scratch and lands under `tools/attack/v6-invention/` with the 09:00 report), the counter-asic-4 crate's `igneum-pow accept --class <form>` over seeds `igneum-v6inv/<i>`; the F8 census is `tools/attack/f8-uniform` (`attack-f8 warps`, master); the chip row is the model's arithmetic with the GPU side measured where a pack ran.
|
||||
|
||||
### 2.1 Layer 5: the shadow placed per load, one pass of a long sub-block (KEEP, rank 1)
|
||||
|
||||
The class v4 shadow runs 256 instructions 27 times after instruction 63 of every iteration, where the next iteration's 64 base instructions and 16 loads stand between the block and every load, and a chip may run it on a second die with 64 B of lane state crossing once per iteration (140 GB/s at the 5090's read rate, a PCB link; 16.2). Placed inside every read's dependency the same work makes the lane state cross twice per read, 2.2 TB/s, an interposer-class link or one N5 die carrying controller, lanes and PHY, which the mission lane's model prices at a project of about USD 60 M against 30 M and a break-even cap of about 200 M against 100 M. The 16 x 27 form (16 sub-blocks of 16, each iterated 27 times) was built on 7 October and closed the same night: 27 passes of a 16-instruction map right before a load collapses or biases the load's address register before any base instruction can re-randomise it, and the acceptance rule in execution order refused it. The sound form named there and never drawn is one pass of a long segment per load: 16 sub-blocks of 432 instructions, each run once, the same 6,912 instructions per iteration. The experimental class caps the per-load block at 4,096 instructions, so today's census takes the two forms inside the cap that bracket it: `mx8+shl4096x1` (16 x 256, one pass, 59 percent of class v4's work per hash) and `mx8+shl2304x3` (16 x 144, three passes, class v4's exact count), and the constant-work ladder between them (16 x 256 x 1, 32 x 128 x 2 ... 16 x 16 x 16) that reads how the acceptance rate depends on the sub-block length against the pass count. The 432 x 1 form itself needs the cap raised, a one-line change in a research-only parser, which this lane does not make this week; its number is bracketed by the 256 x 1 and 144 x 3 rows and the ladder's flatness between them.
|
||||
|
||||
Known-failed test, as a harness run: `ERA=none SEEDS=256 /srv/builds/v6-invention-census.sh` on build-1 under `lease pool 48`. Fail: a form whose per-candidate rejection is 0.98 or above (P(exhaust) at the 256-attempt cap above 0.5 percent, an epoch without a program every few months). The 16 x 27 form reads 0.989 and fails (section 3.1). Pass: a form under 0.95 (P(exhaust) under 2 x 10^-6). The 256 x 1 form reads 0.927 and passes; so does every form with a sub-block of 36 instructions or longer (0.927 to 0.949). The second known-failed case is the instrument's own: `ERA=era` on the same seeds reads 0 of 256 accepted on every per-load form, with the window's fixed top bits named as biased index bits (section 3.3); the fixed instrument (bits at or above `28 - k_off_s` excluded from the value-level test) must accept per-load forms under drawn eras at the no-era rate within the binomial band, and still refuse the per-load record of 7 October (candidate 0 of the first export, 1,482 duplicate lanes).
|
||||
|
||||
Chip row:
|
||||
|
||||
| Column | Value | Label |
|
||||
|---|---|---|
|
||||
| A fixed-function chip's `k` | unchanged (the work is the same ALU mix); its capex: the controller cannot be a 28 nm part with the core elsewhere, so the project moves from USD 5 M (no core) or 30 M (a core on its own die) to about 60 M (one N5-class die or a 2.5D package); break-even cap about USD 200 M in years 1 to 2 (s = 0.30) against about 100 M | modelled (16.2, the mission lane's N3 single-die row; a GDDR7 PHY on N5 is unpriced) |
|
||||
| A GPU-like chip's per-joule edge | unchanged: 2.1x at `k = 1`, 3.5x at `k = 0.3` at the knee; its capex per MH/s 3.0 to 4.3 USD against 2.8 | modelled |
|
||||
| RTX 5090 | the 16 x 27 v2 export: 135.90 MH/s at 448.3 W unlocked against the whole block's 137.51 at 462.2 (the premium 137 against 151 W, -14 W); at the 1,300 lock 126.04 at 282.9 against 126.93 at 295.8 (-13 W); the 256 x 1 and 144 x 3 forms in today's PC 1 job (the hash lane, after the AMD grid, about 12:45 UK) | measured (research file 20.3); the sound forms' rows owed |
|
||||
| RTX 5070 Ti | no row (no card in this lane); the 4070's class v4 premium at its tune point, 30 W for no rate, less the block effect, is the proxy | approximate |
|
||||
| Apple M5 Max | the 16 x 27 v2 export 26.88 MH/s against 27.01 (-0.5 percent, Metal packbench, 7 October); the 256 x 1 form's inline text is 4,096 shadow lines per iteration where the 1,024-line block cost the M5 Max 17 percent (6 October, measured), so its footprint is the open Apple number: OWED (a Mac measurement under the measure lock, which this lane does not run; the hash lane's or the shipper's Metal row) | measured for 16 x 27; the sound form's row owed |
|
||||
| The verifier | 8.28 to 8.55 ms cold with the sibling loaded (256 x 1), 8.44 to 8.82 (144 x 3), against class v4's 8.33 to 8.63 on the same core in the same minutes; the acceptance's dynamic test 35 ms per candidate (1,111 ms for 32), 13.7 candidates per seed on average: about 0.5 s of one core per epoch | measured (section 3.2) |
|
||||
| The acceptance | 0.927 per candidate (256 x 1), P(256 consecutive rejections) 0.927^256 about 4 x 10^-9 per seed; class v4 sub-version 3 reads 0.681 and 2 x 10^-43; the gap is the missing dataflow rule (the per-load class is not the class v4 shape, so (a'), (c') and (c'') do not run on it; the value-level bias test catches the same population: 1,563 of 2,329 bias rejections name index bit 0 at a one-count near 4,096 or 12,288 of 16,384, the product's low-bit law) | measured (section 3.1) |
|
||||
|
||||
Verdict: KEEP as layer 5, the first thing v6 adds beyond the four, because it is the only mechanism found that moves the project cost, it costs the 5090 less than class v4's own block (measured on the 16 x 27 form; the sound form's row today), and its acceptance is now a measured 0.927 with a named fix (the sub-version 3 dataflow fixpoint run over the real execution order, base and sub-blocks interleaved, as the generator's draw rule) that the research file's 20.2 already asked for. What it does not do: move the energy identity by one joule. The founder's "useless as soon as it dropped" is layer 1's and 3's sentence; layer 5's sentence is "the chip that can be built costs twice as much to start".
|
||||
|
||||
### 2.2 Layer 6: the register-file width drawn per era, the link tax on layer 5 (KEEP, rank 2)
|
||||
|
||||
The hash runs on 8 registers per lane, a prototype value to be fixed at gate 1 (spec 1.4). The lane state a chip must carry is those 8 words plus the nonce and counter, 64 B, which is why the chip's 1,172 lanes are 73 KB of SRAM and why, under layer 5, the per-read crossing is 128 B at 17.5 G reads per second, 2.2 TB/s: an interposer carries that (a one-stack HBM package moves about 0.8 to 1.2 TB/s of memory traffic and a die-to-die link of a few TB/s is a 2.5D product; approximate, from memory), so the chip has an escape at USD 200 of package instead of one die. Draw the register count per era from {8, 16, 32} (the acceptance rule's part (b) over every register; the program length scaled so that every register is written, or registers above 8 initialised and read by the shadow alone) and the crossing is 128 to 256 B per lane per read: 4.5 to 9 TB/s, past the interposer class, so the single die is forced and the project's USD 60 M row has no cheaper branch. A GPU pays nothing in rate while latency-bound: a CUDA lane holds up to 255 registers, the 5090's 7,262 lanes in flight at 256 B are 1.9 MB against about 43 MB of register file (170 SMs x 256 KB; approximate), and occupancy at 32 live registers plus the kernel's temporaries fits the 64K-register SM at full residency (approximate, unmeasured). The verifier's register-major arrays grow 4x (4 KB per warp) and the interpreter's cost per op does not move.
|
||||
|
||||
Known-failed test, as a harness run: the generator with `REGISTERS` as a class field (a research-only change behind a pack name, `mx8+r32`), then `v6inv-census.sh` over the per-load forms at 8, 16 and 32 registers. Fail: the 32-register form's per-candidate rejection above the 8-register form's by more than the binomial band (more registers, more cold registers, more (b) rejections unless the program length scales). Pass: rejection at or under the 8-register form's; the F8 census at 2^24 on 64 seeds within 1.2x of the window model (the top 0.1 percent of items); the cold verify on core 40 with core 88 loaded under 10 ms. Then the card: one pack per register count on the 5090, rate within 1 percent of the 8-register pack at both states (the occupancy claim measured, not argued).
|
||||
|
||||
Chip row:
|
||||
|
||||
| Column | Value | Label |
|
||||
|---|---|---|
|
||||
| A fixed-function chip | with layer 5: the lane state per read 128 to 256 B, 4.5 to 9 TB/s of die-to-die traffic at the 5090's read rate; the interposer branch (USD 200 of package) closed, the single N5-class die forced; the project about USD 60 M either way, but with no cheaper escape; alone (without layer 5): nothing, the state crosses once per iteration | modelled, the link figures approximate |
|
||||
| A GPU-like chip's per-joule edge | unchanged; its lane SRAM 73 KB to 300 KB (nothing) | modelled |
|
||||
| RTX 5090 / 5070 Ti / M5 Max | 0 rate while latency-bound (approximate: the occupancy arithmetic above; a measurement is the pack); watts: the same `F` (the same ops) | approximate until the pack runs |
|
||||
| The verifier | 4x the register arrays per warp (4 KB); cost per op unchanged (0.1 ns per lane-instruction, the shadow's law) | modelled |
|
||||
| The acceptance | part (b) over 16 or 32 registers needs the base program to write every register: at 64 instructions over 32 registers about 13 percent of registers are never written (approximate, e^(-64 x 0.75 / 32)), so either the base length scales with the register count (the verifier's 10 ms gate holds to about 330,000 ops) or the extra registers belong to the shadow alone and part (b) reads the base's 8 | modelled; the census decides |
|
||||
|
||||
Verdict: KEEP as layer 6, conditional on layer 5 (alone it moves nothing). Its value is one sentence in the chip's project plan: no interposer saves the second die.
|
||||
|
||||
### 2.3 Layer 7: warp-uniform data-dependent block selection (KEEP, rank 3, small)
|
||||
|
||||
A program whose control flow depends on the data it reads is the brief's first candidate. Per-lane branches are dead on arrival: a divergent branch costs a GPU warp both paths and a chip with per-lane sequencers nothing (the history's "placed nowhere" table; RandomX's one predictable branch targets speculative CPUs, which Igneum does not have). The form that survives is warp-uniform: at the end of each iteration a value reduced across the 32 lanes by shuffles (xor-fold of `r0`, say, which costs 5 shuffles) selects which of B drawn sub-blocks runs next, the same block for every lane of the warp, so the GPU takes one uniform indirect branch per iteration (as `sel` already takes one per iteration for the immediates) and the FPGA overlay or the fixed pipeline must hold all B blocks and pay B times the shadow's area for one block's throughput. For the GPU-like chip, a sequencer that already runs the hour's program, it is one more jump. What it buys: the per-epoch bitstream (the FPGA lane, history addition 5) holds B blocks instead of one, so a mid-size part's compile (42 to 160 minutes, PRflow, claimed in spec 1.13.1) carries B times the logic; at B = 4 a part that fitted one block does not fit, and at B = 8 the overlay must time-multiplex. Nothing in the energy identity moves. The acceptance must run every reachable path (B blocks per iteration, each judged by (a') in its own order) and the uniformity census must read the selection's bias (a selection that favours one block is a block that runs more).
|
||||
|
||||
Known-failed test, as a harness run: a research-only class `mx8+sh256x27+sel<B>` (the generator draws B blocks, the interpreter selects per iteration from the warp-folded `r0`), then `igneum-pow accept` over 256 seeds with every path judged, and `attack-f8 warps` at 2^24 on 64 seeds. Fail: the block-selection histogram over the 2^24 nonces outside 6 sigma of uniform (a plant: select from lane 0's `r0` bit 0 alone, which the fold is meant to prevent), or any path's (a') verdict differing from the whole-program verdict. Pass: within the band, 60 of 64 seeds under 1.2x on the hot-set test, as class v4 reads.
|
||||
|
||||
Chip row:
|
||||
|
||||
| Column | Value | Label |
|
||||
|---|---|---|
|
||||
| A fixed-function chip or an FPGA overlay | B x the shadow's logic for one block's throughput, or time-multiplexing at 1/B the rate; a bitstream compiled per epoch carries B blocks | approximate (LUT area scales with the straight-line block; no FPGA row exists in the repo) |
|
||||
| A GPU-like chip | nothing: one jump per iteration on a sequencer | modelled |
|
||||
| RTX 5090 / 5070 Ti / M5 Max | about 0: one uniform branch per iteration, 5 shuffles per iteration for the fold (5 x 8 = 40 shuffles per hash at 29 to 56 pJ: 0.002 microjoules, 0.3 percent of `F`); the compile-ahead carries B x 256 instructions of text (B = 4: the 1,024-line footprint that cost the M5 Max 17 percent on 6 October) | modelled on measured per-op costs; the Apple footprint is the cap on B |
|
||||
| The verifier | B x the acceptance's dynamic test per candidate (every path); the hash's cost unchanged | modelled |
|
||||
|
||||
Verdict: KEEP, rank 3, with B capped by the Apple footprint (B = 2 or 4 at the 256-instruction block, or B = 4 at 64-instruction blocks, which the 6 October measurement says run 2.5 to 3.5 percent faster anyway). It is the only candidate that moves the FPGA lane, which the history ranks as the first adversary of a per-hour program (Lyra2REv2, X16R) and which no measured row in the repo has priced (the HBM FPGA row is 0.30x to 0.39x of a 5090 per watt, chip-model-v3 5.3, the soft-overlay case unmeasured).
|
||||
|
||||
### 2.4 The reserve ordered by hardware orthogonality (KEEP as an ordering rule inside layer 3)
|
||||
|
||||
Layer 3 unlocks reserve families by height and rotates after exhaustion. The order is Open in spec 1.13.2 except R1. The history's addition 6 said: families that force a full 32-bit datapath per lane first, the int8 tile last. Today's measured rows (research file 15.1a; the research lane's layer 3 table) sharpen it: a shuffle crossbar is the one block where the GPU's cost per op is highest (29 to 56 pJ) and a chip's is near it (about 20 pJ, approximate), so `shfla` (lane plus delta, a second crossbar form) is the family a 12-op chip lacks most and gains least on; byte permute and popcount next (small adders a chip adds for 0.1 pJ, but a datapath without them loses 4 points of the mix); the int8 tile last (k 0.03 to 0.3: a chip's MAC array is cheaper than the GPU's tensor core, so the tile is kept for datapath diversity and never for joules). The chip row is layer 3's: about USD 4 of N5 pre-wires all eight. Cost to the cards at 4 points: under 1 percent of ALU time on every vendor (measured step costs: shfla 1.91x on Apple, 1.53x NVIDIA, 0.75 to 0.84 AMD). Known-failed test: the layer 3 gate's own (a kernel built without the live family refused at packcheck; the fast-time harness crossing one family epoch with a stale miner, 0 accepted blocks after it). Verdict: not a new layer; an ordering rule, stated so the synthesis fixes it at genesis.
|
||||
|
||||
### 2.5 Data-dependent program graphs, per-lane (REJECT)
|
||||
|
||||
The brief's form: the program's control flow drawn from the data it reads, per lane. A GPU warp executes a divergent branch as both paths with lanes masked, so a branch taken by half the lanes doubles the ALU work of that span; a chip with a sequencer per lane pays the taken path only. Number: a shadow of 55,296 instructions per hash with one two-way branch per 64 instructions at 50 percent divergence costs the card up to 2x the shadow's premium (165 W instead of 83 at the knee on the 5090, modelled on the measured 6.4 pJ per op) for a chip cost of 1x; `k` on the branched work falls to 0.15 to 0.4. Costs GPUs more than chips. The warp-uniform form (2.3) is what survives.
|
||||
|
||||
### 2.6 Latency-bound reads tied to the shard proof (REJECT)
|
||||
|
||||
The hash's reads sampled from the state the miner is proving: class v5 already keys every item to a leaf of the execution state at the epoch's cut and refreshes per epoch (spec 1.8.6; proof of following). Tying the reads to the segment being proved means a refresh per block (every second) from the touched leaves. The research file's row 7 priced the refresh as a cost: a 1 GiB rebuild is 157 G ops, 13.4 ms on a 5090 and 32 ms on a 4090 (measured), 0.16 to 0.5 J on a chip core (1 to 3 pJ per op, approximate); per block that is 0.3 to 1 W against 78 W of chip hashing (0.4 to 1.3 percent) and 1.3 to 3.2 percent of a GPU's hash time (the rebuild stalls the hash on the card; the chip's rebuild runs on its core beside the memory). A delta refresh (only the touched leaves, a few KB) costs both sides nothing. Either way the GPU pays more or equal. What the tie would buy is liveness (a chip must follow the chain per block, not per epoch), which class v5's per-epoch refresh already gives at the WAN line of 2a.2. Number: GPU 1.3 to 3.2 percent of rate against a chip's 0.4 to 1.3 percent of energy. Rejected.
|
||||
|
||||
### 2.7 Randomised memory topology per era (REJECT)
|
||||
|
||||
The dataset's address map and stride family drawn per era: class v3 draws the stride multiplier `M`, the rotation `R` and the interleave `pos` per era already (spec 1.13.1, Counter ASIC 2.0 layers 4 and 8, decided IN at a six-era hash-rate spread of 1.3 percent on the 5090, 3.2 on the 9070 XT, 0.8 on the M5 Max, measured). The plan said then what still holds: a chip whose address decoder can permute its address lines pays nothing. Drawing a richer family (a per-era permutation polynomial over bank and row bits, a drawn item size, a drawn line interleave across devices) costs the chip's decoder a few hundred gates and costs the honest card whatever the mapping does to its own DRAM's bank parallelism: a mapping that concentrates consecutive dependent reads into one bank group hurts the side with fewer lanes in flight, which is the chip (1,172 against 7,262), but the chip adds lanes at 64 B each (lane state is free, chip-model-v3 5.5), so the asymmetry closes at no cost. The one topology lever that would have moved the chip, the hot region above the window model, was read by adv-cache-2 as the diffuse era-stride excess (a product's low bits placed at address bit `R`; 8 of 27 drawn-era programs over 1.2x), which is a FAULT the next class's value-level test removes, not a lever to keep. Number: 0 to the chip, 0 to 3.2 percent to the cards. Rejected; the existing draws stand.
|
||||
|
||||
### 2.8 VRAM-size ratchet (REJECT as a lever; layer 2's floor stands)
|
||||
|
||||
A floor that rises with chain state by rule is layer 2. The ratchet form (the floor tracking the modal miner's VRAM minus the prover footprint, or rising on a calendar faster than the schedule) was read against the card-lifetime table (`docs/analysis/card-lifetime-2026-10-05.md`, option (b) steps): the 4 GB tier ends at the 4 GiB step, 8 GB at 8 GiB, 12 and 16 GB at the 16 GiB step; a chip holds 24 GB (one HBM3 stack, about USD 200, modelled) or 32 GB (the 5090's own 16 devices, USD 320), so every step retires a card tier before it touches the chip, and at 32 GiB and beyond the chip adds devices and its activate-bound rate RISES with the bank count (chip-model-v3 5.7, row "dataset size": "not a lever against this chip"). Number: at the 16 GiB step the 8, 12 and 16 GB tiers are out (3 of 6 card tiers) and the chip's energy per hash moves 0. Rejected as a lever; layer 2's rule (the schedule as the floor, the state above it, a ceiling at the next cache doubling) is kept exactly as the synthesis writes it, with its honest line that it retires cards before chips.
|
||||
|
||||
### 2.9 Proof-carrying hashes sampled by the pool (REJECT)
|
||||
|
||||
A fraction of hashes carries a verifiable execution witness. Three witness forms were read. (i) The hash's own 128 item values: the stored-dataset chip has every item; the recompute chip derives them; cost 0 to both, 512 B per share on the wire. (ii) A Merkle witness of the state leaves under the window's root: the chip's node has it (one node serves a farm, class-v5 2a.2); cost 0 to both. (iii) A witness that the item was DERIVED (a transcript of the 8 dependent cache reads and the mixer's 72 applications): a stored-dataset chip cannot produce it without the cache and the mixer core, so this form forces the `f = 0` chip's silicon (the 256 MiB SRAM mirror, USD 46 of die and an N5 project) onto the `f = 1` chip for the sampled fraction `g`; but the honest GPU must produce the same transcript, and deriving an item on the card is 8 dependent 64-byte cache reads at the mixer's 9,360 ops (the inline kernel measured 4.8x slower than the honest kernel on the M5 Max, spec 1.8.5), so at `g = 1/128` (one item per hash) the card pays about 4 percent of its rate and at `g = 1/16` about 30 percent; the chip derives on an SRAM-resident cache at 6.3 nJ per item (modelled) for 7 percent of its energy at `g = 1/16`. Number: GPU 4 to 30 percent of rate against the chip's 1 to 7 percent of energy. Rejected on form (iii); forms (i) and (ii) force nothing.
|
||||
|
||||
### 2.10 Prover-gated eligibility (REJECT)
|
||||
|
||||
The block's eligibility tied to the miner's proving (a key must have proved its share of segments in the last window to claim a block), so a chip farm must carry provers. The bound is the gas bound the research file's section 7 found: the chain needs 2 shards per block at the v1 budget, about 1.6 kW of 5090 proving network-wide at 1 block per second (measured prover rows), independent of the hash rate. Against the hash: at 1 GH/s the hash draws 2.4 kW (2.4 microjoules per hash, measured), so proving is 67 percent of it; at 100 GH/s 0.7 percent; at 10 TH/s 0.007 percent. A chip farm at share `s` must prove share `s` of 1.6 kW: six 5090s per farm at any scale, which is the node it already runs. Redundant proving (each segment proved by `m` provers) raises the forcing `m` times and is the useful-work gaming the history records (Aleo, Boundless). Number: at mainnet scale the forcing is under 0.01 percent of the chip's energy; the honest card already proves. Rejected; the 80/20 split stands.
|
||||
|
||||
### 2.11 Time-locked parameter commitments (REJECT beyond the era VDF)
|
||||
|
||||
An era's parameters committed under a VDF so a chip cannot be built ahead: the era VDF of 7 October (`docs/analysis/era-vdf-2026-10-07.md`) already makes the era draw's input unknowable for 517 s on the fastest prover measured (chiavdf's GMP path, 208,800 squarings per second, against the production T of 108 million) and the era lead is 2 hours (`pow_era_lead`), so a chip taped out against era `n` knows era `n + 1`'s draw 2 hours before it runs, against a 5-month (Bitmain) to 13-month (a startup) design cycle (the history's lesson 5, Vorick). Lengthening the delay or the commitment changes nothing a chip can use: the GPU-like chip holds the whole drawn band as firmware (the synthesis's section 7), and the fixed-function chip is dead at the first draw outside its wired value whether it learns the draw 2 hours or 2 days ahead. The one party for whom 2 hours matters is the FPGA fleet (a bitstream compiles in 42 to 160 minutes on a mid-size part, claimed), and layer 7 (2.3) and the epoch length (spec 1.13.1, the 600 s floor) are the levers for it, not the lock. Cost of a longer lock: one honest node core for the VDF's hour per era (today) rising linearly with T; the 2019-class verify gate already missed by 2.2x (26 ms against 10, measured, proxy). Number: 0 to the chip at any delay above 2 hours; the honest node's core-hours rise with T. Rejected.
|
||||
|
||||
### 2.12 A fraction of reads derived from the cache in the hash (REJECT)
|
||||
|
||||
The brief's spirit of "tie the hash to what the chip must hold": a fraction `g` of the 128 reads per hash derived on the fly from the 256 MiB cache (8 dependent cache reads and 72 mixer applications) instead of read from the dataset, so the stored-dataset chip must carry the recompute chip's cache and core for that fraction. This is 2.9 form (iii) without the witness and the same arithmetic: the card's derived read is 8 dependent DRAM reads (the cache does not fit L2 at 256 MiB, and the cache doubling keeps it so), so at `g = 1/16` the card's dependent-read count per hash rises from 128 to 184 and its rate falls about 30 percent (modelled on the latency-bound rule; the inline kernel's 4.8x at `g = 1` is the measured anchor); the chip with the cache on die derives at 6.3 nJ per item (4.0 nJ of SRAM reads, 2.3 of mixer; modelled) for 0.466 to 0.50 microjoules per hash (+7 percent) and buys the USD 46 mirror and the N5 project it already needs for the shadow core. Number: GPU -30 percent of rate at `g = 1/16`, chip +7 percent of energy and +USD 46 of die. Rejected.
|
||||
|
||||
### 2.13 Row-straddling and double-activation reads (REJECT)
|
||||
|
||||
The chip and the card share the DRAM's physics (the research file's section 5: the same tRC, the same activate window, the same 32-byte atom). A read that opens two rows (an item straddling a row boundary, or two independent 32-byte sectors per read) costs the chip's memory +0.9 nJ per read (a second 909 pJ activation; modelled) and the card +1 sector of traffic, which at 128 reads per hash is the w64 regime (64 B per read): the 5090 fell to 71.9 MH/s, bandwidth-bound, 47 percent of its rate (measured, read-width). Number: chip +45 percent of `E_mem` (0.466 to 0.58), card -47 percent of rate and about +9 percent of energy per hash on the memory side alone. The edge moves from 3.6x to about 3.1x at the knee (modelled) at the price of half the card's rate. Rejected.
|
||||
|
||||
### 2.14 Per-era lane-state and scratch draws (REJECT)
|
||||
|
||||
Per-lane live state across the hash (a scratch with read-modify-write) was measured out in Counter ASIC 2.0 (layer 3: the recompute chip's gain at every share 2.4x, the cards -12 to -48 percent) and bounded in `docs/analysis/scratch-soundness.md` (the live state sits in a chip's SRAM at under 5 percent of its mirror). A drawn scratch size per era draws from a dead family. Number: the cards -12 to -48 percent of rate (measured), the chip +picojoules per access. Rejected. (The register-file width of 2.2 is the live form of this idea: state that costs the GPU nothing because its register file is already there, and costs the chip a link, not an SRAM.)
|
||||
|
||||
### 2.15 A refresh per block (REJECT; the research file's row 7)
|
||||
|
||||
Dead by arithmetic: a 1 GiB rebuild is 0.16 to 0.5 J on a chip core and 13 to 32 ms of a card's hash time; per block that is 0.4 to 1.3 percent of the chip's energy and 1.3 to 3.2 percent of the card's rate. The refresh cadence is a liveness tool (class v5's proof of following), not an energy lever.
|
||||
|
||||
## 3. The measured rows (igneum-build-1, 8 October 2026, 11:0x to 11:2x UK)
|
||||
|
||||
The crate: `igneum-pow` of branch `counter-asic-4` at 5984ffab, built on build-1 through `tools/build-remote.sh --no-fetch --box 1` from the detached worktree `igneum-wt-v6-inv-ca4` (RESULT rc=0, 11 s, sccache); the binary `/srv/builds/igneum-wt-v6-inv-ca4/igneum-pow/target/release/igneum-pow`. Every run under `/srv/builds/_bin/lease` (pool 48 at class measure for the censuses, `cores 40,88` for the benches), owner `class-v6-invention`; the box at load 15 to 24 on 96 threads from other lanes throughout; logs under `/srv/builds/v6-invention/` (`census-none.tsv`, `census-era.tsv`, `logs/<era>-<form>-<seed>.log`, `census-run-*.log`), copied into `docs/analysis/class-v6/logs/` with the 09:00 report.
|
||||
|
||||
### 3.1 The acceptance census (`v6inv-census.sh`, 256 seeds `igneum-v6inv/0..255`, every candidate's verdict through `igneum-pow accept --class <form>`, the class's own 32-attempt cap)
|
||||
|
||||
No era (`ERA=none`; 2,816 rows in 80 s on 48 cores):
|
||||
|
||||
| Form (sub-blocks x length x passes) | Shadow instructions per iteration | Seeds accepted of 256 | Seeds exhausting 32 attempts | Candidates | Rejection per candidate | Mean accepted attempt | First failing part, the top four |
|
||||
|---|---|---|---|---|---|---|---|
|
||||
| `mx8+sh256x27` (class v4's shape, the whole block after instruction 63) | 6,912 | 256 | 0 | 268 | 0.045 | 0.05 | (a) 6, (b) 5, (c) 1 (the v2/v3 rule only: the crate's `accept` does not take the class v4 parts on this spelling, so the row is the control's shape, not sub-version 3's 0.681) |
|
||||
| `mx8+shl256x27` (16 x 16 x 27, the 7 October form) | 6,912 | 76 | 180 | 7,043 | 0.989 | 15.9 | per-load bias 6,081; (c) 545; (b) 212; (a) 129 |
|
||||
| `mx8+shl256x16` (16 x 16 x 16) | 4,096 | 69 | 187 | 7,117 | 0.990 | 15.4 | bias 6,294; (c) 406; (b) 215; (a) 133 |
|
||||
| `mx8+shl576x12` (16 x 36 x 12) | 6,912 | 215 | 41 | 3,815 | 0.944 | 10.6 | bias 3,367; (b) 98; (a) 72; (c) 63 |
|
||||
| `mx8+shl512x8` (16 x 32 x 8) | 4,096 | 209 | 47 | 4,120 | 0.949 | 11.5 | bias 3,686; (b) 106; (a) 82; (c) 37 |
|
||||
| `mx8+shl1152x6` (16 x 72 x 6) | 6,912 | 226 | 30 | 3,428 | 0.934 | 9.9 | bias 3,036; (b) 97; (a) 62; (c) 7 |
|
||||
| `mx8+shl1024x4` (16 x 64 x 4) | 4,096 | 231 | 25 | 3,487 | 0.934 | 10.6 | bias 3,097; (b) 81; (a) 73; (c) 5 |
|
||||
| `mx8+shl2304x3` (16 x 144 x 3, class v4's count) | 6,912 | 224 | 32 | 3,457 | 0.935 | 9.9 | bias 3,076; (b) 89; (a) 67; (c) 1 |
|
||||
| `mx8+shl2048x2` (16 x 128 x 2) | 4,096 | 228 | 28 | 3,423 | 0.933 | 10.1 | bias 3,041; (b) 83; (a) 65; (c) 6 |
|
||||
| **`mx8+shl4096x1` (16 x 256 x 1, the sound form inside the cap)** | 4,096 | **234** | **22** | 3,217 | **0.927** | 9.7 | bias 2,823; (b) 94; (a) 64; (c) 2 |
|
||||
| `mx8+shl4096x2` (16 x 256 x 2) | 8,192 | 233 | 23 | 3,273 | 0.929 | 9.9 | bias 2,875; (b) 95; (a) 67; (c) 3 |
|
||||
|
||||
What the ladder says: the iterated 16-instruction map is the fault (0.989 to 0.990 whatever its pass count), and from a 36-instruction sub-block up the rejection is flat at 0.927 to 0.949 whatever the pass count or the work per hash (4,096 or 6,912 or 8,192 instructions per iteration). The remaining 0.93 is not the placement: the `(c)` lane-constant and distinct rejections fall to 1 to 7 per form (they were 406 to 545 on the 16-instruction forms), and the bias rejections are the product's low-bit law at the load's source, which under class v4 the sub-version 3 dataflow rule (a') removes at the draw and which the per-load class, not being the class v4 shape, never applies. The value-level reading of the 256 x 1 form's 2,329 bias rejections: index bit 0 in 1,563 (one-counts clustered at 3,584 to 4,608 of 16,384, the 1/4 law, 680 of them; and at 11,776 to 12,288, the 3/4 complement, 212), bits 26 and 27 in 502 (one-counts 7,168 to 7,680: a mild low bias of the top address bits just outside the 6-sigma band of 384, the high bits of small products through `mulhi`, unattributed), the other 26 bits 264 in all; by site, site 0 takes 788 of 2,329 (its source is written last by the previous iteration's sub-block 15 and by the base instructions before instruction 1, where the draw's redraw covers the sub-block's last writer of the next load's source and not a product rotated into place by a later `rotl`). The named fix is one rule, the research file's own ask of 20.2: the sub-version 3 freshness fixpoint and the shared-operand rule run over the real execution order (base instruction, the load, its sub-block, the next base instructions), and a load whose source is not fresh at that point refused at the draw, which class v4 pays at 0.568 of candidates and which should bring the per-load forms from 0.93 toward 0.68.
|
||||
|
||||
The acceptance's own cost: 35 ms per per-load candidate on one box core (1,111 ms for 32 candidates; the control's v2/v3 rule 2.8 ms), so an epoch's draw at 13.7 candidates is about 0.5 s of one core; the (c'') ratio at 2^20 would add class v4's 2.8 s per chosen candidate.
|
||||
|
||||
### 3.2 The verifier (core 40 of the EPYC 9454P at nice 19, core 88 its SMT sibling held busy by a 100,000-warp class v4 bench for the whole run, killed by its pid at the end; the ladder's method; `igneum-pow bench --seed igneum-genesis --day 2026-10-03 --class <form> --warps 50`)
|
||||
|
||||
| Form | Cold, sibling loaded, warp base 0 / 4,096 / 1,000,000 (ms) | Avg of 50, loaded (ms) | Cold, core alone, earlier in the same minutes (ms) | Label |
|
||||
|---|---|---|---|---|
|
||||
| `mx8+sh256x27` (class v4's shape) | 8.63 / 8.33 / 8.33 | 8.29 | 5.90 / 6.34 / 5.24 | measured; the ladder's run 2 read 8.77 / 5.14 at load 25 on 6 October |
|
||||
| `mx8+shl4096x1` | 8.55 / 8.28 / 8.28 | 8.24 | 5.44 / 5.21 / 5.17 | measured |
|
||||
| `mx8+shl2304x3` | 8.82 / 8.54 / 8.44 | 8.43 | 5.31 / 5.13 / 5.09 | measured |
|
||||
| `mx8+shl4096x2` | not run loaded | | 5.97 / 5.33 / 5.29 | measured, alone only |
|
||||
|
||||
The per-load forms verify in class v4's time within the run's noise (the same instruction count, the same items derived, 4,096 per warp on every row). A first pass of the loaded column was discarded: its sibling run (300 warps) ended before the measured warps began, the ladder script's own known-failed case, and read the quiet-core figures; the second pass held the sibling for the whole run.
|
||||
|
||||
### 3.3 The instrument fault under drawn eras, and the correction it forces
|
||||
|
||||
The same 2,816 rows with `--era igneum-era-test/<seed mod 16>` (`ERA=era`): every per-load form 0 of 256 seeds accepted, 8,192 candidates per form, rejection 1.000; the class v4 shape 256 of 256. Of the 256 x 1 form's 7,862 bias rejections, 5,536 name index bit 26 or 27 "set in 0 of 16,384" or "set in 16,384 of 16,384" at a load site, which is the era's working-set window (spec 1.13.1: `k_off = below(3)` per site puts the site on the whole dataset, a half or a quarter by fixing the top `k` bits of the index to the drawn offset `o`); the prototype's `BiasedIndexBit` test loops bits 0 to 27 and does not exclude bits at or above `28 - k_off_s`, so under any era it refuses every program with a half- or quarter-window site, which is nearly every program. The research file's 20.2a-close ("the 16 x 27 per-load class accepts 22 of 1,621 candidates over 64 seeds, 1.4 percent; 42 of 64 seeds exhaust the chain's 32 attempts") was read across drawn eras and therefore measured the instrument on most of its rows; the no-era census above is the construction's own figure (the 16 x 27 form 0.989 per candidate, 76 of 256 seeds accepted, which still fails the test of 2.1 and keeps that form dead). Owed to the research file (the Counter ASIC coordinator): the instrument fix (skip the window bits per site) and the 20.2a-close figures re-read with it; neither is made this week by this lane, which changes no code in the crate.
|
||||
|
||||
### 3.4 The packs
|
||||
|
||||
`igneum-pow export --seed igneum-genesis --day 2026-10-03 --class <form> --out <dir>` on build-1: `mx8_shl4096x1` (attempt 7, id 75ca9547da21b200, OVERALL PASS, kernel.cu 245,267 bytes, 4,308 lines) and `mx8_shl2304x3` (attempt 8, id bbfdfc1dcdda0b46, OVERALL PASS, kernel.cu 142,010 bytes, 2,516 lines), under `/srv/builds/v6-invention/packs/`, tarred as `v6inv-perload-packs.tgz` (sha256 ca1986b7fc5fab20a643fc37151a55e01f91edbfacc6f1a22a7384ae87cc11bc). Handed to the hash lane at 11:1x UK, taken into its v6 PC 1 job (the 5090 alone, the packs beside today's class v3 x8 and x16, the two re-weighted shadow packs, and the controls `mx8-genesis` and `mx8_sh256x27`; self-test, the 2^24 fingerprint, MH/s and W unlocked and at the 1,300 MHz lock), queued after the AMD grid, publish about 12:00 UK, close about 12:45 UK. Nothing of the packs' output goes to a served page or the spec.
|
||||
|
||||
## 4. The ranked list, every column
|
||||
|
||||
| Rank | Layer | Door (section 1) | Chip: fixed-function `k` / capex | Chip: GPU-like per-joule edge | Cost: RTX 5090 | Cost: RTX 5070 Ti | Cost: Apple M5 Max | Verifier | Harness state |
|
||||
|---|---|---|---|---|---|---|---|---|---|
|
||||
| 1 | Layer 5: the shadow per load, one pass of a long sub-block | capex and project (door 2) | `k` unchanged; project about USD 60 M against 30 M, cap about 200 M against 100 M (modelled); capex 3.0 to 4.3 USD per MH/s | unchanged (2.1x at `k = 1`) | -13 to -14 W against class v4's block at the same work (16 x 27 form, measured); the sound forms' rows in today's PC 1 job | no row; the 4070's 30 W premium as the proxy (approximate) | -0.5 percent (16 x 27 form, measured); the 4,096-line footprint OWED | 8.28 to 8.82 ms loaded (measured) | acceptance 0.927 measured; the dataflow rule in execution order is the fix (gate plan) |
|
||||
| 2 | Layer 6: the register-file width drawn per era | capex (door 2), with layer 5 | closes the interposer branch: 4.5 to 9 TB/s of die-to-die traffic (modelled, approximate link figures) | unchanged | about 0 rate (occupancy arithmetic, approximate; the pack measures it) | the same | the same | 4x the register arrays, cost per op unchanged (modelled) | no pack form; a generator constant (gate plan) |
|
||||
| 3 | Layer 7: warp-uniform block selection | life of a bitstream (door 3, the FPGA lane) | B x the shadow's area for a fixed pipeline or an overlay (approximate) | unchanged | about 0 (one uniform branch and 40 shuffles per hash: 0.3 percent of `F`) | the same | the compile footprint caps B (the 1,024-line block cost 17 percent, measured) | B x the dynamic test per candidate | no pack form (gate plan) |
|
||||
| 4 | The reserve's order | life of fixed silicon (door 3) | USD 4 pre-wired | unchanged | under 1 percent at 4 points (measured steps) | the same | the same | 0 | layer 3's gate |
|
||||
|
||||
What the list does not contain, and why it is honest to say so: no candidate moves the per-joule identity. The chip that stores the dataset keeps 3.6x at zero premium and 2.1x at `k = 1` under every layer here, as under the four. What the list adds is the project cost (rank 1 doubles it on the mission lane's model, rank 2 removes its cheaper branch), the FPGA lane's cost (rank 3), and the order of the reserve (rank 4). The founder's line "render an ASIC useless as soon as it dropped" is true of the fixed-function chip under layers 1 and 3 and stays false of the GPU-like chip under everything; the honest public sentence is the research file's: the price per joule of the honest card's operating point and the shadow's premium are what hold the general chip, and the layers decide which chip can be built and what it costs to start.
|
||||
|
||||
## 5. Consequences per tier (the standing rule of 5 October 2026)
|
||||
|
||||
| Tier | What this file means today | What is being done |
|
||||
|---|---|---|
|
||||
| A home miner, one 8, 12 or 16 GB card, any vendor, any OS | nothing changes: no layer here ships this week, no class moves, the devnet pays nothing; if rank 1 lands in v6 the card runs the same shadow work in a different place at the same or lower watts (the 16 x 27 form's measured 13 to 14 W under the whole block on a 5090; a 4070-class card's premium at its tune point is 30 W today, measured) | the sound forms' 5090 rows today; a small-card row (the 4070) by job when the hash lane's queue allows |
|
||||
| One 24 or 32 GB card (5090 class) | the measured rows of section 3; the per-load placement is cheaper for this card than class v4's block at the same work | the PC 1 job, about 12:45 UK |
|
||||
| RTX 5070 Ti | no card in the project; every row is the 4070's or the 5090's scaled, approximate; the hash lane's default (the stock pair plus the 5090's lock slope) stands | stated as approximate wherever it appears |
|
||||
| Apple (M-series) | the one open number: the inline footprint of a 4,096-line per-load block (the 1,024-line block cost 17 percent on 6 October); if it costs rate, rank 1 takes a block-shape cap for the Apple tier (144 x 3 at 2,516 lines, or a 64-instruction sub-block form) and the synthesis says so | a Metal packbench row under the measure lock by the lane that runs the Mac (not this one) |
|
||||
| A rig | watts per card as the 5090 row; a rig's bill under rank 1 is at or under class v4's | the same rows |
|
||||
| A pool user | nothing: no share, payout or template changes in any candidate kept; the rejected 2.9 (pool-sampled witnesses) is the only one that would have touched the pool protocol | nothing |
|
||||
| A node operator (the verifier) | the per-load forms verify in class v4's time (8.3 to 8.8 ms loaded, measured); layer 7 at B blocks multiplies the acceptance's dynamic test per candidate, not the hash | the 2019-class core measurement (O-1.14) decides rung and block caps as before |
|
||||
| A chip maker | under rank 1 the controller and the shadow core share one advanced die or an interposer (project about USD 60 M, modelled); under rank 2 the interposer no longer suffices; under rank 3 a per-epoch bitstream carries B blocks; the per-joule edge is unchanged | the gate plan of section 6 |
|
||||
| The public claim | nothing moves; the chip texts rest on the research file's close (2.1x at `k = 1` for 82 to 90 W on a 5090 at the knee, measured four times) | the Counter lane's texts |
|
||||
|
||||
## 6. The gate plan (hours, never weeks; nothing this week)
|
||||
|
||||
| Gate | What runs | Pass line | Known-failed case |
|
||||
|---|---|---|---|
|
||||
| G5-draw (layer 5) | the generator's dataflow fixpoint and shared-operand rule over the real per-load order; the 4,096 cap raised so 16 x 432 x 1 draws; `v6inv-census.sh` at 256 seeds, no era and drawn eras (with the instrument's window bits excluded) | rejection per candidate at or under 0.75 on every sound form, 0 exhaustions, drawn-era rate equal to the no-era rate within the binomial band; the F8 census at 2^24 on 64 seeds: 60 of 64 under 1.2x, the four tail seeds' sites read against their own windows | the 7 October per-load record (candidate 0 of 854050a4293f0615) refused; the 16 x 27 form at 0.989 refused by the line |
|
||||
| G5-card (layer 5) | one pack per sound form on the 5090 (today), the 4070 and the 9070 XT by job, Metal packbench on the M5 Max | rate within 1 percent of class v4's shape at both states on NVIDIA and AMD; watts at or under class v4's; the Apple footprint within 5 percent or the block-shape cap set | a pack whose fingerprint differs from the Rust verifier's on any vendor |
|
||||
| G6 (layer 6) | the register count as a class field; the census at 8, 16, 32; the card packs | 2.2's pass line | 2.2's fail line |
|
||||
| G7 (layer 7) | the selection class; every path judged; the selection histogram at 2^24 | 2.3's pass line | the lane-0 plant |
|
||||
| G-order (the reserve) | layer 3's gate with the order fixed | layer 3's line | layer 3's case |
|
||||
|
||||
Hours: the dataflow rule in execution order 2 to 3 (the research file's own estimate) plus the re-export and census 1; the register class 3 to 4; the selection class 4 to 6; the card jobs are queue time. Nothing is coded this week; the first code is the founder's call after the synthesis.
|
||||
|
||||
## 7. Unverified and owed
|
||||
|
||||
- The sound forms' card rows (the 5090 today through the hash lane; the 4070 and the 9070 XT later; the M5 Max footprint by the lane that runs the Mac).
|
||||
- The 16 x 432 x 1 form itself: bracketed by the 256 x 1 and 144 x 3 rows (0.927 and 0.935) and the flat ladder between 36 and 256; not drawn (the cap).
|
||||
- The instrument fix (the window bits) and the re-read of 20.2a-close: owed to the research file's owner, not made here.
|
||||
- The bits 26 and 27 mild bias (502 rejections at one-counts 7,168 to 7,680 of 16,384): unattributed; a trace of the site's source writers is the next read.
|
||||
- The register-width and block-selection classes: modelled only; no pack exists.
|
||||
- Every chip figure is the model's (chip-model-v3 section 5 and the research file's sections 2, 15.1a, 16 and 20.4); the die-to-die link figures of 2.2 are approximate, from memory, uncited; no chip has been measured.
|
||||
- The web search budget of this session was exhausted before this lane's reading; every external figure here is one already cited in the repo's files, with its URL and date there (the research file's section 14, the history's section 6, chip-model-v3 5.1).
|
||||
|
||||
## 8. Sources
|
||||
|
||||
Internal: `docs/spec/01-lottery-hash.md` (1.4.3 to 1.4.7, 1.8.5, 1.8.6 on branch class-v5, 1.13); `docs/analysis/chip-model-v3.md` (sections 1 to 3, 5.1 to 5.11, 6); `docs/analysis/counter-asic-4-research.md` on branch counter-asic-4 (sections 0, 2, 4, 7, 9, 15.1a, 15.1b, 16, 17, 20.2 to 20.4); `docs/plans/cryptanalysis/in-house-pass.md` (sections 12 to 14); `docs/plans/counter-asic-3-status.md` section 7c; `docs/analysis/asic-resistance-history.md` (sections 1.2, 2.4 to 2.6, 3, 4.3); `docs/analysis/era-vdf-2026-10-07.md`; `docs/design/class-v5-stored-state.md` on branch class-v5 (2a, 3); `docs/design/latency-ladder.md` on branch ladder (2 to 5); `docs/analysis/card-lifetime-2026-10-05.md`; `docs/analysis/latency-shadow-2026-10-06.md`; `docs/analysis/scratch-soundness.md`; `docs/design/class-v6-rotating-family.md` on branch counter-asic-4 (the synthesis's outline at 5984ffab); the harness runs of section 3 (logs on build-1 under `/srv/builds/v6-invention/`).
|
||||
|
||||
External, as cited in those files (read there on the dates they state): O'Connor et al., Fine-Grained DRAM, MICRO 2017; Li, Reddy, Jacob, MEMSYS 2018; Folded Banks, ISCA 2025; Horowitz, ISSCC 2014; Dally, Hot Chips 2023; the mlsysbook energy table citing Horowitz and Dally; the RandomX design document; the ProgPoW audits (Least Authority and Rao, 2019); Condrey, PoSME, arXiv 2604.15751 (April 2026); the Ethash, RandomX, Equihash and Cuckatoo chip rows of the history; the GDDR7 price rows (TrendForce, September 2026).
|
||||
2817
docs/analysis/class-v6/logs/census-era.tsv
Normal file
2817
docs/analysis/class-v6/logs/census-era.tsv
Normal file
File diff suppressed because it is too large
Load diff
2817
docs/analysis/class-v6/logs/census-none.tsv
Normal file
2817
docs/analysis/class-v6/logs/census-none.tsv
Normal file
File diff suppressed because it is too large
Load diff
122
docs/bridge/light-client-bridge.md
Normal file
122
docs/bridge/light-client-bridge.md
Normal file
|
|
@ -0,0 +1,122 @@
|
|||
# The light-client bridge primitive (Devnet 3 to Ethereum Sepolia), 8 October 2026
|
||||
|
||||
Devnet 3, test tokens, no value. This is a design plus one working contract. It moves nothing. It proves two things on
|
||||
Sepolia and states, below, what it does not prove.
|
||||
|
||||
## What exists
|
||||
|
||||
| Piece | Where | What it does |
|
||||
|---|---|---|
|
||||
| The verifier contract | `contracts/bridge/src/IgneumCertificateVerifier.sol`, deployed on Sepolia (address in `docs/contracts/sepolia.json`) | holds a Devnet 3 voter table; verifies a finality certificate against it and records the checkpoint hash as final; verifies an Ethereum account proof against a state root |
|
||||
| BLS12-381 | `contracts/bridge/src/BLS12381.sol` | hash-to-curve for G2 (RFC 9380, the node's DST), key aggregation in G1, the two-pairing check, all through the EIP-2537 precompiles |
|
||||
| The account proof | `contracts/bridge/src/MerklePatricia.sol` | walks an eth_getProof-shaped proof (RLP nodes, hex-prefix paths, embedded children) to the account's RLP value or to its absence |
|
||||
| The suite | `contracts/bridge/test/Verifier.t.sol`, vectors from `test/vectors/gen.mjs` | 9 tests on Foundry's Prague EVM: the vote message byte for byte, RFC 9380 expand_message_xmd answers, a certificate by four of five made-up keys, one under two thirds refused, forged index and checkpoint refused, the recorded checkpoint, an account present and an account absent under one root, a wrong root refused, and one certificate the chain actually carried |
|
||||
| The vectors | `gen.mjs synthetic`, `gen.mjs table <weights.json>`, `gen.mjs chain <checkpoint.json>` | made-up keys and a three-account trie; the Devnet 3 voter table from a node's `igneum_getFinalityWeights`; a real certificate as `/api/checkpoint` serves it, keys and signature decompressed to the precompiles' encodings |
|
||||
|
||||
The suite ran green on build-3 (9 of 9) before the deploy; the Sepolia address and the deploy transactions are in
|
||||
`docs/contracts/sepolia.json`.
|
||||
|
||||
## What the certificate check proves
|
||||
|
||||
A certificate is `(index, checkpoint hash, bitmap, aggregate signature)` as `consensus/core/src/finality.rs` writes it
|
||||
into a block's coinbase (`Certificate::write`: index_le64, checkpoint, voter_count_le32, bitmap_len_le32, bitmap,
|
||||
signature, aggregator, aggregator proof). The contract takes the first four fields; the signature is the 96-byte G2
|
||||
point decompressed off chain to the precompiles' 256-byte form (a wrong decompression is a point the pairing
|
||||
precompile refuses).
|
||||
|
||||
The contract holds a voter table installed by its deployer: the canonical voter list at one checkpoint index (every
|
||||
key above dust and not stripped, sorted by key hash, as the node's `igneum_getFinalityWeights` reports it), each key a
|
||||
128-byte uncompressed G1 point, each weight the key's blue blocks in the 30-day window. `tableId` is the keccak of
|
||||
`(index, keys, weights)`.
|
||||
|
||||
`verifyCertificate(index, checkpoint, bitmap, signature)` holds exactly when:
|
||||
|
||||
1. bit `p` of the bitmap names voter `p` of the table, and the sum of the named voters' weights is at least two thirds
|
||||
of the table's total weight (the rule decided 4 October 2026: lock = 2/3 of all 30-day weight; stricter than the
|
||||
17/30 floor plus 2/3 of active that the node line still carries, so every certificate the node locks under the new
|
||||
rule passes here and some the old rule locked would not);
|
||||
2. the aggregate of the named keys (G1 additions) verifies the signature over the vote message
|
||||
`"igneum-vote-v1/" || chain_id || 0x00 || index_le64 || checkpoint` under the domain separation tag
|
||||
`IGNEUM_VOTE_V1_BLS12381G2_XMD:SHA-256_SSWU_RO_NUL_`, with `chain_id` the string the contract was built with
|
||||
(`igneum-devnet-3`): e(aggregate key, H(message)) * e(-G1, signature) = 1.
|
||||
|
||||
So a recorded `finalCheckpoint(index)` means: the keys in the installed table that hold at least two thirds of that
|
||||
table's weight signed this checkpoint hash at this index on this chain id. That is the finality rule's own statement,
|
||||
checked with the node's own bytes, by a contract on another chain.
|
||||
|
||||
Measured on the test EVM: a 29-voter table costs about 5.3 million gas to install; a certificate with 12 signers
|
||||
verifies in about 3.9 million gas (the pairing and the two map-to-curve calls dominate; a G1 addition per signer is
|
||||
375 gas). On Sepolia at a 1 gwei tip that is under 0.01 ETH per certificate.
|
||||
|
||||
## What the account proof proves
|
||||
|
||||
`verifyAccount(stateRoot, account, proof)` walks an Ethereum account proof (the `eth_getProof` shape: RLP nodes from
|
||||
the root, keys hashed with keccak, the hex-prefix leaf and extension paths, children by hash or embedded when under 32
|
||||
bytes) and returns the account's nonce, balance, storage root and code hash, or `exists = false` when the trie shows the
|
||||
account absent. This is the trie Igneum's executor commits to: `igneum/exec/src/state.rs` computes `stateRoot` with
|
||||
`alloy_trie::root::state_root` over `keccak256(address)` and `RLP(nonce, balance, storage_root, code_hash)`, EIP-161
|
||||
empty accounts left out, reth's layout, the same as Ethereum's.
|
||||
|
||||
So a verified account proof means: under this state root, this account has these fields.
|
||||
|
||||
## What is NOT proven, in order of weight
|
||||
|
||||
1. **The link from a certified checkpoint to a state root.** Nothing the contract verifies ties a checkpoint hash to an
|
||||
EVM state root. The Kaspa-shaped header the voters sign has no execution root (its `utxo_commitment` is the UTXO
|
||||
multiset, `accepted_id_merkle_root` the accepted transaction ids); the executor runs behind consensus as a follower
|
||||
and the EVM block hash is the DAG block hash, not a hash of the EVM header. The binding that exists today is in the
|
||||
coinbase of later blocks: the IGNS segment record (`BlockStatement.post_root` for its last chain block, signed by
|
||||
the aggregator's vote key) and the proof records (`ProofRecord.statement` = keccak of a `ShardOutput` carrying
|
||||
`pre_root` and `post_root`, signed by the prover's vote key), both under the carrier block's `hash_merkle_root`. A
|
||||
carried record that fails a node's native veto is ignored rather than faulting the block, so even that binding
|
||||
rests on the aggregator's and prover's keys and on the nodes' native check, not on a header field. Today a caller
|
||||
gives the verifier a state root as a stated input beside a verified certificate; the contract does not know they
|
||||
belong together. The reference-apps lane's oracle verifies the coinbase path (BLAKE2b header hash, the merkle
|
||||
branch, the record parse) on Sepolia and shares this verifier for the certificate; the two together are the full
|
||||
chain once the record's signature check lands there.
|
||||
2. **The voter table itself.** The table is installed by the deployer from a node's `igneum_getFinalityWeights` read:
|
||||
the keys, their canonical order (sorted by `BLAKE2b-256("IgneumVoteKeyHash", key)`, which the contract does not
|
||||
recompute: no BLAKE2b on chain today) and their weights are trusted. A wrong table makes a wrong verdict in both
|
||||
directions. A light client proper tracks the table from the chain: every weight is a count of blue blocks whose
|
||||
headers name the key, so the table follows from headers; and the node's `FinalityWeights` RPC reports the table at
|
||||
the certificate's own index (`voters_at_index`). The next step is a table update that takes a certified checkpoint
|
||||
plus the headers between locks, the shape `/api/checkpoint` already serves to the browser verifier
|
||||
(`site/verify/core.js` checks exactly that path, in JavaScript).
|
||||
3. **The checkpoint index is a number the submitter gives.** The contract records one hash per index and refuses a
|
||||
second, but it does not know the chain's current index; an old certificate at an old index verifies for ever
|
||||
against the table it was signed under. A consumer should read `finalCheckpoint` at an index it already knows from
|
||||
the chain, not treat the newest recorded index as the chain's tip.
|
||||
4. **Equivocation and stripping.** The node strips a key's weight for 30 days on equivocation evidence. The installed
|
||||
table carries the stripping as of its read and nothing after it.
|
||||
5. **Proof of work, the DAG order, execution correctness.** None of it is checked here. The certificate's claim is the
|
||||
voters' signature, and the voters are the miners who proved their blocks; the ZK proofs of execution (the shard
|
||||
proofs the records name) are verified by the nodes, not by this contract. A proof-carrying bridge (the chain's SP1
|
||||
shard proofs verified on Ethereum) is the design's end state and is not today's primitive.
|
||||
6. **The state root's age and the account's current balance.** An account proof says what the balance was under that
|
||||
root; the root is one block's. Nothing here prevents a stale root from being presented.
|
||||
|
||||
## How one balance gets proven on Sepolia today, and what each step rests on
|
||||
|
||||
| Step | Source | Rests on |
|
||||
|---|---|---|
|
||||
| the voter table at index N | a Devnet 3 node's `igneum_getFinalityWeights` | the node, the installer (trusted today) |
|
||||
| the certificate for checkpoint C at index N | `/api/checkpoint?source=dn3` (the observer's `dn3_live_certificates`, the bytes a block carried) | verified on chain: the signature and the two-thirds rule |
|
||||
| the state root R of chain block B | `eth_getBlockByNumber` on Devnet 3 | stated, not proven against C (gap 1) |
|
||||
| the account proof for A under R | `eth_getProof` on the reference-apps lane's reader node (fork branch light-apps-node, the Devnet 3 pin plus a read-only RPC) | verified on chain against R |
|
||||
|
||||
The test `test_account_proof_present_and_absent` proves the account under a made-up root; the Devnet 3 account
|
||||
proof against a real root goes into the suite as `test/vectors/dn3-account.json` the moment the reader node serves
|
||||
`eth_getProof` (the proof shape is Ethereum's, so the contract needs no change).
|
||||
|
||||
## The design from here
|
||||
|
||||
1. The header path on chain: BLAKE2b-256 through the EIP-152 precompile for the keyed header hash and the key hashes,
|
||||
the merkle branch to the coinbase, the segment and proof records parsed from the coinbase payload. This closes gap 1
|
||||
and lets the contract recompute canonical order (gap 2's order).
|
||||
2. The table update from certified headers: weights counted from the blue blocks between two locks, so the table
|
||||
follows the chain instead of an installer. This closes gap 2.
|
||||
3. A tip rule: the contract keeps the highest index it has recorded and a consumer reads only at or below it; the
|
||||
relayer submits each lock as it lands (one transaction per 30-second checkpoint is affordable on Sepolia, not on
|
||||
mainnet; mainnet gets one certificate per epoch).
|
||||
4. The proof-carrying bridge: the shard proofs' aggregate verified on Ethereum (the prover network's own product),
|
||||
which replaces trust in the native veto with a verified execution root.
|
||||
16
docs/build/README.md
vendored
Normal file
16
docs/build/README.md
vendored
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
# docs/build: the builder programme
|
||||
|
||||
8 October 2026. These files are the source of the developer pages on igneum.network; `site/build.mjs` renders two of them as pages and the rest are read here.
|
||||
|
||||
| File | Serves |
|
||||
|---|---|
|
||||
| `build.md` | [igneum.network/build](https://igneum.network/build): what is different (built to prove every block, a lock in minutes, nothing to stake, the EVM unchanged), the chain ids and endpoints, the wallet, the explorer, the faucet, the five-minute contract, the browser verifier |
|
||||
| `grants.md` | [igneum.network/grants](https://igneum.network/grants): the tiers, what a grant is, how to apply, the review, the honest lines |
|
||||
| `first-contract.md`, `first-contract-test.sh` | the walkthrough and the script that runs it end to end on Devnet 3 from a build box; the PASS line is the test record |
|
||||
| `rpc.md` | the JSON-RPC method list as the node serves it, read from a Devnet 3 node, with the probe |
|
||||
| `faucet.md` | the Devnet 3 faucet: rules, where it runs, how it is funded |
|
||||
| `verify-a-block.md` | the in-browser checkpoint verifier, twelve lines |
|
||||
|
||||
The faucet service is `infra/build-server/faucet/`. The grant application template is `.forgejo/issue_template/grant.md`.
|
||||
|
||||
Served-text rules (the site audit reads every page before it lands): no em dashes, short sentences, one to three points per block, nothing that reads as an offer, a price or a promise of value; devnet and testnet coins have no value; no amount, price or date is promised.
|
||||
88
docs/build/build.md
vendored
Normal file
88
docs/build/build.md
vendored
Normal file
|
|
@ -0,0 +1,88 @@
|
|||
# Build on Igneum
|
||||
|
||||
This file is the source of [igneum.network/build](https://igneum.network/build). The site build renders it as the page. The other files in this directory are the walkthrough, the RPC list, the faucet, the verifier and the grants.
|
||||
|
||||
## What is different
|
||||
|
||||
**Every block is built to be proven.** A chain block carries a zero-knowledge proof of its execution. The miners are the provers: the same cards that find blocks prove them, in shards. On Devnet 3 a share of blocks carries a proof today; the live page shows the share and the lag, and the design target at launch is under a minute. Full nodes execute every block themselves, so a bad proof is a light-client problem and never a chain split.
|
||||
|
||||
**A lock in minutes, not an hour of confirmations.** Miners sign a checkpoint every 30 seconds. When two thirds of the mining weight of the last 30 days have signed, the checkpoint is locked. Weight is blocks mined, nothing else. The lock lands in about two minutes. The [litepaper](/litepaper) has the rule.
|
||||
|
||||
**Nothing to stake.** No validator set, no delegation, no slashing, no bonded class above the miners. Finality comes from mining weight alone. Nobody holds a key that the chain depends on.
|
||||
|
||||
**The EVM you already know.** Solidity deploys unchanged. Standard JSON-RPC, EIP-1559 transactions, the chain id in the signature, `cancun` as the EVM version. Gas has two dimensions on Igneum, execution and proving, and the node folds the second into the price it quotes, so `eth_estimateGas` and `eth_gasPrice` work as they do on Ethereum.
|
||||
|
||||
## Networks
|
||||
|
||||
| | Devnet 3 | Testnet | Mainnet |
|
||||
|---|---|---|---|
|
||||
| Chain id | 4463 (`0x116f`) | 4462 (`0x116e`) | 4461 (`0x116d`) |
|
||||
| Network id | `igneum-devnet-3` | `igneum-testnet-1` | not started |
|
||||
| RPC | `https://rpc.devnet.igneum.network` (a node you run serves `http://127.0.0.1:26790`) | `https://rpc.testnet.igneum.network` (answers; nothing mines there yet, so a transaction waits) | none |
|
||||
| Coins | no value, resets without notice | no value, resets with notice | not started |
|
||||
| Symbol, decimals | IGN, 18 | IGN, 18 | IGN, 18 |
|
||||
|
||||
Devnet 3 is where you build today. It is a developer network: it resets without notice and its coins have no value. Its public RPC takes the read methods, `eth_sendRawTransaction` and a wRPC websocket at `/ws`, at 20 requests a second per address. The public testnet exists, its RPC answers, and no blocks are being produced on it until it opens. Mainnet has no date. Devnet 3 answers chain id 4463 until its class v5 floor, then 4464.
|
||||
|
||||
## Endpoints and tools
|
||||
|
||||
- **Wallet.** Any Ethereum wallet. [Add Igneum to MetaMask](/metamask) with one click, or the [Igneum wallet](/wallet).
|
||||
- **Faucet.** [10 IGN of Devnet 3 coin](/faucet) per address per day. No account.
|
||||
- **Explorer.** [The explorer](/explorer) shows blocks, the DAG, miners and addresses. The EVM views, transactions and contracts, are being built and link from the same page as they land.
|
||||
- **Swap.** [The swap](/swap): test tokens on Devnet 3, every swap in a proven block.
|
||||
- **Source.** [git.igneum.network/igneum-network/igneum](https://git.igneum.network/igneum-network/igneum): the node, the miner, the site, and these pages under `docs/build/`.
|
||||
|
||||
## Your first contract in five minutes
|
||||
|
||||
With [Foundry](https://getfoundry.sh). Tested end to end on Devnet 3 on a build box; the full walkthrough with the expected output is [docs/build/first-contract.md](https://git.igneum.network/igneum-network/igneum/src/branch/master/docs/build/first-contract.md).
|
||||
|
||||
```
|
||||
curl -L https://foundry.paradigm.xyz | bash && foundryup
|
||||
export RPC=https://rpc.devnet.igneum.network
|
||||
cast wallet new # an address and a private key, for the devnet only
|
||||
```
|
||||
|
||||
Paste the address into [the faucet](/faucet). Then:
|
||||
|
||||
```
|
||||
export PK=0x... # the private key cast printed
|
||||
cast balance $(cast wallet address $PK) --rpc-url $RPC --ether
|
||||
forge init counter && cd counter
|
||||
forge create src/Counter.sol:Counter --rpc-url $RPC --private-key $PK --broadcast
|
||||
```
|
||||
|
||||
`forge create` prints `Deployed to: 0x...`. Call it:
|
||||
|
||||
```
|
||||
cast send 0xDEPLOYED "increment()" --rpc-url $RPC --private-key $PK
|
||||
cast call 0xDEPLOYED "number()(uint256)" --rpc-url $RPC
|
||||
```
|
||||
|
||||
The call answers `1`. Paste the transaction hash into [the explorer](/explorer). Hardhat, ethers and viem work the same way: chain id 4463, the RPC above.
|
||||
|
||||
## The RPC the node serves
|
||||
|
||||
Read from a Devnet 3 node, not from a spec. `web3_clientVersion` answers `igneumd/2.1.0/execution-layer-v3`. The full list, served and not served, with the probe that produced it: [docs/build/rpc.md](https://git.igneum.network/igneum-network/igneum/src/branch/master/docs/build/rpc.md).
|
||||
|
||||
- **Served.** `eth_chainId`, `eth_blockNumber`, `eth_getBalance`, `eth_getTransactionCount`, `eth_getCode`, `eth_getStorageAt`, `eth_getBlockByNumber`, `eth_getBlockByHash`, `eth_getTransactionByHash`, `eth_getTransactionReceipt`, `eth_getBlockReceipts`, `eth_getLogs`, `eth_call`, `eth_estimateGas`, `eth_gasPrice`, `eth_maxPriorityFeePerGas`, `eth_feeHistory`, `eth_sendRawTransaction`, `eth_syncing`, `eth_accounts`, `net_version`, `net_peerCount`, `net_listening`, `web3_clientVersion`.
|
||||
- **Igneum's own.** `igneum_getExecStatus`, `igneum_getProvingStatus`, `igneum_getShardPlan`, `igneum_getProofRecords`, `igneum_getTransactionStatus`, `igneum_estimateGas`, `igneum_getBudgets` and the segment and proof calls. `igneum_estimateGas` returns both gas dimensions and whether a call exceeds the proving limit.
|
||||
- **Not served.** Filters and subscriptions (`eth_newFilter`, `eth_subscribe`), `txpool_*`, `debug_*`, `trace_*`, `eth_sendTransaction`, `eth_sign`, `eth_getProof`, the uncle calls. Poll `eth_blockNumber` and `eth_getLogs`. Sign on your side.
|
||||
|
||||
## Verify a block in your browser
|
||||
|
||||
The site ships a light client. Your browser fetches the latest certified checkpoint from `/api/checkpoint` and verifies the BLS aggregate signature, the voter weights and the header chain itself, in the tab. Nothing is trusted from the server but the data. The example, in twelve lines, is [docs/build/verify-a-block.md](https://git.igneum.network/igneum-network/igneum/src/branch/master/docs/build/verify-a-block.md); the live run is [verify/test.html](/verify/test.html), genuine and tampered cases side by side.
|
||||
|
||||
```
|
||||
import { fetchCheckpoint, verify } from 'https://igneum.network/verify/verify.js';
|
||||
const data = await fetchCheckpoint('https://igneum.network/api/checkpoint');
|
||||
const r = verify(data);
|
||||
console.log(r.verified, r.signers, 'of', r.voters, 'voters', r.ms, 'ms');
|
||||
```
|
||||
|
||||
## Where to ask
|
||||
|
||||
- An issue on [the repository](https://git.igneum.network/igneum-network/igneum/issues).
|
||||
- [Discord](https://discord.gg/igneum), the builders channel.
|
||||
- [Grants](/grants) for tooling, reference apps, infrastructure and research.
|
||||
|
||||
Devnet and testnet coins have no value. Nothing on this page is an offer to sell anything.
|
||||
36
docs/build/faucet.md
vendored
Normal file
36
docs/build/faucet.md
vendored
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
# The Devnet 3 faucet
|
||||
|
||||
[igneum.network/faucet](https://igneum.network/faucet) sends 10 IGN of Devnet 3 coin to an address. Once per address per day, once per connection per day. No account.
|
||||
|
||||
## What it is
|
||||
|
||||
- A small Node service on a build box, `infra/build-server/faucet/faucet.mjs`, behind Caddy at `faucet.igneum.network`. The page on igneum.network posts to it.
|
||||
- It signs a plain transfer with its own key and sends it to the Devnet 3 node on the same box by address (`FAUCET_RPC`), never chosen by chain id: Devnet 3 answers the same chain id as the shared devnet.
|
||||
- The key lives only in the service's environment file on that box. It is not in the repository and not on the site.
|
||||
|
||||
## The rules, as the code enforces them
|
||||
|
||||
| Rule | Value |
|
||||
|---|---|
|
||||
| Amount | 10 IGN per send; the code refuses to start with an amount over the 100 IGN cap |
|
||||
| Per address | one send per 24 hours |
|
||||
| Per connection | one send per 24 hours |
|
||||
| Per day, in total | 500 sends, then "come back tomorrow" |
|
||||
| What is stored | the address, the connection's IP, the transaction hash and the time, in a file on the box, for the 24-hour window |
|
||||
|
||||
The faucet's balance is refilled from the devnet's funder as it runs down. When it is empty the page says so and sends nothing.
|
||||
|
||||
## Devnet 3 coin
|
||||
|
||||
No value. Not for sale, not redeemable, not a claim on anything. The chain resets without notice and balances do not carry over. Mainnet starts from an empty genesis.
|
||||
|
||||
## Running it
|
||||
|
||||
```
|
||||
infra/build-server/faucet/faucet.sh install # dry run: what would be copied and started
|
||||
infra/build-server/faucet/faucet.sh install --go # copy the service, the unit and the Caddy block; start it
|
||||
infra/build-server/faucet/faucet.sh status # the unit, the balance, the sends in the last 24 hours
|
||||
node infra/build-server/faucet/faucet.mjs --self-test # the limiter: known-failed cases first
|
||||
```
|
||||
|
||||
The public testnet faucet is a separate thing: `site/api/faucet.mjs` is prepared for it and answers "not open yet" until the testnet starts.
|
||||
49
docs/build/first-contract-test.sh
vendored
Executable file
49
docs/build/first-contract-test.sh
vendored
Executable file
|
|
@ -0,0 +1,49 @@
|
|||
#!/usr/bin/env bash
|
||||
# The five-minute walkthrough (docs/build/first-contract.md), run end to end on a build box against a Devnet 3 node, so the
|
||||
# page is tested and not described. Runs where Foundry is installed (~/.foundry/bin); asks the faucet for the coins exactly
|
||||
# as a reader would, deploys Foundry's Counter, calls it, reads the receipt, prints one PASS line with the numbers.
|
||||
# RPC=http://127.0.0.1:27810 FAUCET=http://127.0.0.1:8790/api/faucet bash docs/build/first-contract-test.sh
|
||||
# Known-failed first: with RPC pointed at a closed port the script must print FAIL and exit 1 (--self-test).
|
||||
set -uo pipefail
|
||||
export PATH="$HOME/.foundry/bin:$PATH"
|
||||
RPC="${RPC:-https://rpc.devnet.igneum.network}"
|
||||
FAUCET="${FAUCET:-https://faucet.igneum.network/api/faucet}"
|
||||
t0=$(date +%s); now() { date -u +%H:%M:%SZ; }
|
||||
fail() { echo "FAIL $(now): $*"; exit 1; }
|
||||
if [ "${1:-}" = --self-test ]; then
|
||||
out=$(RPC=http://127.0.0.1:9 FAUCET=http://127.0.0.1:9/x bash "$0" 2>&1); rc=$?
|
||||
[ "$rc" = 1 ] && case "$out" in *FAIL*) echo "self-test passed: a closed RPC port reads FAIL, exit 1"; exit 0 ;; esac
|
||||
echo "self-test failed: rc=$rc out=$out"; exit 1
|
||||
fi
|
||||
command -v forge >/dev/null || fail "forge is not installed"
|
||||
cid=$(cast chain-id --rpc-url "$RPC" 2>/dev/null) || fail "no chain id from $RPC"
|
||||
[ "$cid" = 4463 ] || [ "$cid" = 4464 ] || fail "chain id $cid is not Devnet 3"
|
||||
work=$(mktemp -d); cd "$work" || fail "no scratch dir"
|
||||
# step 1: a key for the devnet only (never printed)
|
||||
w=$(cast wallet new 2>&1 | sed 's/\x1b\[[0-9;]*m//g') || fail "cast wallet new"
|
||||
PK=$(printf '%s\n' "$w" | sed -n 's/^Private key: *//p' | head -1); ME=$(printf '%s\n' "$w" | sed -n 's/^Address: *//p' | head -1)
|
||||
[ -n "$PK" ] && [ -n "$ME" ] || fail "cast wallet new printed no key"
|
||||
# step 2: the faucet, as a reader would
|
||||
f=$(curl -s -m 60 -X POST -H 'content-type: application/json' --data "{\"address\":\"$ME\"}" "$FAUCET") || fail "the faucet did not answer"
|
||||
case "$f" in *'"ok":true'*) ;; *) fail "the faucet refused: $f" ;; esac
|
||||
drip=$(printf '%s' "$f" | sed -n 's/.*"tx":"\(0x[0-9a-f]*\)".*/\1/p')
|
||||
for i in $(seq 1 60); do bal=$(cast balance "$ME" --rpc-url "$RPC" --ether 2>/dev/null); case "$bal" in 10.*|9.*) break ;; esac; sleep 1; done
|
||||
case "$bal" in 10.*|9.*) ;; *) fail "balance after the faucet: ${bal:-none}" ;; esac
|
||||
# step 3: deploy Foundry's template counter
|
||||
forge init counter --no-git >/dev/null 2>&1 || forge init counter >/dev/null 2>&1 || fail "forge init"
|
||||
cd counter || fail "no counter dir"
|
||||
out=$(forge create src/Counter.sol:Counter --rpc-url "$RPC" --private-key "$PK" --broadcast 2>&1) || fail "forge create: $(printf '%s' "$out" | tail -3)"
|
||||
C=$(printf '%s\n' "$out" | sed -n 's/^Deployed to: *//p' | head -1); deployTx=$(printf '%s\n' "$out" | sed -n 's/^Transaction hash: *//p' | head -1)
|
||||
[ -n "$C" ] || fail "no Deployed to line: $out"
|
||||
# step 4: call it
|
||||
cast send "$C" "increment()" --rpc-url "$RPC" --private-key "$PK" >/dev/null 2>&1 || fail "cast send increment"
|
||||
n=$(cast call "$C" "number()(uint256)" --rpc-url "$RPC" 2>/dev/null); [ "$n" = 1 ] || fail "number() after increment: $n"
|
||||
sendOut=$(cast send "$C" "setNumber(uint256)" 41 --rpc-url "$RPC" --private-key "$PK" 2>&1) || fail "cast send setNumber"
|
||||
txh=$(printf '%s\n' "$sendOut" | sed -n 's/^transactionHash *//p' | head -1)
|
||||
n=$(cast call "$C" "number()(uint256)" --rpc-url "$RPC" 2>/dev/null); [ "$n" = 41 ] || fail "number() after setNumber: $n"
|
||||
# step 5: the receipt
|
||||
st=$(cast receipt "${txh:-$deployTx}" --rpc-url "$RPC" 2>/dev/null | sed -n 's/^status *//p' | head -1)
|
||||
case "$st" in 1*|*success*) ;; *) fail "receipt status: $st" ;; esac
|
||||
blk=$(cast block-number --rpc-url "$RPC" 2>/dev/null)
|
||||
echo "PASS $(now): Devnet 3 chain id $cid, faucet drip $drip, deployed Counter at $C (tx $deployTx), increment then setNumber(41) read back 41, receipt status $st, block $blk, $(( $(date +%s) - t0 )) s end to end, Foundry $(forge --version 2>/dev/null | sed -n 's/^forge Version: *//p' | head -1)"
|
||||
cd / && rm -rf "$work"
|
||||
91
docs/build/first-contract.md
vendored
Normal file
91
docs/build/first-contract.md
vendored
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
# Your first contract on Devnet 3, in five minutes
|
||||
|
||||
With Foundry. Tested end to end on Devnet 3 from a build box on 8 October 2026; the pass line and the exact output are at the end. Hardhat, ethers and viem work the same way: chain id 4463 and the RPC below.
|
||||
|
||||
## 0. What you need
|
||||
|
||||
- Foundry: `curl -L https://foundry.paradigm.xyz | bash && foundryup`. About a minute.
|
||||
- The RPC. Devnet 3's public endpoint is `https://rpc.devnet.igneum.network`. A node you run yourself serves `http://127.0.0.1:26790`.
|
||||
- Nothing else. No account, no sign-up.
|
||||
|
||||
```
|
||||
export RPC=https://rpc.devnet.igneum.network
|
||||
cast chain-id --rpc-url $RPC # 4463
|
||||
```
|
||||
|
||||
## 1. A key, for the devnet only
|
||||
|
||||
```
|
||||
cast wallet new
|
||||
```
|
||||
|
||||
It prints an address and a private key. Keep the key for this walkthrough and nothing else: devnet coins have no value and the chain resets without notice.
|
||||
|
||||
```
|
||||
export PK=0x... # the private key cast printed
|
||||
export ME=$(cast wallet address $PK)
|
||||
```
|
||||
|
||||
## 2. Coins from the faucet
|
||||
|
||||
Paste `$ME` into [igneum.network/faucet](https://igneum.network/faucet). It sends 10 IGN and shows the transaction hash. Once per address per day.
|
||||
|
||||
```
|
||||
cast balance $ME --rpc-url $RPC --ether # 10.000000000000000000
|
||||
```
|
||||
|
||||
## 3. Deploy
|
||||
|
||||
Foundry's template is a counter. Initialise it and deploy it as it is.
|
||||
|
||||
```
|
||||
forge init counter && cd counter
|
||||
forge create src/Counter.sol:Counter --rpc-url $RPC --private-key $PK --broadcast
|
||||
```
|
||||
|
||||
Expected:
|
||||
|
||||
```
|
||||
Deployer: 0x...
|
||||
Deployed to: 0x...
|
||||
Transaction hash: 0x...
|
||||
```
|
||||
|
||||
```
|
||||
export C=0x... # the Deployed to address
|
||||
```
|
||||
|
||||
## 4. Call it
|
||||
|
||||
```
|
||||
cast send $C "increment()" --rpc-url $RPC --private-key $PK
|
||||
cast call $C "number()(uint256)" --rpc-url $RPC # 1
|
||||
cast send $C "setNumber(uint256)" 41 --rpc-url $RPC --private-key $PK
|
||||
cast call $C "number()(uint256)" --rpc-url $RPC # 41
|
||||
```
|
||||
|
||||
`cast send` waits for the receipt. A block takes about a second.
|
||||
|
||||
## 5. See it
|
||||
|
||||
Paste the transaction hash into [igneum.network/explorer](https://igneum.network/explorer). The receipt is also one call away:
|
||||
|
||||
```
|
||||
cast receipt 0xTXHASH --rpc-url $RPC
|
||||
```
|
||||
|
||||
## What is different under the hood
|
||||
|
||||
- Gas has two dimensions, execution and proving. The node folds the second into the price it quotes, so `forge` and `cast` estimate and pay as on Ethereum. `igneum_estimateGas` shows both numbers and whether a call exceeds the proving limit.
|
||||
- Your transaction is in a block within about a second, proven tens of seconds later, and locked by miner signatures in about two minutes. `igneum_getTransactionStatus` reports each stage.
|
||||
- A transaction signed for another chain id is refused. EIP-155, EIP-1559 and legacy envelopes are accepted.
|
||||
|
||||
## The test record
|
||||
|
||||
Run on a build box against its own Devnet 3 node (the box that also fronts the public RPC and runs the faucet), with Foundry 1.8.5 and a fresh key, through `docs/build/first-contract-test.sh`. The pass line is appended below by the run.
|
||||
|
||||
```
|
||||
PASS 10:17:23Z: Devnet 3 chain id 4463, faucet drip 0x8620e9d894484e824e4ac33002946a00e2f75823ea6db0da0ad29f1af142e8f2, deployed Counter at 0x6345265C6Db0b3713eb6645d795d0B52FE0a4201 (tx 0xcf77b4822d51f3c60ecdf6d7dbbe67524d42071f06c76e1cf9b0511d64783574), increment then setNumber(41) read back 41, receipt status 1 (success), block 27055, 24 s end to end, Foundry 1.8.5
|
||||
```
|
||||
|
||||
Through the public endpoints, `https://rpc.devnet.igneum.network` and `https://faucet.igneum.network`, from the box: the first faucet drip and the first reader-path deploy on Devnet 3.
|
||||
46
docs/build/grants.md
vendored
Normal file
46
docs/build/grants.md
vendored
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
# Grants
|
||||
|
||||
This file is the source of [igneum.network/grants](https://igneum.network/grants).
|
||||
|
||||
## What a grant is
|
||||
|
||||
Grants are paid in IGN from the dev fee fund, on delivery. You propose a piece of work, it is accepted with a written definition of done, you build it, and it runs on the public testnet. Not a salary, not an advance, not an investment.
|
||||
|
||||
The money is the dev fee fund: the IGN that the Ember dev fee collects. Ember, the official miner, takes an optional 1% of a miner's rewards, in full view and off with one flag; that fee goes to Igneum Labs, the company that ships the software. The protocol itself carries no fee, no fund and no allocation, and no grant is paid from emission. [The dev fee](/dev-fee) has the mechanism.
|
||||
|
||||
## The tiers
|
||||
|
||||
| Tier | What fits |
|
||||
|---|---|
|
||||
| Tooling | SDK bindings, indexers, a Hardhat or Foundry plugin for the two gas dimensions, verification tooling, a light client in another language |
|
||||
| Reference apps | A token, a swap, a registry, a wallet integration, an app that uses `igneum_getTransactionStatus` and the lock the way it is meant to be used |
|
||||
| Infrastructure | RPC providers, archive nodes, seed nodes in new regions, pool software, an explorer back end |
|
||||
| Research | The lottery hash, the finality rule, the proving layer, the fee model; attacks on the public test vectors; measurements the project does not have |
|
||||
|
||||
A grant is sized by the work in front of it, not by a table. Two grants in the same tier can differ.
|
||||
|
||||
## How to apply
|
||||
|
||||
Open an issue on [git.igneum.network/igneum-network/igneum](https://git.igneum.network/igneum-network/igneum/issues/new?template=.forgejo%2Fissue_template%2Fgrant.md) and pick the Grant template. It asks for:
|
||||
|
||||
1. What you will build, in a paragraph, and which tier it is.
|
||||
2. What done looks like: what runs where, what a reviewer can click or call to see it working on the public testnet.
|
||||
3. Your public work: a repository, a package, a paper, a deployed thing.
|
||||
4. How you want to be reached.
|
||||
|
||||
A short issue is fine. The definition of done is the part that matters.
|
||||
|
||||
## The review
|
||||
|
||||
- Every Friday. Each open application gets one of three answers inside seven days: accepted with a definition of done, questions, or no with the reason.
|
||||
- Accepted work is tracked in its issue. The reviewer and the builder agree the definition of done there before any work starts.
|
||||
- Delivery is reviewed on the public testnet first. Payment follows the review, in the issue, in the open.
|
||||
|
||||
## The honest lines
|
||||
|
||||
- Devnet and testnet coins have no value. Before mainnet there is no IGN with value: a grant delivered on the testnet is recorded in its issue, and payment comes from the fund when the fund holds IGN. Nothing is promised about when, or whether, that is.
|
||||
- No amount, price or date is promised. The fund is what the dev fee collects, and it is zero today.
|
||||
- A grant is for work delivered, never for a user count, a listing, a post or a referral.
|
||||
- Igneum Labs may decline any application and may close the programme; what has been accepted and delivered is still paid.
|
||||
|
||||
Not legal advice.
|
||||
79
docs/build/rpc.md
vendored
Normal file
79
docs/build/rpc.md
vendored
Normal file
|
|
@ -0,0 +1,79 @@
|
|||
# The JSON-RPC a Devnet 3 node serves
|
||||
|
||||
Read from the node, not from a spec: every method below was sent to a Devnet 3 node on 8 October 2026 (`web3_clientVersion` answered `igneumd/2.1.0/execution-layer-v3`, `eth_chainId` `0x116f`, block 26,666) and sorted by what came back. A method the node does not know answers JSON-RPC error `-32601`. The probe is at the end; run it against your own node to refresh this file.
|
||||
|
||||
Transport: HTTP POST, JSON-RPC 2.0, one request per call, no batches tested. The public endpoint is `https://rpc.devnet.igneum.network`; a node you run serves `http://127.0.0.1:26790`. The DAG side of the node (blocks, the mempool, the vote table) speaks the Kaspa-style gRPC and wRPC on their own ports; the explorer and the observer use those, a contract developer needs only what is here.
|
||||
|
||||
## Served: the Ethereum set
|
||||
|
||||
| Method | Note |
|
||||
|---|---|
|
||||
| `web3_clientVersion` | `igneumd/<version>/execution-layer-v3` |
|
||||
| `net_version` | the chain id as a decimal string, `"4463"` |
|
||||
| `net_listening`, `net_peerCount` | |
|
||||
| `eth_chainId` | `0x116f` (4463) on Devnet 3; `0x1170` after its class v5 floor |
|
||||
| `eth_blockNumber` | the executed chain tip |
|
||||
| `eth_syncing` | `false` when the executor is at the tip |
|
||||
| `eth_mining` | `false` from the RPC's point of view: mining is the miner's, not the node's |
|
||||
| `eth_accounts` | always `[]`: the node holds no keys |
|
||||
| `eth_protocolVersion` | `0x41` |
|
||||
| `eth_gasPrice`, `eth_maxPriorityFeePerGas`, `eth_feeHistory` | EIP-1559 pricing; the proving dimension is folded into the quoted price |
|
||||
| `eth_getBalance`, `eth_getTransactionCount`, `eth_getCode`, `eth_getStorageAt` | by block tag or number |
|
||||
| `eth_getBlockByNumber`, `eth_getBlockByHash` | the EVM view of a chain block; `null` for an unknown hash |
|
||||
| `eth_getBlockTransactionCountByNumber` | |
|
||||
| `eth_getTransactionByHash`, `eth_getTransactionByBlockNumberAndIndex` | |
|
||||
| `eth_getTransactionReceipt`, `eth_getBlockReceipts` | |
|
||||
| `eth_getLogs` | by block range, address and topics |
|
||||
| `eth_call`, `eth_estimateGas` | as on Ethereum |
|
||||
| `eth_sendRawTransaction` | a signed EIP-155, EIP-1559 or legacy envelope; the chain id must match |
|
||||
|
||||
## Served: Igneum's own
|
||||
|
||||
| Method | What the answer carries (from the probe) |
|
||||
|---|---|
|
||||
| `igneum_getExecStatus` | the executed tip, a continuity break if any, what the executor is blocked on |
|
||||
| `igneum_getProvingStatus` | whether proving is active, its activation height, assignees per shard, the dust rule |
|
||||
| `igneum_getShardPlan` | a block's shard plan: the DAA score, eligible keys, the epoch seed, the assignments |
|
||||
| `igneum_getProofRecords` | the proof records a block carries and claims |
|
||||
| `igneum_getTransactionStatus` | per transaction: in the mempool, included in, executed, locked |
|
||||
| `igneum_estimateGas` | both gas dimensions, the base fee, and `exceedsProvingLimit` |
|
||||
| `igneum_getBudgets` | the proving budgets: backlog depth, the base fee, chain blocks |
|
||||
| `igneum_getAssignedShards` | the shards assigned to this node's prover |
|
||||
| `igneum_getSegment`, `igneum_getSegmentRecords`, `igneum_getSegmentStatement` | a segment's executed blocks, records and statement |
|
||||
| `igneum_getSegmentProofBytes`, `igneum_getProofBytes` | the proof bytes for a key hash (`keyHash` is required) |
|
||||
| `igneum_exportSegments` | a range of segments with their accounts |
|
||||
| `igneum_exportExecSnapshot` | writes a snapshot to a path on the node's own disk |
|
||||
| `igneum_submitProofRecord`, `igneum_submitSegmentRecord` | the prover's submissions; a record is required |
|
||||
|
||||
## Not served
|
||||
|
||||
Each of these answered `-32601` on 8 October 2026. Where a tool wants one, the note says what to do instead.
|
||||
|
||||
| Method | Instead |
|
||||
|---|---|
|
||||
| `eth_newFilter`, `eth_newBlockFilter`, `eth_newPendingTransactionFilter`, `eth_getFilterChanges`, `eth_getFilterLogs`, `eth_uninstallFilter` | poll `eth_blockNumber` and `eth_getLogs` |
|
||||
| `eth_subscribe`, `eth_unsubscribe` | no WebSocket subscriptions; poll |
|
||||
| `eth_sendTransaction`, `eth_sign`, `eth_signTransaction` | the node holds no keys; sign on your side and use `eth_sendRawTransaction` |
|
||||
| `eth_getProof` | not yet |
|
||||
| `eth_getTransactionByBlockHashAndIndex`, `eth_getBlockTransactionCountByHash` | use the by-number forms |
|
||||
| `eth_getUncleByBlockHashAndIndex`, `eth_getUncleByBlockNumberAndIndex`, `eth_getUncleCountByBlockHash`, `eth_getUncleCountByBlockNumber` | there are no uncles; the DAG's merged blocks are not EVM blocks |
|
||||
| `eth_createAccessList`, `eth_simulateV1`, `eth_blobBaseFee` | not yet; no blobs |
|
||||
| `eth_coinbase`, `eth_hashrate` | the miner's, not the node's |
|
||||
| `txpool_content`, `txpool_status` | `igneum_getTransactionStatus` for one transaction |
|
||||
| `debug_traceTransaction`, `debug_traceBlockByNumber`, `trace_block` | no tracing yet |
|
||||
| `web3_sha3` | hash on your side |
|
||||
|
||||
## The probe
|
||||
|
||||
Every method with a harmless argument; the verdict is `served`, `not-found` (`-32601`) or `error` (the node knows the method and refused the argument, which counts as served).
|
||||
|
||||
```
|
||||
URL=http://127.0.0.1:26790
|
||||
call() { curl -s -X POST -H 'content-type: application/json' \
|
||||
--data "{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"$1\",\"params\":${2:-[]}}" "$URL"; }
|
||||
for m in web3_clientVersion eth_chainId eth_blockNumber eth_newFilter eth_subscribe; do
|
||||
printf '%-32s %s\n' "$m" "$(call $m | cut -c1-80)"
|
||||
done
|
||||
```
|
||||
|
||||
Devnet 3 resets without notice and its coins have no value.
|
||||
34
docs/build/verify-a-block.md
vendored
Normal file
34
docs/build/verify-a-block.md
vendored
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
# Verify a block in your browser
|
||||
|
||||
Igneum's finality is a certificate: miners sign a checkpoint every 30 seconds, and when two thirds of the 30-day mining weight have signed, it is locked. A browser can check that certificate by itself. The site ships the verifier: `site/verify/core.js` does the work, `site/verify/verify.js` fetches the data and calls it.
|
||||
|
||||
## Twelve lines
|
||||
|
||||
```
|
||||
<script type="module">
|
||||
import { fetchCheckpoint, verify } from 'https://igneum.network/verify/verify.js';
|
||||
const data = await fetchCheckpoint('https://igneum.network/api/checkpoint');
|
||||
const r = verify(data);
|
||||
console.log(r.verified ? 'verified' : 'not verified', r.reason || '');
|
||||
console.log(`checkpoint ${r.index} on ${r.network}, block ${r.hash.slice(0, 12)}`);
|
||||
console.log(`${r.signers} of ${r.voters} voters signed`);
|
||||
console.log(`${(r.weight_fraction_total * 100).toFixed(1)}% of total weight`);
|
||||
console.log(`${r.headers_checked} headers checked in ${r.ms} ms`);
|
||||
</script>
|
||||
```
|
||||
|
||||
## What is checked, in the tab
|
||||
|
||||
1. The header chain from the previous locked checkpoint to this one: each header's hash is recomputed and each links to its parent.
|
||||
2. The voter table: each voter's key hash, and the weights the bitmap selects.
|
||||
3. The BLS aggregate signature over the checkpoint message, against the aggregated public keys of the signers, and that the signed weight reaches two thirds of the total.
|
||||
|
||||
Nothing is trusted from the server but the data itself. Change one bit of the signature, drop one signer from the bitmap, alter a header's nonce, and `verify` says `false` with the reason. The live run of exactly those cases is [igneum.network/verify/test.html](https://igneum.network/verify/test.html).
|
||||
|
||||
## The data
|
||||
|
||||
`GET /api/checkpoint` returns the latest certified checkpoint: the certificate as carried in a block, the voter list with public keys and weights, and the selected-chain headers from the previous lock. `?source=test` returns the finality test network's instead. Libraries, pinned: BLAKE2b from `@noble/hashes` 2.4.0 and BLS12-381 from `@noble/curves` 2.4.0, pure JavaScript.
|
||||
|
||||
## From a node
|
||||
|
||||
The same certificate is in the block that carries it, and `igneum_getProofRecords` returns a block's records. A light client that reads blocks from a node instead of the site's API verifies the same way; `core.js` has no dependency on the site.
|
||||
24
docs/contracts/devnet-3.json
Normal file
24
docs/contracts/devnet-3.json
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
{
|
||||
"network": "igneum-devnet-3",
|
||||
"chain_id": 4463,
|
||||
"chain_id_hex": "0x116f",
|
||||
"note": "Devnet 3, test tokens, no value. The chain may reset; these addresses go with it.",
|
||||
"rpc": "https://rpc.devnet.igneum.network",
|
||||
"deployed_at": "2026-10-08T10:50:00Z",
|
||||
"deployer": "0x07DD4DBca5c1a66755AF28BACCA1D901a2D209aA",
|
||||
"source": "contracts/dex (Foundry, solc 0.8.28, evm_version paris, optimizer 200 runs)",
|
||||
"contracts": {
|
||||
"WIGN": { "address": "0x47447783D00e1760Eb815a34707b611D53f2A51e", "tx": "0x9fc48e0e3aa6ccdc41ff72381e1986d617722e22cd2b5f0f9f1e988eef60b2d6", "block": 26917 },
|
||||
"TTA": { "address": "0x9ad4F0435f9172A89C6765eE8631CAB2Db3B5052", "tx": "0xa16b6a6501d2705b7c7dc4cf01f8b65b87270e5f1f90b4638b19f120b4830dc0", "block": 26919, "name": "Test Token A", "faucet": "drip() mints 1,000 TTA to the caller once an hour" },
|
||||
"TTB": { "address": "0x996e3042089E80029348d7836472DB34C21841c1", "tx": "0x63eca8238d7f2c29e67c5aad33b0f1cb341d233f2ae0922621e4ba09d94eca61", "block": 26921, "name": "Test Token B", "faucet": "drip() mints 1,000 TTB to the caller once an hour" },
|
||||
"IgneumFactory": { "address": "0x09FF42dbb20448ddB673fD34F973a7D93E7139A8", "tx": "0xd25223b5f1adcba415e51a0936c1ba3e9ae1dcbb1299ec5c4a91293e41ace3bb", "block": 26923 },
|
||||
"IgneumRouter": { "address": "0x9a6fA842C4e58A87AEF1F3aD15233d99283002B7", "tx": "0xabce2fcac81f87fdca02ac4528d4029ebbe1e6d49304dbe6427e1320f2e17b27", "block": 26924 }
|
||||
},
|
||||
"pairs": {
|
||||
"TTA_WIGN": { "address": "0x5352Fc2723014Bb45A5b1767Df549DA755773A2B", "seeded": "500 TTA beside 100 IGN", "block": 26969 },
|
||||
"TTB_WIGN": { "address": "0x93Db70744e200D647f783C3953dF35d7394EdBC5", "seeded": "500 TTB beside 100 IGN", "block": 26970 },
|
||||
"TTA_TTB": { "address": "0xF35775db56dE4f1Cd8Ed7ea7CAb8D017d584a96F", "seeded": "500 TTA beside 500 TTB", "block": 26972 }
|
||||
},
|
||||
"fee": "0.3 percent per swap, kept in the pool",
|
||||
"gas_note": "Devnet 3 charges the proving dimension inside the execution gas: a local EVM estimate runs out (drip() failed at 133,603 gas in block 26925; the node's eth_estimateGas said 685,513). Send with the node's own estimate (forge script --skip-simulation, or eth_estimateGas before every send)."
|
||||
}
|
||||
42
docs/contracts/sepolia.json
Normal file
42
docs/contracts/sepolia.json
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
{
|
||||
"network": "ethereum-sepolia",
|
||||
"chain_id": 11155111,
|
||||
"note": "The Igneum light-client bridge primitive: a verifier for Devnet 3 finality certificates and Ethereum account proofs. Devnet 3, test tokens, no value; Sepolia, test ether, no value. What it proves and what it does not: docs/bridge/light-client-bridge.md.",
|
||||
"rpc": "https://ethereum-sepolia-rpc.publicnode.com",
|
||||
"deployed_at": "2026-10-08T12:36:00Z",
|
||||
"deployer": "0x0C896A191D6b76c37d704454b35B2D61276b7471",
|
||||
"source": "contracts/bridge (Foundry, solc 0.8.28, evm_version osaka, via-IR, optimizer 200 runs)",
|
||||
"contracts": {
|
||||
"IgneumCertificateVerifier": {
|
||||
"address": "0xAf74f3F512081291D663Bb1d6b6d37E99e37D744",
|
||||
"create_tx": "0x55351cbbccda0f78311c22feb1174d99c5d8d9fe3488cb60ff8656f65007e079",
|
||||
"create_block": 11869731,
|
||||
"igneum_chain_id": "igneum-devnet-3",
|
||||
"table": {
|
||||
"tx": "0x6ec1045dbc0abe981944e9e15987089d3f0cdc2e8e467f688b7b0c63e907b26b",
|
||||
"block": 11869732,
|
||||
"index": 2127,
|
||||
"voters": 29,
|
||||
"total_weight": 7164,
|
||||
"table_id": "0xabfcc2bc54ca92ec506beee8a44dced17f15cf1e7c518a6221bf2819b0d1cbd6",
|
||||
"read_from": "igneum_getFinalityWeights on a Devnet 3 node at checkpoint index 2127 (hash 0xcb21b52c\u2026), 12:1x UTC 8 October 2026"
|
||||
},
|
||||
"final_checkpoints": [
|
||||
{
|
||||
"index": 2127,
|
||||
"checkpoint": "0xcb21b52c18654542e7e66af82898313282fd6881e44d01c448d3ba2bd1abd544",
|
||||
"tx": "0x569a62c155f2273bc2167afc137bc9a44bfe522bf21f7554500c2045add444fc",
|
||||
"block": 11869773,
|
||||
"gas_used": 765514,
|
||||
"signers": 17,
|
||||
"signed_weight_under_table": 4833,
|
||||
"total_weight": 7164,
|
||||
"source": "igneum.network/api/checkpoint?index=2127 (dn3_live_certificates), the bytes the chain carried; verified by eth_call before the send (true, 4833, 7164)"
|
||||
}
|
||||
],
|
||||
"interface": "IIgneumCertificateVerifier in contracts/bridge/src/IgneumCertificateVerifier.sol: chainId(), tableId(), verifyCertificate(uint64 index, bytes32 checkpoint, bytes bitmap, bytes signature) view returns (bool ok, uint256 signedWeight, uint256 totalWeight), submitCertificate(...), finalCheckpoint(uint64) view returns (bytes32), isFinal(bytes32) view returns (bool), verifyAccount(bytes32 stateRoot, address account, bytes[] proof) pure returns (bool exists, uint256 nonce, uint256 balance, bytes32 storageRoot, bytes32 codeHash)"
|
||||
}
|
||||
},
|
||||
"first_deploy_note": "A first creation at 0xD7dd375E14F92A4CE4782040325189e6d6E394b6 (tx 0x4db10565\u2026, block 11869633) ran out of gas at Foundry's Prague-spec estimate of 3,323,884; Sepolia runs Osaka pricing (EIP-7883 modexp), so the test EVM and the deploy now use osaka and the RPC's own estimate. That address holds no code.",
|
||||
"tests": "contracts/bridge/test/Verifier.t.sol: 9 of 9 green on build-3 (Foundry, osaka), 12:3x UTC 8 October 2026; the live contract verified and recorded Devnet 3 checkpoint 2127 at 12:5x UTC"
|
||||
}
|
||||
|
|
@ -41,8 +41,8 @@ Versions in the table: `igneum-pow` is the Rust crate at `igneum-pow/Cargo.toml`
|
|||
| 14 | Ethereum bytecode runs unchanged, with the documented differences of spec 7.1 | Homepage Build card; litepaper Building | tested by the team | as row 13; fixes `F-exec-A`, `F-exec-B` (spec 7.5) | `tools/evm-smoke/smoke.mjs`: deploy via viem, `increment`, `hashLoop`, `eth_estimateGas`, `eth_getLogs`; `tools/exec-attacks` scenarios 1 and 3; bench-log "execution layer attack fixes" | Deployment, calls, reverts, logs and gas estimates behave as viem expects; chain id 4463; the prototype pgas table gives 0.0095 to 0.028 pgas per gas, below the design's band before calibration, 3 October 2026. 4 October 2026: a transaction that would cross the block's proving budget is refused by the mempool and, if forced in, aborted and charged with its nonce advanced (25 of 25 checks; 30 of 30 malformed cases). Apple M5 Max. The `Prover` precompile, proof records and the shard planner are not in the node | none yet |
|
||||
| 15 | Every block is proven, with the proof landing within about a minute at launch | Homepage stats ("~60 s to a proof"); litepaper Proving; roadmap phase 3 gate | implemented | repo `d7e1f89` (GPU proof), `e01a3cc`, `292e800`, `eedd136` (`proving/igneum-prove`: shard cutter, MPT witnesses, shard and aggregator guests); SP1 6.8.1; spec 7.2, 7.6 | `proving/windows-wsl2` (SETUP-PROVER, PROVE-BLOCK) on the RTX 5090; `igneum-prove-host --mode block` on `proving/fixtures/`; bench-log "proving v0 on the RTX 5090" and "proving: devnet v4 shards" | First GPU proof of an Igneum block, 4 October 2026, RTX 5090 (WSL2, SP1 cuda, mining paused): fixture `block-78-increment` (2 transactions), core proof 1.4 s (7.3 MB, verify 0.221 s), compressed proof 2.7 s (1.27 MB, verify 0.038 s), post-state and receipts roots identical to the node's; 15.7x and 20.6x faster than a loaded M5 Max CPU. The same day on that CPU (load 38 to 47): a three-shard block proved shard by shard and aggregated by recursion, 19 min (1,139 s) end to end, 245 to 337 s per compressed shard proof, every proof verified. What is not there: no proof is produced, carried or checked on the chain (the devnet prover is a stub that signs claims), the proving pool pays nobody (row 21), the block proven is far below one shard, and the 60-second figure remains a design target; the pass mark is the standard in `docs/benchmarks/proving-e2e.md`. Second RTX 5090 run, 4 October 2026 evening (job run-20261004-173115): a full shard at the provisional S_p (6.75 M pgas, 60.8 M cycles) executed in 1.63 s, core proof 8.3 s (18.1 MB), compressed proof 10.9 s (1.27 MB, verify 0.040 s); a two-shard block (13.5 M pgas) proved shard by shard (11.7 s and 10.0 s) and aggregated in 2.2 s, 24 s of GPU stages end to end, every proof verified, six tampered witnesses rejected. The two host defects (an abort after the upload, an idle wait that turned out to be an unbuffered 18 MB proof save through the WSL2 file bridge, 24 minutes) are fixed (ledger P20) 5 October 2026, live devnet with real transactions (bench-log "real transactions, the first non-empty shard proven and paid"): block 72704 shard 0, 29 transfers, 5,800 pgas, proven on PC 2 in 34 s, verified on the Mac in 0.297 s and paid 1.7623 IGN, 53 s after the chain block executed; of about 1,400 blocks in the 20-minute window 36 were proven (the one prover takes the newest shard assigned to it), so "every block" is not yet true; a second content shard (72803, all copies skipped) failed the native-execution veto on the exporter's block structure, fixed with fixtures the same day, the node side pending the 0.3.9 rollout 5 October 2026, evening (bench-log "proving v1"): the aggregated segment record, the chain rule and the unproven rule are implemented behind `proving_v1_activation_daa` (branch proving-v1, not on the devnet before 0.3.11); on the RTX 5090 a chain of 8 consecutive live blocks proved and aggregated by recursion in 135.6 s with the miner on the card (17 s a block, one proof of 1,272,909 bytes attesting all 8, verified in 0.04 s); the 3-node fast-time harness paid a segment record 1.0 s after submission and refused a late one after its deadline (21 checks); the devnet itself, with one prover, carried proofs for 2.4% of blocks over 30 minutes at a block-to-record latency p50 44 s, p99 52 s. The "within about a minute" holds per proven block; "every block" needs 18 mining 5090s or 6 proving-only cards at empty blocks on the measured rates, and the mandatory rule stays off until the share is one | none yet |
|
||||
| 16 | A 12 GB card proves one shard in about 20 s (WITHDRAWN 5 October 2026: a 24 GB card proves a full shard at the adopted size in 4.3 s; 32 GB mines and proves) | Litepaper Proving ("The proving budget"); roadmap gate 2 | designed | spec 5.1 (Target), 7.6 (`S_p` provisional, 7,500,000 pgas = `B_p` / 4) | `PROVE-SHARD.bat` on the RTX 5090 (pending); the end-to-end standard in `docs/benchmarks/proving-e2e.md`; bench-log "proving: devnet v4 shards" | Measured on a 32 GB card, not yet on a 12 GB card. A shard at the provisional `S_p` is 60.8 M SP1 cycles on the prototype pgas table (9 cycles per pgas, 44 per EVM gas; the modexp entry about 100x its SP1 cost); on an RTX 5090 (4 October 2026 evening, job run-20261004-173115) it executed in 1.63 s and its compressed proof took 10.9 s, verified in 0.040 s, so the 32 GB card is inside the 20 s target with margin. Whether a 12 GB card proves it at all, and in what time, is the next measurement (an RTX 3060 and an RTX 5060 Ti 16 GB are on order). A per-shard time can be met by shrinking the shard, so the project does not use it as a pass mark 5 October 2026, evening (bench-log "proving v1", the S_p curve): measured on the RTX 5090 with SP1 6.8.1's GPU prover, the card to itself, 1-s nvidia-smi samples: an empty shard 13,874 MiB and 2.2 s; a full shard at the ADOPTED v1 budget (30,000 pgas, 4.7 M cycles) 20,434 MiB and 4.3 s; the full prototype shard (6.75 M pgas, 60 M cycles) 28,307 MiB and 10.8 s; beside the miner 15,670 and 30,039 MiB. No environment knob of SP1 moves the 13.9 GB floor and the GPU server has no options of its own, so on this build a 12 GB card proves nothing, a 16 GB card only empty shards, a 24 GB card the adopted full shard alone and beside the miner (22,210 MiB and 13.2 s, measured on the 32 GB card: the 5090's allocation pattern, not yet a run on a 24 GB card) and a 32 GB card the prototype shard beside the miner with 2.5 GB spare. The litepaper line now says so; the 12 GB gate returns when a prover build with a smaller floor is measured on a 12 GB card | none yet |
|
||||
| 17 | The chip resistance claim: at launch the strongest chip in the public model reaches 2.1x (a core as good as a GPU lane, k = 1) to 3.4x (a core three times better, k about 0.33) per joule against an RTX 5090 under class v4, live from genesis on the testnet and the mainnet; the ladder's second rung brings it to about 2.8x; class v5 makes the dataset the chain's state so a stateless or stale chip is wrong on every item; the hot-set cache is bounded at 1.067x at the ceiling and the weak-day FPGA at 12 percent on 15 days a century, both routed to the next class; datacentre silicon does not change the question; a stored-dataset chip pays for itself only at about USD 100 M of market cap in two years; without class v4 the same chip would reach 5x to 9x (the class v3 baseline, the devnet's starting state, never the launch state) | the home page's chip line, the litepaper's chip section (/litepaper#chip-model), the miner page's line | tested by the team (every card, the verifier, the two attack-pass bounds, the H100), the chip itself modelled, class v5 and the ladder designed, the X9 figure claimed against a CPU core and never measured | `docs/analysis/chip-model-v3.md` 5 and 6; `docs/analysis/latency-shadow-2026-10-06.md`; `docs/plans/counter-asic-3-status.md`; `docs/analysis/attack-pass/f8-uniform.md`, `f4-weakday.md`, `docs/analysis/ca3-v4-uniform.md`; `docs/design/class-v5-stored-state.md`; the H100 and market-cap rows of 7 October; `docs/plans/cryptanalysis/in-house-pass.md` (the internal adversarial pass) | the chip model's arithmetic in its file; the card rows by the benchmark package; the attack-pass harnesses `tools/attack/f8-uniform` and the F4 census; the verifier by `igneum-pow bench` | 136 MH/s at 350 W (5090, bench) and 290 W (app); the class v4 efficiency passes (bench log "7 to 8 October 2026, the class v4 efficiency passes: the core clock lock on the RTX 5090 and the RTX 5080", measured): the 5090 at 136.84 MH/s and 475.5 W unlocked, 134.98 at 316.3 W at a 1,400 MHz core lock, the best points class v4 at 1,200 MHz (133.80 MH/s, 305.1 W, 0.439 MH/W) and class v3 at 1,300 MHz (134.62, 223.3 W, 0.603), the premium 145 W unlocked and 82 W at the best points, the knee 1,300 MHz; the RTX 5080 (8 October 2026, the dock card of the three-card Windows rig) at 71.41 MH/s and 253.1 W unlocked under class v4 against 71.28 at 169.7 W under class v3, the best points class v4 at 1,100 MHz (71.20 MH/s, 146.6 W, 0.486 MH/W) and class v3 at 1,000 MHz (71.11, 103.7 W, 0.686), the premium 83.4 W unlocked and 41 W at the best points, the knee between 1,000 and 900 MHz; per tier: a 5080 owner on class v4 locked near 1,100 MHz pays 147 W instead of 253 for 0.3 percent less rate, MH per watt up 72 percent, the lever Ember Tune's core-clock knob in 0.3.24; 27 MH/s at 21 W (M5 Max); 249 MH/s (H100 SXM) at 98 percent of its read ceiling, 1.78x hash, 1.15x MH/W, a third per rented dollar; 2.33 ms per warp; 2.1x, 3.4x, 2.8x at launch; the shadow's premium on a 5090 81.8 W at its knee (class v4 at the 1,200 MHz lock 133.80 MH/s at 305.1 W; class v3 at 1,300 MHz 134.62 at 223.3 W; 7 October 2026); 1.067x at the ceiling; 12 percent on 15 days a century; 10.85 ms at rung 3; USD 100 M; 5.1x to 9.2x the class v3 baseline; 6 and 7 October 2026, the M5 Max, PC 2's RTX 5090, PC 1's RX 9070 XT and RTX 4070, a rented H100 SXM, igneum-build-1 The k about 0.33 bound is the implied core of Bitmain's Antminer X9 (RandomX; 1,000 KH/s, 2,472 W, 2.47 J per KH, USD 5,600; pre-orders 26 December 2025), withdrawn in mid-May 2026 with buyers refunded before any unit shipped, no independent benchmark, commodity Sophgo SG2044 server SoCs with an AES accelerator, no tapeout: a claimed, unmeasured figure carried as the pessimistic bound, not a calibration point (attack pass AP-F5-1, 7 October 2026). | none yet; the next test is the internal adversarial pass (three lanes new to the hash code, outsider inputs only, reports published whole), and no outside review has run yet |
|
||||
| 18 | The chip resistance measurements: the program is latency-bound (random reads), not bandwidth-bound, on every card we own, and sits beyond a card's on-chip cache | Litepaper Mining ("waits on memory latency, not on maths or bandwidth"), vs RandomX; the numbers page | tested by the team | readwidth e752fc7 (`docs/plans/read-width.md`), ca2-era 78c0ee4, ca2-cache 2de19e5 (`docs/plans/hot-table.md`) | The dependent-read probes at 32 to 1,024 MiB and the hash rate per class on the three cards; the latency-bound share = rate over the probe ceiling per load | Latency-bound share at the 1 GiB dataset: RTX 5090 0.96 (v2) and 1.01 (v3), RX 9070 XT 0.87 and 0.95, M5 Max 1.01 and 1.06; wider reads do not close the AMD gap (the 9070 XT does 2.4 G dependent reads per second at every width; the 5090 goes bandwidth-bound at 64 B, share 0.58); a 32 to 96 MiB hot table is not kept resident by any card while the dataset streams (g 0.80 to 0.87 in the added form). 5 October 2026 | none yet |
|
||||
| 17 | The chip resistance claim: at launch the strongest chip in the public model reaches 2.1x (a core as good as a GPU lane, k = 1) to 3.4x (a core three times better, k about 0.33) per joule against an RTX 5090 under class v4, live from genesis on the testnet and the mainnet; the ladder's second rung brings it to about 2.8x; class v5 makes the dataset the chain's state so a stateless or stale chip is wrong on every item; the hot-set cache is bounded at 1.067x at the ceiling and the weak-day FPGA at 12 percent on 15 days a century, both routed to the next class; datacentre silicon does not change the question; a stored-dataset chip pays for itself only at about USD 100 M of market cap in two years; without class v4 the same chip would reach 5x to 9x (the class v3 baseline, the devnet's starting state, never the launch state) | the home page's chip line, the litepaper's chip section (/litepaper#chip-model), the miner page's line | tested by the team (every card, the verifier, the two attack-pass bounds, the H100), the chip itself modelled, class v5 and the ladder designed, the X9 figure claimed against a CPU core and never measured | `docs/analysis/chip-model-v3.md` 5 and 6; `docs/analysis/latency-shadow-2026-10-06.md`; `docs/plans/counter-asic-3-status.md`; `docs/analysis/attack-pass/f8-uniform.md`, `f4-weakday.md`, `docs/analysis/ca3-v4-uniform.md`; `docs/design/class-v5-stored-state.md`; the H100 and market-cap rows of 7 October; `docs/plans/cryptanalysis/in-house-pass.md` (the internal adversarial pass) | the chip model's arithmetic in its file; the card rows by the benchmark package; the attack-pass harnesses `tools/attack/f8-uniform` and the F4 census; the verifier by `igneum-pow bench` | 136 MH/s at 350 W (5090, bench) and 290 W (app); the class v4 efficiency passes (bench log "7 to 8 October 2026, the class v4 efficiency passes: the core clock lock on the RTX 5090 and the RTX 5080", measured): the 5090 at 136.84 MH/s and 475.5 W unlocked, 134.98 at 316.3 W at a 1,400 MHz core lock, the best points class v4 at 1,200 MHz (133.80 MH/s, 305.1 W, 0.439 MH/W) and class v3 at 1,300 MHz (134.62, 223.3 W, 0.603), the premium 145 W unlocked and 82 W at the best points, the knee 1,300 MHz; the RTX 5080 (8 October 2026, the dock card of the three-card Windows rig) at 71.41 MH/s and 253.1 W unlocked under class v4 against 71.28 at 169.7 W under class v3, the best points class v4 at 1,100 MHz (71.20 MH/s, 146.6 W, 0.486 MH/W) and class v3 at 1,000 MHz (71.11, 103.7 W, 0.686), the premium 83.4 W unlocked and 41 W at the best points, the knee between 1,000 and 900 MHz; per tier: a 5080 owner on class v4 locked near 1,100 MHz pays 147 W instead of 253 for 0.3 percent less rate, MH per watt up 72 percent, the lever Ember Tune's core-clock knob in 0.3.24; 27 MH/s at 21 W (M5 Max); 249 MH/s (H100 SXM) at 98 percent of its read ceiling, 1.78x hash, 1.15x MH/W, a third per rented dollar; 2.33 ms per warp; 2.1x, 3.4x, 2.8x at launch; the shadow's premium on a 5090 81.8 W at its knee (class v4 at the 1,200 MHz lock 133.80 MH/s at 305.1 W; class v3 at 1,300 MHz 134.62 at 223.3 W; 7 October 2026); 1.067x at the ceiling; 12 percent on 15 days a century; 10.85 ms at rung 3; USD 100 M; 5.1x to 9.2x the class v3 baseline; 6 and 7 October 2026, the M5 Max, PC 2's RTX 5090, PC 1's RX 9070 XT and RTX 4070, a rented H100 SXM, igneum-build-1 The k about 0.33 bound is the implied core of Bitmain's Antminer X9 (RandomX; 1,000 KH/s, 2,472 W, 2.47 J per KH, USD 5,600; pre-orders 26 December 2025), withdrawn in mid-May 2026 with buyers refunded before any unit shipped, no independent benchmark, commodity Sophgo SG2044 server SoCs with an AES accelerator, no tapeout: a claimed, unmeasured figure carried as the pessimistic bound, not a calibration point (attack pass AP-F5-1, 7 October 2026). | none yet; the next test is the internal adversarial pass (three lanes new to the hash code, outsider inputs only, reports published whole), whose floor reading is in (measured, 8 October 2026; ledger AP-F8-1 and AP-F8-6): nine of nine hot sets refused; the diffuse era-stride excess, bounded under 0.1 percent of a hash's reads per site, is not caught by the floor and is the next class's test, and no outside review has run yet |
|
||||
| 18 | The chip resistance measurements: the program is latency-bound (dependent reads spread over the whole dataset), not bandwidth-bound, on every card we own, and sits beyond a card's on-chip cache; measured 8 October 2026: the distinct-index floor holds at 0.995 on every accepted program, about half of epochs carry one load site with a biased address bit at the era's stride rotation, priced at about 1.6 percent of a hash's reads to a chip storing half the dataset and nothing to one storing all of it (`docs/analysis/class-v6/family-gate.md`, lane D; adv-cache-2's `report-chained-cache-2.md` section 2.3 on its branch; ledger AP-F8-7) | Litepaper Mining ("waits on memory latency, not on maths or bandwidth"), vs RandomX; the numbers page | tested by the team | readwidth e752fc7 (`docs/plans/read-width.md`), ca2-era 78c0ee4, ca2-cache 2de19e5 (`docs/plans/hot-table.md`) | The dependent-read probes at 32 to 1,024 MiB and the hash rate per class on the three cards; the latency-bound share = rate over the probe ceiling per load | Latency-bound share at the 1 GiB dataset: RTX 5090 0.96 (v2) and 1.01 (v3), RX 9070 XT 0.87 and 0.95, M5 Max 1.01 and 1.06; wider reads do not close the AMD gap (the 9070 XT does 2.4 G dependent reads per second at every width; the 5090 goes bandwidth-bound at 64 B, share 0.58); a 32 to 96 MiB hot table is not kept resident by any card while the dataset streams (g 0.80 to 0.87 in the added form). 5 October 2026 | none yet |
|
||||
| 19 | The lottery hash is sound as a hash: uniform output, deterministic, no out-of-bounds read, fuzzed; class v3 bit-exact on the three vendors | Litepaper vs RandomX ("Every number above is measured and logged"), the numbers page | tested by the team | ca2-mixer 1ab8b21 (`tests/mixer.rs`, `tests/scratch.rs`), ca2-era 78c0ee4, ca2-soundness a465881 (`docs/analysis/scratch-soundness.md`), `igneum-pow/tests/packs.rs` | The crate suite (53 + 4 + 19 + 7), the Metal fuzz, edge, stats and determinism runs on the v3 construction, the pack vectors and 2^24 fingerprints on Metal, Apple OpenCL, the RTX 5090 and the RX 9070 XT, the 1,024-hash CPU re-check per card | Class v3 (mixer x8 + era): 200-program fuzz 200 of 200 on Metal, every tenth on Apple OpenCL; the pinned v3 packs 3/3 + 3/3 and 96 of 96 lanes on Metal and Apple OpenCL; the six era packs' fingerprints equal on the three vendors (PC 1 job run-ca2-era-pc1-20261005, 5 October 2026); the v2 exports byte-identical on the v3 crate; the final-class PC rows and the G2 re-check: job run-ca2-era-pc1b-20261005 (pending at the time of writing) | none yet |
|
||||
| 20 | No premine, no pre-sale, no allocation: every coin is minted by the schedule and every coin goes to the block producer (80%) and the proving pool (20%) | Homepage stats and Economics tiles; litepaper Supply, Economics | implemented | repo `6ac80a3`; fork "igneum-node devnet v0"; `consensus/core/src/igneum.rs`, `coinbase.rs` | `cargo test -p kaspa-consensus-core igneum` (8 pass: subsidy table, ramp, split, cap) and `cargo test -p kaspa-consensus coinbase` (8 pass); `igneum-miner inspect 40`; bench-log "igneum-node devnet v0" | Coinbases on the devnet: 80/20 exact on 39 of 39 single-payee blocks, the 20% to the `igneum-proving-pool-v0` output; the per-second schedule sums to under the 4,000,000,000 cap by less than 100 coins; 3,168,808,781 units per DAA second in years 0 to 2, halving at 63,115,200 DAA s. 3 October 2026, Apple M5 Max. The devnet genesis carries no allocation; the mainnet genesis does not exist yet, so the claim is about the code and the stated rule, not a launch that has happened | none yet |
|
||||
| 21 | The proving pool's 20% reaches shard provers and aggregators | Litepaper Economics; homepage "20% provers" | tested by the team | spec 5.3; `proving/igneum-prove` carries the prover's payout address in every shard proof (ledger P12) | None. The pool output exists (row 20); the payout from it against proof records is unwritten. Since 5 October 2026: the payout rule is live on the devnet (`proving.rs shard_payouts`, the carrying segment pays the first valid record per shard its part of the segment's pool credit) | The escrow accumulated on the simnet (92.55 IGN at the end of the v3 run) and nothing can draw it. Rule decided: per block, divided among shards by consensus proving cost, sortition to 8 provers for 10 s then open (spec 7.2). The economy model of 4 October 2026 (`sim/economy`, 1,000 operators, 30 days) kept every block proven within 60 s under six stress scenarios; a model, not hardware Live devnet, 5 October 2026: 388 shards paid by 16:02 UTC, 446.13 IGN from the pool to PC 2's payout address, 0.8813 IGN per mergeset block of the proven segment (bench-log entries of 5 October: "the first shards proven, verified and paid" and "real transactions, the first non-empty shard proven and paid") | none yet |
|
||||
|
|
|
|||
|
|
@ -715,7 +715,7 @@ Evidence: litepaper "For miners", hardware paragraph. Wording: overclaims list,
|
|||
### C2. vs Monero: "no chip in seven years" is not proof
|
||||
"Absence of a public RandomX ASIC is not evidence one cannot exist. Monero is also a small prize."
|
||||
|
||||
Status: Conceded, stated; reopened as conceded (7 October 2026, morning, X36): the X9 never shipped, so Monero's record is again seven years without a shipped chip, and the concession stands as first written; the litepaper says so in the same sentences.
|
||||
Status: Conceded, stated; corrected (8 October 2026, lane A's history): Monero's record is about seven years with one shipped chip, the Antminer X5 at 1.46x per joule over a desktop CPU, not seven years without one; the concession stands and the litepaper's sentences say so (`docs/analysis/class-v6/history.md` 2.3). Was: Conceded, stated; reopened as conceded (7 October 2026, morning, X36): the X9 never shipped, so Monero's record is again seven years without a shipped chip, and the concession stands as first written; the litepaper says so in the same sentences.
|
||||
|
||||
Status: Conceded, stated (7 October 2026, morning): the one-screen home page is back on the owner's word, so this row is stated on `site/litepaper.html` only; the sentence there is unchanged and the text check lists it under the litepaper.
|
||||
|
||||
|
|
@ -2307,7 +2307,7 @@ Evidence: `site/litepaper.html`; `docs/plans/testnet-go.md`; X31, X32.
|
|||
### X34. RandomX described as chip-free
|
||||
"The home page said the random program 'has kept chips off Monero since 2019', the litepaper said Monero ran on RandomX 'with no chip publicly shipped' and spoke of 'Monero's seven years without a public chip'. Bitmain's Antminer X9, a RandomX chip, ships from July 2026 (1 MH/s at 2,472 W, about USD 5,600; monero-project/monero issue 10270), and RandomX 2.0 shipped on 25 March 2026. Every sentence that said or implied RandomX is chip-free, or that Monero's approach has held, was wrong."
|
||||
|
||||
Status: Fixed, stated; corrected (7 October 2026, morning, X36): the X9 never shipped. Bitmain opened pre-orders on 26 December 2025 and withdrew the product in mid-May 2026 before any unit was delivered; every sentence below that had it shipping now states that, and RandomX stands as a technique no chip has yet shipped against. The sentences in this row are the history.
|
||||
Status: Fixed, stated; corrected again (8 October 2026, lane A's history, `docs/analysis/class-v6/history.md` 2.3): one chip did ship against RandomX, Bitmain's Antminer X5 (announced 27 August 2023, shipped September 2023), a board of RISC-V chips at 1.46x per joule over a Ryzen 9 7950X, on silicon SChernykh believes mined privately from about 2021; RandomX v2 was released on 25 March 2026 with its mainnet activation pending (PR 10038); the X9 was withdrawn in mid-May 2026 with zero units. Every served sentence that said "no chip shipped" or "seven years without a shipped chip" now carries the X5 and the v2 release (litepaper precedents row, the chip-model paragraph, the vs RandomX section and its track-record row; /claims and /randomx follow from it); the X36 sentence on the X9 stands. Was: Fixed, stated; corrected (7 October 2026, morning, X36): the X9 never shipped. Bitmain opened pre-orders on 26 December 2025 and withdrew the product in mid-May 2026 before any unit was delivered; every sentence below that had it shipping now states that, and RandomX stands as a technique no chip has yet shipped against. The sentences in this row are the history.
|
||||
|
||||
Status: Fixed, stated (7 October 2026, morning): the one-screen home page carries no RandomX sentence, so the corrected wording stands on `site/litepaper.html` (four sentences and the table row); the text check lists them there.
|
||||
|
||||
|
|
@ -2506,13 +2506,15 @@ The second sub-version 3 commit is 017e70376489251e18564c0abce7e466e606c8b3 (pus
|
|||
|
||||
F8's 64-seed gate on 017e7037 (the attack-pass lane, box 2, last seed 16:00:20 UTC): 60 of 64 under 1.2x; the four over are the named tail and nothing else (p10 1.5036x, p8 1.3776x, p34 1.2505x, p4 1.2167x; hottest items 355 to 541 reads of 2^31, unattributed, inside the ratio's clean spread); p23, p19, p15, p18 and p56 under the line; the clean spread 0.9915x to 1.144x. Exhaustion on 017e7037: 0 in the attack-pass lane's 20,532 chain-shaped seeds (max attempt 29) plus this lane's 4,099 (max 17); the 10^6 count continues as a strengthening line. Cost line for the node: the chain's epoch draw now pays the 2^20 ratio pass on every candidate that reaches it (the accepted one, and the about 4 percent that fail there), 2.2 s per pass on one box-2 core, so about 2.3 s per epoch draw on that core and, by the attack-pass lane's reading, about 4 to 5 s per epoch per node on slower cores; the earlier rejections cost milliseconds. From the attack-pass lane sub-version 3 at 017e7037 reads green on both gates with the named tail; its close line went to the plan, main and the Counter ASIC lane. This row stays open on the tail (p4, p8, p10, p34) until it is attributed or ruled accepted.
|
||||
|
||||
The tail read (8 October 2026, 09:40 to 09:46 UK, the hash lane, the M5 Max under the measure lock, one seed at a time; attack-f8 census at 2^24 nonces, window-model control, by-site attribution; tree b38b4af6 with igneum-pow at the frozen 017e7037): the four gate ratios reproduce to four places (p4 1.2169x, p8 1.3774x, p10 1.5036x, p34 1.2501x), the hot-set verdict on the windowed control is clear on all four, and every tail is attributed to one load site reading a narrow window, the site's 256-item bucket concentration carrying the excess with no saturated and no lossy source. p4: site 1 (instr 8, source r2, window 2^22 items, offset 1, last base writer mad at 4) puts 1.448 percent of its reads into the top 0.1 percent of items against 0.107 flat, index entropy 13.74 of 14 bits, largest 256-item bucket 4.5x its window expectation; hottest item 0x4000e7 at 355 reads, predicted source none. p8: site 14 (instr 51, r7, window 2^22, offset 2, writer xor at 44) 1.423 percent, entropy 13.72 of 14, bucket 3.1x, and site 6 (instr 33, r3, window 2^23, offset 1, writer mad at 30) 0.834 percent, entropy 14.71 of 15, bucket 3.5x; hottest 0x837de4 at 420 reads, source none. p10: site 8 (instr 28, r0, window 2^22, offset 1, writer mad at 20) 2.040 percent, entropy 13.71 of 14, bucket 5.6x; hottest 0x4004da at 362 reads, source none. p34: site 1 (instr 13, r3, window 2^23, offset 1, writer sub at 5) 1.352 percent, entropy 14.96 of 15, bucket 3.5x; hottest 0x800010 at 541 reads, predicted source a one-bit value from the sub at 5, saturated source 0.0001 percent. Every other site in all four seeds reads at its flat share. Reading: the residue is a per-site bucket concentration of about a quarter bit (0.26 to 0.29 bits short of uniform on a 2^22 window; 0.04 on p34) at one narrow-window site whose last writer is a mad, an xor or a sub, and the ratio tracks the bucket excess (5.6x gives 1.50x; 3.1x to 4.5x give 1.22x to 1.38x). Sub-version 3's distinct-index ratio (c'') passes these sites at 0.9927 to 0.9963 because distinctness does not see a bucket. The check that would refuse all four is a per-site bound on the largest 256-item bucket, about 2x its window expectation, at the 2^20 units (c'') already draws; it is a generator change, so it is not for the frozen 017e7037, and its cost on clean seeds is unmeasured (a morning item). Chip consequence of the residue: none beyond the window model's (a quarter bit at one site of sixteen is under 1.002x on the item set a chip would hold). The row's tail is attributed; nothing in the stream, the id or the fingerprints changes.
|
||||
|
||||
Two in-house pass findings against sub-version 3 (adv-accept-3, 7 October 2026, evening), neither a chain consequence. (1) Documentation: program.json's `program_id_derivation` and spec 01 section 1.4.6 stated the plain form while generator 4 appends `'sub/' || sub_version_le16`, so a client written from the text derives another id (the devnet v4 pack: 8aa9f185d63f269e from the text against a785001687d8688a; Devnet 3's epoch 0: 30956569d8f3d8d7 against fce15bf61030be57). Fixed at 15008aca and 0f45c8be: one byte recipe (`generator::IdRecipe`) builds the id and the text, the emitter prints that text, the spec states the suffix, the class v5 form (generator 5, no suffix) and the rung form, `tests/derivation.rs` re-derives every pinned pack's id from its own text with the pack's fields only (the plain text as the known-failed case), 38 packs' program.json corrected one line each with every other file and every id and fingerprint byte-identical on re-export; the twelve readwidth mix packs of 5 October keep their text (a class name the parser no longer accepts). (2) Correctness, unreachable: the last-resort program after 256 failed attempts (`last_resort_v4`, the xor rewrite) fails the acceptance rule in 223 of 2,500 seeds (209 by part (a)) and is handed to the chain unchecked; at r = 0.67 to 0.68 the path is reached with probability about 4.6e-44 per epoch, so no chain reaches it and sub-version 3 is not reopened for it. Sub-version 3's last resort is therefore UNREACHABLE AND UNVERIFIED against the rule; class v5's generator (the v5 lane) carries the verified construction with the known-failed test on one of the 223 seeds, and its entry states it. From the same pass: the three lowest-ratio steering seeds of 4,975 at a 256-unit sample read 1.0002x worst live, so the 256-unit ratio is noise as a selector and the selector works only at the 2^20-unit read, which is what rule (c'') uses.
|
||||
|
||||
Owed (recorded, not run, by the founder's word): G2 (the CPU verifier on 1,024 hashes per card) on the amended stream; G3 (the Metal fuzz, edge, stats and determinism runs) on the amended stream; the hash-rate ladder re-measure on the M5 Max and the RTX 5090 (the amendment changes the base program's source draws, not the op mix or the load count, so the latency-bound rows of `docs/analysis/latency-shadow-2026-10-06.md` are expected to hold within their spread; unmeasured); AMD (the RX 9070 XT, PC 1); the 2019-class verifier core (O-1.14); F8's phase E (the 64-seed dynamic census) on the amended stream, which is the attack-pass lane's and the test of the per-op table. The row reads FIXED-AND-PASSED only after phase E passes against the amended class.
|
||||
|
||||
Owed (recorded, not run, by the founder's word): G2 (the CPU verifier on 1,024 hashes per card) on the amended stream; G3 (the Metal fuzz, edge, stats and determinism runs) on the amended stream; the hash-rate ladder re-measure on the M5 Max and the RTX 5090 (the amendment changes the base program's source draws, not the op mix or the load count, so the latency-bound rows of `docs/analysis/latency-shadow-2026-10-06.md` are expected to hold within their spread; unmeasured); AMD (the RX 9070 XT, PC 1); the 2019-class verifier core (O-1.14); F8's phase E (the 64-seed dynamic census) on the amended stream, which is the attack-pass lane's and the test of the per-op table. The row reads FIXED-AND-PASSED only after phase E passes against the amended class.
|
||||
|
||||
Status: Fixed in part, finding bounded, stated (7 October 2026, night, the Counter ASIC lane's words): class v4 sub-version 3 (igneum-pow 017e7037, the audit-freeze tag) is frozen with the dataflow rule, the shared-operand rule, the 0.98 ratio and the total draw; the in-house pass's F8 re-gate reads 60 of 64 seeds under 1.2x with the four-seed tail accepted by the coordinator as the window model's unattributed residue (no chip consequence); the pass then attributed the class by value (eight live hot sets at 1.54x to 2.24x in the lowest 30 of 29,032 accepted programs, each about 1 MB of items at 0.3 percent of reads, 1.002x to a chip); class v5 (1c420786, frozen 21:53 UK) carries the fix as rule (c'''), the per-site distinct-index floor at 0.995 on the state flag (its census refuses 2.435 percent of accepted programs; seven of seven live hot sets refused at 0.9821 to 0.9919; the eighth's ratio owed tonight), with a named residual (three mild shadow-block-written concentrations at 0.9992 to 0.9997, about 1.0004x, a value-level test in the next class); the record is `docs/plans/counter-asic-3-status.md` section 7c and the class v5 design's section 14. The eighth live hot set (seed 122960, id 4be7393ab6c84802, the deepest found: X_f +0.111 percent, 1.54x the window model, its hottest item at 475,616 reads from an all-ones source) reads minimum site 12 at 0.9824 at the acceptance's own 2^20 sample (live 0.9822), refused by class v5's (c''') floor at 0.995; so the floor refuses nine of nine live hot sets by X_f at or above f found in the tail of 269,250 accepted programs (minimum sites 0.9809 to 0.9919; the ninth, seed 228763 from a non-saturated source, at 0.9809 on 8 October 2026) against 0 hot sets in 20 random programs; what it misses stays the three mild shadow-block-written concentrations at 0.9992 to 0.9997 (Devnet 3's first program among them), about 1.0004x to a chip, the value-level test in the next class (22:41 BST; the logs under `docs/analysis/cryptanalysis/logs/adv-accept/` on branch adv-accept; the v5 design's section 14). The public sentence (the coordinator's wording, 7 October 2026, night; the count moved to nine at 01:13 BST on 8 October when the ninth live hot set, seed 228763 from a non-saturated source, read 0.9809 and was refused): nine of nine hot sets refused; the diffuse era-stride excess, bounded under 0.1 percent of a hash's reads per site, is not caught by the floor and is the next class's test. The reason, read by the in-house pass (adv-cache-2) and the class v5 lane together: the distinct-index count at 2^20 sees concentration on few word indices whatever their source, saturated or not (the hot sets put about 3 percent of a site's reads on 512 indices, so the ratio falls to 0.981 to 0.992; the final tally 9 of 9 live hot sets and both single-item programs refused, 7 clean-live programs refused among the 12 deepest, 3 mild residuals missed) and not a diffuse excess over the top 0.1 percent of items (16,384 items), which is what the era-stride low-bit law produces (13 of 27 drawn-era programs carry a site over 1.04x, 8 over 1.2x, worst 1.75x; 0 of 29 refused at the 2^20 sample, minimum sites 0.9965 to 1.0000); its chip value is about 1.0024x at the worst site read, under this row's bound by an order; the row for it is AP-F8-6. The RTX 5080 grid's knee is not in tonight; X37 keeps the 5080's stock premium only.
|
||||
Status: Fixed in part, finding bounded, stated (7 October 2026, night, the Counter ASIC lane's words): class v4 sub-version 3 (igneum-pow 017e7037, the audit-freeze tag) is frozen with the dataflow rule, the shared-operand rule, the 0.98 ratio and the total draw; the in-house pass's F8 re-gate reads 60 of 64 seeds under 1.2x with the four-seed tail accepted by the coordinator as the window model's unattributed residue (no chip consequence); the pass then attributed the class by value (eight live hot sets at 1.54x to 2.24x in the lowest 30 of 29,032 accepted programs, each about 1 MB of items at 0.3 percent of reads, 1.002x to a chip); class v5 (1c420786, frozen 21:53 UK) carries the fix as rule (c'''), the per-site distinct-index floor at 0.995 on the state flag (its census refuses 2.435 percent of accepted programs; seven of seven live hot sets refused at 0.9821 to 0.9919; the eighth's ratio owed tonight), with a named residual (three mild shadow-block-written concentrations at 0.9992 to 0.9997, about 1.0004x, a value-level test in the next class); the record is `docs/plans/counter-asic-3-status.md` section 7c and the class v5 design's section 14. The eighth live hot set (seed 122960, id 4be7393ab6c84802, the deepest found: X_f +0.111 percent, 1.54x the window model, its hottest item at 475,616 reads from an all-ones source) reads minimum site 12 at 0.9824 at the acceptance's own 2^20 sample (live 0.9822), refused by class v5's (c''') floor at 0.995; so the floor refuses nine of nine live hot sets by X_f at or above f found in the tail of 269,250 accepted programs (minimum sites 0.9809 to 0.9919; the ninth, seed 228763 from a non-saturated source, at 0.9809 on 8 October 2026) against 0 hot sets in 20 random programs; what it misses stays the three mild shadow-block-written concentrations at 0.9992 to 0.9997 (Devnet 3's first program among them), about 1.0004x to a chip, the value-level test in the next class (22:41 BST; the logs under `docs/analysis/cryptanalysis/logs/adv-accept/` on branch adv-accept; the v5 design's section 14). The public sentence (the coordinator's wording, 7 October 2026, night; the count moved to nine at 01:13 BST on 8 October when the ninth live hot set, seed 228763 from a non-saturated source, read 0.9809 and was refused): nine of nine hot sets refused; the diffuse era-stride excess, bounded under 0.1 percent of a hash's reads per site, is not caught by the floor and is the next class's test. The reason, read by the in-house pass (adv-cache-2) and the class v5 lane together: the distinct-index count at 2^20 sees concentration on few word indices whatever their source, saturated or not (the hot sets put about 3 percent of a site's reads on 512 indices, so the ratio falls to 0.981 to 0.992; the final tally 9 of 9 live hot sets and both single-item programs refused, 7 clean-live programs refused among the 12 deepest, 3 mild residuals missed) and not a diffuse excess over the top 0.1 percent of items (16,384 items), which is what the era-stride low-bit law produces (13 of 27 drawn-era programs carry a site over 1.04x, 8 over 1.2x, worst 1.75x; 0 of 29 refused at the 2^20 sample, minimum sites 0.9965 to 1.0000); its chip value is about 1.0024x at the worst site read, under this row's bound by an order; the row for it is AP-F8-6. The RTX 5080 grid's knee is not in tonight; X37 keeps the 5080's stock premium only. The tail is attributed (8 October 2026, 09:46 UK, the hash lane): one narrow-window site per seed with a quarter-bit bucket concentration from a mad, xor or sub writer, no lossy source, no chip consequence beyond the window model; the per-site bucket bound that would refuse it is a morning item for the next class, not a change to 017e7037.
|
||||
|
||||
### AP-F8-3. The deterministic last-resort program is handed to the chain unchecked, and the rule would refuse 9.0 percent of such programs
|
||||
|
||||
|
|
@ -2555,6 +2557,15 @@ Evidence: `docs/analysis/cryptanalysis/report-acceptance-rule-3.md` sections 6.2
|
|||
|
||||
The three genesis fields of `docs/analysis/mission/mission.md` section 2.8, built on the node fork branch `genesis-forward` (from release-0.3.19-node dc141409) and the repo branch `genesis-forward`; the design and the gates in `docs/design/genesis-forward.md`. Every switch is never on the devnet (its digest c562d70e... does not move); the testnet genesis sets all three (the testnet lane re-pins and re-digests).
|
||||
|
||||
### AP-F8-7. The hash's reads are not uniformly random: about half of epochs carry one load site with a biased address bit
|
||||
"The served text says every hash is a chain of random reads over the dataset. Measured at the acceptance rule's own 2^20 sample over 4,900 drawn eras (lane D's family harness, 8 October 2026) and in adv-cache-2's drawn-program reading the night before: the reads are spread over the whole dataset and the distinct-index floor holds at 0.995 on every accepted program, but 52 to 58 percent of accepted programs in every stratum carry one load site whose address bit R (the era's stride rotation), R+1 or R+2 is biased over 6 sigma, a third over 100 sigma, the worst z 1,024: a product's bit 0 at P = 1/4 landing on an address bit."
|
||||
|
||||
Status: Open, priced: 1.6 percent at f = 1/2, nothing at f = 1; the served sentence corrected 8 October 2026 (the site audit lane, by main's word): the litepaper's lead reads "dependent reads spread over a multi-gigabyte dataset", the "chain of random reads" sentence carries the measured clause after it, evidence row 18 states the measurement with its sources. The disposition is class v6 layer 1's rule: fold the product's low bits before the rotation so no era lands a biased bit on an address bit, with the bias test as its guard (`docs/analysis/class-v6/family-gate.md`).
|
||||
|
||||
Answer: Correct as a measurement and bounded as a gain. The favoured half of one site's window serves 75 instead of 50 percent of that site's reads, 25 percent of 1/16 of a hash's reads, about 1.6 percent, to a chip storing half the dataset; a chip storing all of it gains nothing (the f = 1 verdict unchanged, and the partial store already costs 1.26x the ops). The sentence that said "random" now says what was measured.
|
||||
|
||||
Evidence: `docs/analysis/class-v6/family-gate.md` (lane D, the index-bit bias read, 8 October 2026); adv-cache-2's `docs/analysis/cryptanalysis/report-chained-cache-2.md` section 2.3 (branch adv-cache-2); `site/litepaper.html` Mining; `docs/evidence.md` row 18.
|
||||
|
||||
### GF1. A post-quantum signature scheme would need a hard fork, and every vote key is a public BLS12-381 point
|
||||
"When a quantum computer comes, every BLS vote key is forged and the chain has no way to change the scheme without a fork of the kind you say you never need."
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
Generated by `tools/ledger/export-public.mjs` from `docs/fud-ledger.md`; a gate check fails when the two drift. One row per item: the claim or criticism, its status, what was done, and the evidence. Internal identifiers, times of day and team-member names are left out on purpose; the full ledger is published with the repository.
|
||||
|
||||
196 items. By status: Conceded, stated 52; Fixed 31; Decided 22; Fixed on a branch, pending merge 14; Answered by design 9; Answered with evidence 7; Fixed, stated 4; Closed by rule 3; Open 3; Spec fixed 2; Answered by design, with a correction to our own text 1; Answered with evidence, stated 1; Answered by design for finality, Conceded for the lottery 1; Conceded, implemented, stated 1; Rule implemented, behind a switch 1; Rule implemented and measured; launch month simulated 1; Answered by design, with the concession stated 1; Conceded, stated in the litepaper and the design doc 1; Answered with evidence at 1 block/s 1; Conceded, stated in the simulation report 1; Answered by design, with the dependency conceded. Update 7… 1; Conceded, stated in the litepaper, with the dial explained 1; Closed by spec 1; Conceded by decision, stated in the design doc 1; Answered by design, with the founder's edge conceded 1; Answered by design, with a metrics caveat 1; Closed by removal, 3 October 2026 1; Conceded, stated in the litepaper 1; Conceded, stated in the design doc 1; Measured on the live node line, and the overlay does NOT… 1; Conceded, stated in the simulation 1; Conceded in part, labelled, stated 1; Fixed in the node 1; Answered with evidence for the largest body the rules allow 1; Fixed in the proving code 1; Fixed in the spec 1; Rule fixed 1; Rule written 1; Fixed, logged 1; Answered with evidence for the test half 1; Fixed in the node and shipped, rule not yet activated on… 1; Simulation half run 1; Answered with evidence for all four 1; Written 1; Designed 1; Fixed and confirmed 1; Rolled out 1; Conceded by decision 1; Conceded, scheduled, stated 1; Conceded, contained by rule, stated 1; Fixed on a branch and verified locally 1; Answered with evidence and stated 1; Answered with evidence for PC 2 1; Answered by design and with evidence 1; Fixed, stated; restated 1; Fixed, stated; restated further 1; Fixed in part, finding bounded, stated 1; Fixed in class v5 1; Fixed as a genesis lever, measurement owed 1.
|
||||
197 items. By status: Conceded, stated 52; Fixed 31; Decided 22; Fixed on a branch, pending merge 14; Answered by design 9; Answered with evidence 7; Fixed, stated 4; Closed by rule 3; Open 3; Spec fixed 2; Answered by design, with a correction to our own text 1; Answered with evidence, stated 1; Answered by design for finality, Conceded for the lottery 1; Conceded, implemented, stated 1; Rule implemented, behind a switch 1; Rule implemented and measured; launch month simulated 1; Answered by design, with the concession stated 1; Conceded, stated in the litepaper and the design doc 1; Answered with evidence at 1 block/s 1; Conceded, stated in the simulation report 1; Answered by design, with the dependency conceded. Update 7… 1; Conceded, stated in the litepaper, with the dial explained 1; Closed by spec 1; Conceded by decision, stated in the design doc 1; Answered by design, with the founder's edge conceded 1; Answered by design, with a metrics caveat 1; Closed by removal, 3 October 2026 1; Conceded, stated in the litepaper 1; Conceded, stated in the design doc 1; Measured on the live node line, and the overlay does NOT… 1; Conceded, stated in the simulation 1; Conceded in part, labelled, stated 1; Fixed in the node 1; Answered with evidence for the largest body the rules allow 1; Fixed in the proving code 1; Fixed in the spec 1; Rule fixed 1; Rule written 1; Fixed, logged 1; Answered with evidence for the test half 1; Fixed in the node and shipped, rule not yet activated on… 1; Simulation half run 1; Answered with evidence for all four 1; Written 1; Designed 1; Fixed and confirmed 1; Rolled out 1; Conceded by decision 1; Conceded, scheduled, stated 1; Conceded, contained by rule, stated 1; Fixed on a branch and verified locally 1; Answered with evidence and stated 1; Answered with evidence for PC 2 1; Answered by design and with evidence 1; Fixed, stated; restated 1; Fixed, stated; restated further 1; Fixed in part, finding bounded, stated 1; Fixed in class v5 1; Open, priced 1; Fixed as a genesis lever, measurement owed 1.
|
||||
|
||||
| Id | Claim or criticism | Status | What was done | Evidence |
|
||||
|---|---|---|---|---|
|
||||
|
|
@ -198,6 +198,7 @@ Generated by `tools/ledger/export-public.mjs` from `docs/fud-ledger.md`; a gate
|
|||
| AP-F8-6 | The class v5 acceptance floor does not reach the era-stride diffuse concentration | Answered with evidence | ; the lever routed to the next class and CA4; nothing in class v5's frozen object a commit moves. | none named |
|
||||
| AP-F8-4 | The program id's derivation text omitted generator 4's sub-version suffix (interoperability, documentation; no object change) | Fixed | The id and its printed derivation come from one byte recipe (`generator::IdRecipe`, `program_id_recipe`, `program_id_class_recipe`, `Program::program_id_derivation`), so the two cannot drift; the emitter prints that… | [igneum-pow/tests/derivation.rs](../igneum-pow/tests/derivation.rs) |
|
||||
| AP-F8-5 | The public specification did not describe the shipped acceptance rule (documentary; no object change) | Spec fixed | Sections 1.4.3 and 1.4.6 of `docs/spec/01-lottery-hash.md` rewritten to the shipped rule at igneum-pow a commit with every constant named and every order of operations stated (1.4.3: the two per-register states of the… | [docs/analysis/cryptanalysis/report-acceptance-rule-3.md](../docs/analysis/cryptanalysis/report-acceptance-rule-3.md) |
|
||||
| AP-F8-7 | The hash's reads are not uniformly random: about half of epochs carry one load site with a biased address bit | Open, priced | 1.6 percent at f = 1/2, nothing at f = 1; the served sentence corrected 8 October 2026 (the site the team, by the team's word): the litepaper's lead reads "dependent reads spread over a multi-gigabyte dataset", the… | [docs/analysis/class-v6/family-gate.md](../docs/analysis/class-v6/family-gate.md) |
|
||||
| GF1 | A post-quantum signature scheme would need a hard fork, and every vote key is a public BLS12-381 point | Fixed | The byte costs nothing now and a fork later. | none named |
|
||||
| GF2 | A vote key cannot move: a miner who changes keys re-earns 30 days of weight, and so does the post-quantum migration | Fixed | The successor inherits the window, not a fresh one, so a key rotation costs no weight and the migration of GF1 is one item per key. | none named |
|
||||
| GF3 | A 256 MB on-chip cache makes the lottery hash 2 to 3x cheaper for the card that has it, and the cache size is a constant | Fixed as a genesis lever, measurement owed | Consumer LLC is 96 to 128 MB today and datacentre 256 MB (`chip-model-v3`, approximate), so the shortcut is a datacentre card's today and a consumer card's in a generation or two. | none named |
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
|
|
@ -229,12 +229,12 @@ Internal adversarial pass, not an independent review. Target `igneum-pow` 017e70
|
|||
| adv-mixer-2 | 2a632579 | 0.31 | 0 | the day-key weakness class BOUND for every chip, GPU and the verifier; FINDING on FPGA LUT area only (2^-10.8 of days over 1.1x, 15 days a century, worst 2050-04-28 at 1.113x, reconciled with F4), closed by the measured redraw rule (0 days over 1.1x after it) or the O-1.10 day derivation | none |
|
||||
| adv-mixer-3 | 981bfff2 | about 5.0 wall-hours plus 8 single-core SAT hours | 0 | Q1 BOUND (2^32 t uniform k = 1 to 8, both days, 8 random days); Q2 and Q2b FINDING at k = 1 only (the single-application diffusion), BOUND from k = 2 to 8 at 2^24, 2^27, 2^28; Q3 FINDING at k = 1, BOUND k = 2 to 7; Q4 and Q5 BOUND from k = 1; Q6 SAT BOUND (k = 1 in 137 s, five orders slower than brute force; k = 2 to 4 timeout at one hour on both days). The round margin: no statistic survives 2 of 8 applications between reads, 70 of 72 per item | Q3 k = 8 not run; multi-bit masks and a MILP trail bound not attempted; GPU BLOCKED |
|
||||
| adv-cache | 555c3e42 | 0.55 | 0 | the recompute shortcut BOUND on every row, every plant fired (defender: no dispute) | none |
|
||||
| adv-cache-2 | 91ca5ce1 | about 2.25 of run | 0 | Q1 line census PASS at 2^35 + 3 x 2^33 reads; Q2 real programs PASS with the Devnet 3 site-0 FINDING; Q2b 64 programs, the diffuse era-stride class (16 of 32 base programs biased under drawn eras against 2 of 32 under the devnet's R = 29, 8 over 1.2x, worst 1.75x; under 0.1 percent of a hash's reads per site; the class v5 floor refuses 0 of 61; ledger AP-F8-6); Q3 steering and the 16,384-day weak-day scan PASS; Q3(3) the window layer exact to four digits and the chip model's partial-store rows overstated up to 2.3x, verdict unchanged | line shard s2c (64 fresh days) waiting on build-1 since 23:09 BST |
|
||||
| adv-cache-2 | bfc3746c (closed 04:59 BST) | 2.35 of run (0.08 a duplicate windows run by its build-1 drain, recorded) | 0 | Q1 line census PASS at 2^35 + 3 x 2^33 reads; Q2 real programs PASS with the Devnet 3 site-0 FINDING; Q2b 64 programs, the diffuse era-stride class (16 of 32 base programs biased under drawn eras against 2 of 32 under the devnet's R = 29, 8 over 1.2x, worst 1.75x; under 0.1 percent of a hash's reads per site; the class v5 floor refuses 0 of 61; ledger AP-F8-6); Q3 steering and the 16,384-day weak-day scan PASS; Q3(3) the window layer exact to four digits and the chip model's partial-store rows overstated up to 2.3x, verdict unchanged | none: s2c ran 04:56 to 04:59 BST, PASS at 2^33 reads; the line census total 2^36 reads over 464 chain days at the control's values |
|
||||
| adv-cache-3 | 9452c0bf | 0.23 | 0 | the chain-break or skip BOUND on every row, every plant fired; the pebbling optimum under the hold-every-k curve (bookkeeping) | none |
|
||||
| adv-accept | c8a98e46 | about 9.2 at 03:25 BST, running to its 16-hour line | 0 | Q1 the bypass FINDING, confirmed and bounded: 9 few-item hot sets in the tail of 408,067 accepted programs, 0 in 20 random, 1.002x at the largest; all 9 refused by the class v5 floor, 7 clean programs falsely refused among the 12 deepest (the 2.4 percent), 3 mild residuals missed (the era-stride class, about 1.0004x); Q2 the stand-in gap BOUND; Q5 distinguishers BOUND; row 90 the attempts census complete (0.681 per candidate, (a') 83.5 percent, 0 exhaustions, P 2e-43) | the sweep at 408,067 of 10^6 seeds, shards running on in the pool's gaps; ends at 16 box-hours with the count |
|
||||
| adv-accept | 8f188e5a (closed 09:47 BST) | 15.1 | 0 | Q1 the bypass FINDING, confirmed and bounded: 9 few-item hot sets in the tail of 796,042 accepted programs (37 measured live from the stand-in tail, 22 beyond the 1.2x gate), 0 in 20 random, 1.002x at the largest; all 9 refused by the class v5 floor, 7 clean programs falsely refused among the 12 deepest (the 2.4 percent), 3 mild residuals missed (the era-stride class, about 1.0004x); Q2 the stand-in gap BOUND; Q5 distinguishers BOUND; row 90 the attempts census complete (0.681 per candidate, (a') 83.5 percent, 0 exhaustions, P 2e-43) | the sweep at 796,042 of 10^6 (79.6 percent): three ranges unswept (40886 to 100001, 706081 to 800001, 849304 to 900001) after their waiters gave up at the pool's 2-hour limit; the last shard ended 09:37 BST with nothing left running; BOUND, no BREAK |
|
||||
| adv-accept-2 | 92168536 | about 9.0 core-hours | 0.3 (the one pod) | header grinding BOUND by measurement (+0.09 percent on an RTX A6000) and by tail (3e-7); one 0.1 percent repeat class for the rule's owners | none |
|
||||
| adv-accept-3 | 7826d2b2 | 3.3 | 0 | exhaustion BOUND (P 1.0e-43); the last-resort path FINDING (correctness, unreachable); steering BOUND (no property over 1.03x at 1 in 1e6 tries); the program id BOUND with the derivation-string FINDING (fixed on master and in the packs); determinism BOUND, the spec text proven sufficient by two read-backs (0 of 400 at 8b834634 with one named function, 0 of 400 at 56eebc0d with nothing from the crate); the era lever BOUND | the steering sweep at 975 of 10^5 full-rule seeds (1e6 static) |
|
||||
|
||||
Totals: box-hours about 30.4 of run across the nine lanes (0.6 + 0.31 + 5.0 + 0.55 + 2.25 + 0.23 + 9.2 + 9.0 + 3.3, the lanes' own figures, wall times threads over 96 or slot-hours as each states, lease waits excluded) plus about 9.8 single-core SAT hours; pod-hours 0.3 (one RunPod A6000, USD 0.33 in all, rented and destroyed by the fleet lane, none originated by this lane). The 24 box-hour line of section 4 was read and crossed by one lane (adv-accept at about 02:15 BST, reported); no lane reached the 16-hour ask line.
|
||||
Totals: box-hours about 36.4 of run across the nine lanes (0.6 + 0.31 + 5.0 + 0.55 + 2.35 + 0.23 + 15.1 + 9.0 + 3.3, the lanes' own figures, wall times threads over 96 or slot-hours as each states, lease waits excluded) plus about 9.8 single-core SAT hours; pod-hours 0.3 (one RunPod A6000, USD 0.33 in all, rented and destroyed by the fleet lane, none originated by this lane). The 24 box-hour line of section 4 was read and crossed by one lane (adv-accept at about 02:15 BST, reported); no lane reached the 16-hour ask line (adv-accept closed at 15.1 when its last shard ended).
|
||||
|
||||
The verdict. No lane broke the frozen object. The mixer's 72 keyed applications cost what the chip model prices (no fold, no low-degree form, no statistic past 2 of 8 applications, no SAT preimage past 1); the chained cache yields no line under j + 1 blocks and no curve under the full store; the line and item distributions are uniform at 2^35 reads; header grinding gains nothing a card can measure; the draw cannot be exhausted or steered by its attempt index. The acceptance rule admits two residual classes of address concentration, both priced under 1.002x to a chip: few-item hot sets, which the class v5 floor at 0.995 closes entire (9 of 9) at a 2.4 percent clean-rejection cost; and a diffuse era-stride excess (a product's biased low bits placed in the item index by the era rotation unless R is 29 or 30) the floor does not reach, routed with its lever (a value-level source test and the era draw's R range) to the next class. The weak-day FPGA tail is reconciled at 15 days a century on LUT area only (no chip, GPU or verifier gain) and closed by a measured redraw rule. Already changed by the pass: the program-id derivation string in shipped packs; spec 1.4.3 to 1.4.6 rewritten to the shipped rule with its measured rates and proven text-sufficient; the chip model's partial-store and pebbling baselines flagged for correction; the last-resort path flagged for its owner.
|
||||
|
|
|
|||
|
|
@ -127,3 +127,21 @@ site. None of this is in the repo; the stats API of this branch is the network s
|
|||
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.
|
||||
|
||||
## 8. Devnet 3 explorer (8 October 2026, the explorer lane; the founder's order of 11:00 UK: a public explorer the same day)
|
||||
|
||||
What serves, all at igneum.network (the host explorer.igneum.network is a CNAME to the same Vercel project with a root rewrite to /explorer):
|
||||
|
||||
| Page | What it shows | Data |
|
||||
|---|---|---|
|
||||
| `/explorer` | the Devnet 3 strip (status, height, DAA, hash rate, chain rate, finality, program class, proving), the DAG picture (newest 150 blocks, one lane per miner, parents drawn, lock and paid marks), latest blocks (class, shards paid, final), latest transactions, the proving summary, the API list | `/api/explorer?stats=1`, `?dag=150`, `?blocks=50`, `?txs=30`, `?proving=1` |
|
||||
| `/block/<hash>` or `/block/<number>` | header, parents, children, mergeset, coinbase, the EVM transactions it executed (from the indexer), the shard plan with each shard's state and the node's verdict, the checkpoint and certificate, the lock that covers it, the class; **the verified badge**: for a block under a lock the browser fetches `/api/checkpoint?index=N` and runs `site/verify/core.js` (header hashes recomputed, BLS keys aggregated, the signature checked over the weight rule) and the badge reads "verified under lock N in this browser" or the failure reason | `?block=`, `?height=`, `/api/checkpoint?index=` |
|
||||
| `/tx/<hash>` | status, value, fee, gas, nonce, type, input, the receipt's Igneum section (miner tip, both burns, pgas, app share, including block and miner), the executing block's lock and shard state, the logs | `?tx=` |
|
||||
| `/address/<addr>` | balance, nonce, code (contract or account), sent and received counts, the transactions of the last 7 days, the blocks mined and what they earned | `?address=` (`&before=<number>` pages the transactions) |
|
||||
| `/proving` | the node's proving state, the newest 60 chain blocks with their shards by state and median lag, the provers of 24 h with payouts, the block-to-paid latency of the last hour (p50, p90) and the 24-hour totals by state | `?proving=1` |
|
||||
|
||||
The indexer: `tools/observer/explorer-indexer.mjs`, the observer's sibling on build-1 (unit `igneum-explorer-dn3`, User build, the same env file, `LIVE_TABLE_PREFIX=dn3_`, `IGNEUM_EVM_RPC` on loopback). It reads `eth_getBlockByNumber` with transactions and `eth_getBlockReceipts` per chain block, refreshes `eth_getBalance`, `eth_getTransactionCount` and `eth_getCode` for every address a block touches and for the observer's miners of the last 10 minutes, and keeps `igneum_getNodeInfo` (the class floors and every activation) in `dn3_explorer_state`. Tables `dn3_live_txs`, `dn3_live_accounts`, `dn3_explorer_blocks`, `dn3_explorer_state`; 7 days of transactions. Measured 10:04 to 10:07 UTC: 26,847 chain blocks and 71,218 transactions from genesis in 3 minutes; steady state 0.4 chain blocks per second at 16 percent of one core. Two classes met the same morning, each with its guard: the unit's first start read the first devnet's node for 25 s (the env file's `IGNEUM_EVM_RPC`), so the indexer now refuses any node whose `igneum_getNodeInfo.network` is not `EXPLORER_NETWORK`; and the observer node's restart at 10:21 UTC on 0324-5b673577 re-executed from block 0, so a tip below the indexed number re-reads from the tip and the API settles `chain_now` against the highest number ever indexed, not the current tip.
|
||||
|
||||
Read against the EVM: a block the observer called a chain block whose number the EVM later gave to another block (tip reorgs on Devnet 3 run to depth 18, `igneum_getBudgets.deepestReorg` at 10:0x UTC) reads "replaced" on the list and the block page. The table prefix default of `/api/explorer`, `/api/stats`, `/api/supply` and `/api/checkpoint` moved to `dn3_` (the live deploy had served the first devnet on those four while `/api/live` served Devnet 3).
|
||||
|
||||
Not yet: the STARK itself is not re-run in the browser (the node's verdict is shown as the node's; the explorer-verify branch's binding check of proof bytes to records is not merged); `eth_sendRawTransaction` and live balances from the public RPC (`rpc.devnet.igneum.network`, up since 11:08 UK) are not wired into the pages (`EXPLORER_EVM_RPC` on the deployment switches the balance read to live); a checkpoints list page; the program id per epoch (no RPC); internal transactions (no tracing RPC).
|
||||
|
|
|
|||
|
|
@ -198,3 +198,31 @@ Main's word on route (A) or (B) did not come (asked 01:41, 01:50, 01:53, 01:56 B
|
|||
**The knob:** the hash lane's 74585c91 (main's order of 7 October: the Ember clock ladder continues below 45 percent in 100 MHz steps to a 20 percent floor; the search stops at the knee, the first row more than the tolerance under the cap point's rate, or on a faulted row, the fingerprint check; the best MH per watt within tolerance is the point; lock_result and the card's lock_* fields for the UI; tests known-failed first on a fake helper) sat on the mirror's master, not on the release line; cherry-picked onto release-0.3.24 as e181f497 with ember.rs resolved as the union (the knob's floor and fine step beside the efficient-point ceiling of 7 October: EFFICIENT_W, DEFAULT_CAP_PCT, power_ceiling), the plan-count test updated to the knob's ladder on the 5090 (1 + 6 + 7; b6e2845f); app gate GREEN on build-1 (294 + 35 + 8), pre-push 60; the DMG re-cut under the lock on b6e2845f; the UI lane's drawing of the lock fields asked onto that tip. The rule: the knob never sets a lock below the knee without the user's own choice.
|
||||
|
||||
**The measured Ember line (the Counter lane, read on PC 1 overnight):** the installed app's stock power-limit climb on the RTX 5080 lands at 60.3 MH/s at 123 W (0.489 MH/W, clock_cap 2,936; run-ca3-pc1-ember-5080-20261007 at 07:05 BST, the app's own tune complete before the script's cast fault), while the clock-lock grid on the same card gives 71.1 MH/s at 103.7 W at the 1,000 MHz lock (0.686 MH/W) and 71.2 at 146.6 W at 1,100 on class v4 (0.486) (run-ca3-pc1-v4-eff-5080-20261007-d at 02:54 BST), so the core-clock lock is worth about 40 percent more per watt and 18 percent more rate than the climb alone on the 5080; on the 5090 the knob's reference rows are class v4 at 1,200 MHz (133.8 MH/s at 305 W, 0.439) and class v3 at 1,300 (134.6 at 223 W, 0.603), the knee at 1,300 on both, measured four times (docs/bench-log.md, the 7 to 8 October entry). The 9070 XT tune row follows. Nothing else changes in the cut: the pin dfbd1e10 and the kit e6c088bb stand; the move on main's morning minute.
|
||||
|
||||
## 22. The morning: main's word, the fifth cut, the move staged (09:3x to 09:5x BST, 8 October)
|
||||
|
||||
**The night's silence** was the harness: main's command failed at 23:36 BST and it got no turn until 09:3x; the build-server lane and the fleet lane sat on backgrounded chains from 22:54 and 22:58 BST with nothing lost on the boxes (both idle); all three answered at 09:31 to 09:34. **Main's word (09:3x BST):** route (A) by the shipper (the node lane re-cuts the floor from the minute 10:45 BST; the shipper applies the pack-gate line with the fleet's tooling, places the signed move file at at_epoch 0 the moment the pin is green, names the minute, restarts build-1's three nodes and publishes the Mac entry at the minute; a pin not green by 10:35 slides the minute to the pin plus 25; the ceiling 12:50); the build-server lane builds the seed, Windows and hive pairs on the morning pin under lease class release and hands them over; the Windows app chain is the shipper's after the move (0.3.23 take 3 skipped as moot); "PC 2 clear" for the hash lane's Arc job; the two lanes respawned (the new fleet lane takes the readings after the move, not the move). Then (09:5x): the founder's word, get it live now: the minute is the last FETCHED plus ten, 10:45 the ceiling not the target; everything but the crossing done by 11:00 BST, the Windows chain in parallel. **Standing authority from main:** if the reachable boxes have not all FETCHED by 10:35 the shipper says "slide" itself; when the margin to a floor's publish ceiling falls under 15 minutes, re-cut without asking. **The founder's rule ("this cannot happen again"):** every ask to main carries a default action and a deadline, silence at the deadline means the default, never a stand-down; the Counter lane mirrors every clock the shipper holds today from the shipper's runbook (scratch r0324/RUNBOOK-0324-move.md, twelve steps with commands, hosts, keys and read-backs).
|
||||
|
||||
**The fifth cut, the pin: release-0.3.24-node = 5b673577** (dfbd1e10 with program_class_v5_activation_daa 68,400, epoch 19, nothing else; cut at 09:33:18 BST from build-1's seed at DAA 56,329, the chain at 1.0 DAA/s all night; the publish DAA at 10:45 about 60,630, the floor about 12:54 BST, the three heights under it; the floor holds for a publish up to DAA 61,200, about 10:54 BST); every gate green at 09:39:15 BST (build at gate priority, core 175, exec 47, miner 28, p2p-flows 38, pow 19, consensus 134 at gate priority; the Devnet 3 canary with digest cc9026909eddbadb and the mixed-version refusal against a 2720d8d2 node both ways; the testnet canary on b2e856ed); the node-lane pair igneumd a3b1a2c9 / igneum-miner cfa9f5ca under /srv/artefacts/0324-5b673577/node-lane, igneum-pow-v5 8 paths; the fast-time SUMMARY on it due about 09:55. The app side: release-0.3.24 = 0c47b59a (the knob's display knob-24 2c4dc617 merged, UI 88; the Windows pin to 5b673577 at ebbdbc32); the Mac node pair (igneumd aee81264, igneum-miner 129275ef) and the DMG 7e6e3eb3 built under the lock, the Mac entry re-staged in both folders.
|
||||
|
||||
**The move staged (09:42 to 09:44 BST):** the tarball fleet/5b673577-node-lane.tgz (c5b85b09, 27,495,480 B) served from build-1; the move file m5b67-1 (commit 5b673577, want_version igneumd/2.1.0-5b673577, want_digest cc9026909eddbadb, both pair slots on the tarball, at_epoch 0) signed with the fleet key and placed at 09:42:14 BST, the served file's signature verified; the pack-gate line (cfa9f5ca into PAIR_MINER_SHA16 in env-last and box-dn3.sh's default) applied on 32 of 32 reachable boxes at 09:43:34 with each gate read back (unreachable dn3-relay and p2-4090-1b behind dead Vast proxies; dn3-pool-a destroyed by the fleet's hourly waste pass at 09:02 BST, "exited" on Vast, so the open pool is dn3-pool-b alone until a second member is rented); build-1's three nodes (the seed, node1-dn3 down since the night, the observer: a plain process, not a unit) restart by the shipper's script at the minute, dry-run clean. The fleet's morning reading: the eight boxes it read as "bc5945fe" had NO Devnet 3 node (its reader hashed its own bash); dn3-g2's node died 23:49 BST, dn3-g1's 01:46, the others overnight, no shutdown lines (the death evidence being read); all eight restarted on 2720d8d2 before the minute so they fetch and move with the rest. The eleven prover boxes read "pair ok" at the tip all night; hub-1 at DAA 56,281 with 2 peers at 09:34.
|
||||
|
||||
**The Arc B580 (09:36 to 09:5x BST):** the class v5 kit worker (27faa253) failed its self-test on PC 2's Arc on both the v5 pack and the v4 control (96 of 96 lanes bad; the cache and dataset FNVs right); the Intel lane answered from the app's own log: the installed 0.3.21 worker's self-test PASSED on the Arc with the devnet pack (96 of 96 at 21:23 BST, then 54 blocks accepted with the CPU re-check at 10.58 MH/s), so the /miners row stands as a measurement; the kit worker regressed because class-v5 1095eaa8 (and master) lack proto-opencl/intel_rotr.h (26e135a3), which release-0.3.23 and 0.3.24 carry; the Intel lane lands it on the mirror's master; the Intel kit holds out of 0.3.24 (main's rule), the crossing time 09:36 BST on the page row.
|
||||
|
||||
**THE MINUTE: 10:05:00 BST on 8 October (09:05:00Z),** set in the signed move file m5b67-1 at 09:48:12 BST and read back served (commit 5b673577, want_digest cc9026909eddbadb, at_utc 2026-10-08T09:05:00Z, the signature good), 49 minutes inside the 10:54 ceiling, after the fast-time SUMMARY PASS on 5b673577 at 09:47:45 BST (rung 1 by signal at epoch 6, class v5 by signal at byte 6 from epoch 8, the stale node refused, 0 rejections, the restart across the boundary resynced in 12.1 s, four sinks equal) and FETCHED 35 of 39 at 09:46 (dn3-relay and p2-4090-1b behind dead Vast proxies, p2-3090-1 refusing ssh since last night, dn3-agg48 the new 48 GB aggregator prover renting: the first three fall off onto ba75bf6f and rejoin by the pull, the fourth fetches with its bring-up; named in the file's note); dn3-g1 and g2 back on 2720d8d2 at 09:43 and 09:44 with their miners on and no panic or OOM on either, the other six dead nodes restarting in the same pass. **The pairs on the pin (the build-server lane, 09:43 to 09:47 BST):** seed igneumd 3a204fd9 / igneum-miner 464dca07 (glibc 2.34, the string twice), win igneumd.exe 0b144d7d / igneum-miner.exe 0cc68d9e, the hive package igneum-hive-0.3.24-5b673577.tar.gz 025bf01f (29,876,121 B, the three kit zips, smoked in ubuntu:20.04), all under /srv/artefacts/0324-5b673577/ beside the node lane's hands pair a3b1a2c9 / cfa9f5ca; the engine strings read igneum-pow/src/ (the worktree's path) where the node lane's read igneum-pow-v5/src/, the same code at 1c420786, rule 6a's pattern taking both. At the minute: the pullers restart node and miner from the pair; build-1's seed, node1-dn3 and observer by the shipper's script (dry-run clean; the observer a plain process, restarted with its own command line); the Mac entry (DMG 7e6e3eb3: app 0c47b59a with the knob and its display, the Mac node pair aee81264/129275ef, interface 1.0.2, the floor file kept) and the hive 025bf01f into both token folders with the public Mac and HiveOS aliases, one deploy; "PC 2 go" for the Windows chain (installer-kit-0c47b59a.zip b03fba28 cut, the app cross running, the PC 1 host job publishing). The 0.3.25 line opened by the update-return lane: amd-clock-25 a002732a (the AMD core-clock knob through ADLX manual tuning in the telemetry tool; the exe must be rebuilt for the kit), its default at 13:00 BST.
|
||||
|
||||
## 23. The move executed: 0.3.24 Mac and HiveOS LIVE (10:05 to 10:09 BST, 8 October)
|
||||
|
||||
**THE MINUTE 10:05:00 BST** fired on the signed file m5b67-1 (FETCHED 36 of 39 at 10:00: dn3-agg48 the 48 GB aggregator prover still renting, p2-3090-1 refusing ssh since the night, p2-4090-1b behind the dead proxy ssh2; all eight nodes dead overnight back on 2720d8d2 and fetched by 09:53, dn3-r03 and r04 given a saved environment by hand). **build-1's three on the pin:** node1-dn3 (26671, JSON 28670) and the observer (26651, JSON 28650) up at 10:08 on "igneumd/2.1.0-5b673577", digest cc902690, object version 6, the N15 line ("the 15611 records up to the tip 15611 are continuous"); the seed (26631, JSON 27632) at 10:09 after a first start at 10:08 panicked on the old process's RocksDB lock (meta/LOCK "Resource temporarily unavailable"), up on cc902690 with 3 outgoing connections. The shipper's fault, two parts: the three-node script's --go branch did not execute at 10:05 (the dry-run text printed and it exited: the kill pattern `pgrep -f appdir=...` matched the ssh shell carrying the script, the fleet's fault class of 22:34 the night before), so the move ran by hand at 10:07 with the victims found by process name and cmdline; and the seed restarted before the old process had released its datadir (rule 11 extended). **The 0.3.24 Mac entry LIVE at 10:08:35 BST** (the copy at 10:05:01, one Vercel deploy), both token folders, channel devnet-3: Igneum-Miner-0.3.24-5b673577.dmg 7e6e3eb3 (45,652,380 B; app 0c47b59a: the core-clock knob and its display, the Power Helper unattended, the dashboard caps, the pool daemon's reconnect, the testnet re-cut; the Mac node pair aee81264/129275ef from 5b673577), interface 1.0.2, the floor file kept for the apps below 0.3.22, read back from both folders and the public Mac alias; **the HiveOS package igneum-hive-0.3.24.tar.gz 025bf01f** (the 5b673577 hive pair, the two sub-version 3 kits and the v5 kit e6c088bb) in both folders and on the public alias at the same deploy; dl/public/igneum-downloads.json names 0.3.24 for Mac and HiveOS. The notes carry the knob, the floor from the minute and "update before the move minute or the node stops following Devnet 3". Owed from the fleet: the APPLIED count per box, the chain rate at 10:08 and 10:12, the first lock on cc902690. The Windows chain: "PC 2 go" at 10:07 (the installer job from the a4c5a855 kit, sha ad7a50e8, and the payload igneum-windows-app-0.3.24-a4c5a855-msvc.zip 7f12cbe3 with the PC 1 host 0e241c94 built at 09:50 in 7 s, the 5b673577 Windows pair 0b144d7d/0cc68d9e, the 0c47b59a app exes ce7f82a6/99edc6aa/d035368e; host.sha256 at a4c5a855), the rule 14 smoke as the gate, then the Windows entry into both folders with the public alias and the card ("Mac, HiveOS and Windows now"); the hash lane's Arc re-read on the rotate-fold kit (packs-ca3-v5-20261008T085619Z.zip 65b47211) and the update-return lane's PC 1 re-probe and PC 2 S4U proof after the smoke. The crossing at DAA 68,400 about 12:54 BST (the node lane's watch on build-1's seed).
|
||||
|
||||
## 24. After the move; 0.3.25 opened the same morning (10:06 to 11:05 BST, 8 October)
|
||||
|
||||
**The first lock on cc902690:** checkpoint 1931, blue score 57,930, at 10:06:32 BST on dn3-g1, 92 seconds after the minute. The move's count: 25 boxes APPLIED by the puller, 11 moved by hand (the three puller faults: the miner sha missing from box-dn3.sh's gate list on 18 miners, the MINE=0 boxes with no env on 11 nodes, the unquoted env-last that took 9 nodes down), p2-3090-1 and p2-4090-1b unreachable, dn3-agg48 joining with its bring-up. The three faults are closed on every box before the next move (the fleet lane, 10:41 BST): the gate list is a file the puller appends to at fetch time, every box holds move/env-last, the puller writes a quoted copy of the environment before sourcing it; a dry move file read FETCHED 38 of 39 at 10:39 BST.
|
||||
|
||||
**0.3.24 Windows did not ship.** Take 2 on PC 2 (installer 2b8774b1 from kit 45836da4, the TDateTime line gone) ran silent without /IGNOTA=1: the stop step closed the 0.3.21 app, then Inno copied no file (every exe still 0.3.21, install-running.flag PRESENT from 09:24:17Z, so the abort fell between PrepareToInstall and the copy), and nothing relaunched the app (the installer's own relaunch is postinstall skipifsilent, or OtaRelaunch on /IGNOTA=1), which left PC 2 without its job runner for 16 minutes until the relay's igneum-agent started the app. Two rules from it: every install job carries /VERYSILENT /NORESTART /IGNOTA=1 and ends on the new engine's --version; the Inno log's reason is the update-return lane's fix on release-0.3.25, known-failed first. The 0.3.24 Windows entry is skipped; the Windows line lands with 0.3.25; the Devnet 3 card publishes on the 0.3.25 Windows entry.
|
||||
|
||||
**0.3.25 opened at 10:2x BST on the founder's word "push 0.3.25 everywhere asap".** release-0.3.25 from release-0.3.24's final tip 45836da4, the version bump first (rule 15): amd-clock-25 e2962b89 (the AMD core-clock ladder; the ADLX telemetry exe 1d8e055d a kit input), tiers-25 d3d0704a (the three-tier Ember Tune, both halves), the Intel rotate-fold header already in the tree through tiers-25 (9088293a), the node-source pin and host.sha256 bc8d4f79 (PC 1, MSVC, 10:37 BST; the one-line form was not read by host-gate.py, so the sha on its own line, the note a comment line above it). Crate gate on build-1 GREEN at e0d4425f (303+35+8, 10:29 BST) and unchanged since; the tip 9b93e649 at 10:58 BST. The node line moved twice under it: 7bd2940f (c6629572 plus unpaid proof records re-announced every 120 s, nothing consensus), then the ceiling cut **e0644958** (proving_fee_ceiling_activation_daa 82,800 in the Devnet 3 object, four gwei per pgas; every gate green 10:53 BST, fast-time SUMMARY PASS 10:54 on the same object; digest 1b37cb9da3911c2e; the 0.3.24 nodes and it refuse each other both ways, so the move is the one-minute form; DAA 82,800 about 16:53 BST; a publish up to DAA 75,600 = 14:53 BST needs no second cut). The Mac pair and DMG on e0644958: Igneum-Miner-0.3.25-e0644958.dmg 501ba293 (45,780,063 B; node pair 556926b1/d2dfe966), staged in both token folders at 11:00 BST; the pair tarball fleet/e0644958-node-lane.tgz fed2f4d6 served. The clock: the pin named at 13:00 BST after the 68,400 crossing reads clean (about 12:54), the fleet publishes m0644-1 on that line, the minute = last FETCHED + 10 (13:40 provisional, never past 14:53), Mac and HiveOS at the minute, Windows within the hour behind on a clean take 3, the card after.
|
||||
|
||||
**The tiers at the class flip (main, 10:4x BST):** a power-capped A4000 reads 17 percent under class v4 at an equal fingerprint under class v5 (the A100 1.3, uncapped consumer cards level), so the engine half gains a class key (a class change invalidates the stored tiers and re-runs the search within ten minutes) and the UI half shows "re-measuring for class v5" and never applies v4 tiers as current after the flip (tiers-class-25 d949e274, green, inert alone). Both ride 0.3.25 only if green together on the release tip by the 13:00 pin, else the tiers ship as gated at d3d0704a and this record states that the v4 tiers may be off by the measured percentage until the re-tune. The knee: the hash lane's 5090 rows at the 1,300 lock under v5 against v4 by 12:30; over 2 percent loss and the knee is re-found under v5 with the percentage, else the v4 knee stands.
|
||||
|
||||
**Signed apps (main's order, built 09:40 to 10:43 BST, signing-pipeline-25 at 075fb413):** packaging/mac/sign-notarize.sh inside build-dmg.sh (Developer ID over the ad hoc signature, hardened runtime, timestamp, notarytool --wait, stapler, spctl read-back; config dir ~/.config/igneum/apple-notary) and packaging/windows/sign.ps1 inside build-installer.ps1 (signtool through a cloud CSP or SSL.com's CodeSignTool; the payload exes before ISCC, Setup and the uninstaller through Inno's SignTool line; config ~/.config/igneum/win-codesign). Every artefact ends in "signed: <identity>" or "unsigned: <reason>" in the log and in <file>.signing, never silent; a present but broken config stops the build; the publisher lives once in packaging/sign/publisher.txt, **Igneum Labs LLC** (the signing entity, Wyoming, filed 8 October 2026; the app's display name stays Igneum Miner). Known-failed self-tests on the pre-push gate (9 Mac cases; the 7 Windows cases run as a PC 2 job). Both config paths absent at the commit; the branch lands on master on PC 2's "7 of 7" line, else 15:00 BST.
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ Every cut of the Igneum Miner app and its node runs under these. The dated plan
|
|||
8. **glibc classes:** HiveOS 2.31 (`--ship hive`, smoke in ubuntu:20.04 on the box), seeds and generic 2.35 (`--ship seed`), fleet 24.04 boxes native 2.39.
|
||||
9. **The Mac builds only the macOS binaries and the DMG,** one at a time under the build lock; every other build, suite and the Windows cross-build runs on the box or a PC; the app gate is `build-remote.sh -- test --release` from the crate dir.
|
||||
10. **A pin is green on its own suites and gates.** Lines taken on one binary carry to another only when the code is byte-identical, stated in the tip. No known-red pins: a stale test takes a test-only commit on top.
|
||||
11. **Kill by pid, never by name,** on the shared Mac; a merge worktree never checks out master.
|
||||
11. **Kill by pid, never by name,** on the shared Mac; a merge worktree never checks out master. Extended 8 October 2026 (twice in one night: the fleet's rescue script at 22:34 BST and the shipper's three-node move at 10:07): a kill or a pgrep by a pattern that the calling shell's own command line carries matches that shell and kills the script before its work; find the victims by process name (pgrep -x igneumd) and the appdir in /proc/<pid>/cmdline, never by `pgrep -f <text that the script itself contains>`; and a node restarted onto a kept datadir waits for the old process to release its RocksDB locks (the seed's first start panicked on meta/LOCK at 10:08 BST; the retry at 10:09 was clean).
|
||||
12. **The Discord card only when every platform is live.** Live manifest changes beyond the binaries (a moved consensus floor) go out only on the founder's explicit word, staged beside the release with their digest and a one-line diff.
|
||||
13. **Ship on green:** no calendar waits; when the gates are green, publish and state the clock time (UK). Checkpoints are for slips, not for waiting.
|
||||
15. **The version bump is the release branch's first commit (7 October 2026, after the 0.3.23 miss).** When a release-0.3.N branch opens, its first commit moves the six version places (app/igneum-app/Cargo.toml and Cargo.lock, app/windows/version.h, app/igneum-app/resources/igneum-app.rc's four fields, packaging/mac/app/Info.plist, the installer's AppVersion), never left to the cut: release-0.3.23 opened at 4cdcab31 and carried 0.3.22 in every place until 21:26 BST, so the app exes and the window host crossed from its first closed tip read 0.3.22 and were void. Gate check: on a push to release-0.3.N the pre-push gate (tools/ci/release-version-check.sh, self-test on tonight's shape first) reads all six places against the branch name and goes red on any mismatch; the .rc was the second layer of the same miss (the box cross failed in build.rs at 21:30 BST).
|
||||
|
|
|
|||
171
infra/build-server/faucet/faucet.mjs
Normal file
171
infra/build-server/faucet/faucet.mjs
Normal file
|
|
@ -0,0 +1,171 @@
|
|||
// The Devnet 3 faucet (the builder programme, 8 October 2026). A Node service behind Caddy at faucet.igneum.network on a build box:
|
||||
// POST /api/faucet {address} sends AMOUNT_IGN of Devnet 3 coin to the address and answers {ok, tx, amount, chainId, to}
|
||||
// GET /api/faucet the state: network, chain id, amount, the faucet's balance in IGN, sends in the last 24 hours
|
||||
// Rules, enforced here and nowhere else: one send per address per WINDOW_HOURS, one per connection (IP) per WINDOW_HOURS,
|
||||
// DAILY_MAX sends per WINDOW_HOURS in total, and AMOUNT_IGN under the HARD_CAP_IGN the fleet lane set on the faucet's own sends
|
||||
// (the service refuses to start otherwise). Sends are serialised so the nonce is read once per send. The record of sends is an
|
||||
// append-only JSONL file next to the service (FAUCET_STATE, default ./grants.jsonl); the window is read from it at start.
|
||||
// Environment (EnvironmentFile=/srv/faucet/env on the box, mode 600; the key is nowhere else): FAUCET_KEY (0x + 64 hex),
|
||||
// FAUCET_RPC (the Devnet 3 node by address, never chosen by chain id: Devnet 3 answers the same id as the shared devnet),
|
||||
// FAUCET_CHAIN_ID (4463), FAUCET_PORT (8790), FAUCET_ORIGIN (the page's origin for CORS, https://igneum.network).
|
||||
// Signing: site/lib/eth.mjs, copied next to this file by faucet.sh (zero dependencies).
|
||||
// node faucet.mjs the service
|
||||
// node faucet.mjs --self-test the limiter and the handler against a fake node: known-failed cases first
|
||||
import { createServer } from 'node:http';
|
||||
import { readFileSync, appendFileSync, existsSync } from 'node:fs';
|
||||
import { dirname, join } from 'node:path';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
|
||||
const here = dirname(fileURLToPath(import.meta.url));
|
||||
const { signTransaction, addressOf, isAddress, toWei } = await import(join(here, 'eth.mjs'));
|
||||
|
||||
export const AMOUNT_IGN = 10;
|
||||
export const HARD_CAP_IGN = 100; // the fleet lane's cap on the faucet's own sends (main's rule, 8 October 2026)
|
||||
export const WINDOW_HOURS = 24;
|
||||
export const DAILY_MAX = 500;
|
||||
const WINDOW_MS = WINDOW_HOURS * 3600 * 1000;
|
||||
|
||||
export function limiter(now = () => Date.now()) {
|
||||
// in memory, fed from the JSONL at start; each row {t, address, ip, tx}
|
||||
const rows = [];
|
||||
const prune = () => { const cut = now() - WINDOW_MS; while (rows.length && rows[0].t < cut) rows.shift(); };
|
||||
return {
|
||||
load(row) { rows.push(row); },
|
||||
check(address, ip) {
|
||||
prune();
|
||||
if (rows.some(r => r.address === address)) return `This address had its ${AMOUNT_IGN} IGN in the last ${WINDOW_HOURS} hours. Come back tomorrow.`;
|
||||
if (rows.some(r => r.ip === ip)) return `This connection had its ${AMOUNT_IGN} IGN in the last ${WINDOW_HOURS} hours. Come back tomorrow.`;
|
||||
if (rows.length >= DAILY_MAX) return `The faucet has sent its ${DAILY_MAX} for today. Come back tomorrow.`;
|
||||
return null;
|
||||
},
|
||||
add(row) { rows.push(row); },
|
||||
drop(row) { const i = rows.indexOf(row); if (i >= 0) rows.splice(i, 1); },
|
||||
count() { prune(); return rows.length; },
|
||||
};
|
||||
}
|
||||
|
||||
export function rpcClient(url, fetchImpl = fetch) {
|
||||
let id = 0;
|
||||
return async (method, params = []) => {
|
||||
const r = await fetchImpl(url, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ jsonrpc: '2.0', id: ++id, method, params }) });
|
||||
const j = await r.json();
|
||||
if (j.error) throw new Error(`${method}: ${j.error.message || JSON.stringify(j.error)}`);
|
||||
return j.result;
|
||||
};
|
||||
}
|
||||
|
||||
const ignOf = wei => (Number(BigInt(wei) / 10n ** 12n) / 1e6).toFixed(6);
|
||||
|
||||
export function createHandler({ env = process.env, rpc, lim, record = () => {}, now = () => Date.now() } = {}) {
|
||||
const key = env.FAUCET_KEY || '', rpcUrl = env.FAUCET_RPC || '';
|
||||
const chainId = Number(env.FAUCET_CHAIN_ID || 4463);
|
||||
const origin = env.FAUCET_ORIGIN || 'https://igneum.network';
|
||||
if (AMOUNT_IGN > HARD_CAP_IGN) throw new Error(`AMOUNT_IGN ${AMOUNT_IGN} is over the ${HARD_CAP_IGN} IGN cap`);
|
||||
if (!/^0x[0-9a-fA-F]{64}$/.test(key) || !rpcUrl) throw new Error('FAUCET_KEY (0x + 64 hex) and FAUCET_RPC are required');
|
||||
const from = addressOf(key);
|
||||
rpc = rpc || rpcClient(rpcUrl);
|
||||
lim = lim || limiter(now);
|
||||
let chain = Promise.resolve(); // sends one after another: one nonce read per send
|
||||
const json = (res, status, body) => { res.writeHead(status, { 'Content-Type': 'application/json', 'Cache-Control': 'no-store' }); res.end(JSON.stringify(body)); };
|
||||
const cors = (req, res) => {
|
||||
const o = req.headers.origin || '';
|
||||
const allowed = o === origin || /^http:\/\/(127\.0\.0\.1|localhost):\d+$/.test(o);
|
||||
res.setHeader('Access-Control-Allow-Origin', allowed ? o : origin);
|
||||
res.setHeader('Vary', 'Origin');
|
||||
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');
|
||||
res.setHeader('Access-Control-Allow-Headers', 'Content-Type');
|
||||
};
|
||||
const clientIp = req => { const fwd = req.headers['x-forwarded-for']; const first = (Array.isArray(fwd) ? fwd[0] : fwd || '').split(',')[0].trim(); return first || String(req.headers['x-real-ip'] || req.socket?.remoteAddress || '').trim() || 'unknown'; };
|
||||
const readBody = req => new Promise((resolve, reject) => { const c = []; let n = 0; req.on('data', d => { n += d.length; if (n > 4096) { reject(new Error('too large')); req.destroy(); } else c.push(d); }); req.on('end', () => { try { resolve(JSON.parse(Buffer.concat(c).toString('utf8') || '{}')); } catch (e) { reject(e); } }); req.on('error', reject); });
|
||||
return async function handler(req, res) {
|
||||
cors(req, res);
|
||||
const path = (req.url || '/').split('?')[0];
|
||||
if (req.method === 'OPTIONS') { res.writeHead(204); return res.end(); }
|
||||
if (path !== '/api/faucet' && path !== '/api/faucet/') return json(res, 404, { ok: false, error: 'not found' });
|
||||
if (req.method === 'GET') {
|
||||
let balance = null;
|
||||
try { balance = ignOf(await rpc('eth_getBalance', [from, 'latest'])); } catch { /* the node is the status */ }
|
||||
return json(res, 200, { ok: true, network: 'igneum-devnet-3', chainId, amount: String(AMOUNT_IGN), window_hours: WINDOW_HOURS, daily_max: DAILY_MAX, address: from, balance_ign: balance, sends_24h: lim.count(), funded: balance !== null && Number(balance) >= AMOUNT_IGN });
|
||||
}
|
||||
if (req.method !== 'POST') { res.setHeader('Allow', 'GET, POST, OPTIONS'); return json(res, 405, { ok: false, error: 'method not allowed' }); }
|
||||
let body;
|
||||
try { body = await readBody(req); } catch { return json(res, 400, { ok: false, error: 'bad json' }); }
|
||||
const address = String(body.address || '').trim();
|
||||
if (!isAddress(address)) return json(res, 400, { ok: false, error: 'That is not an address. It is 0x followed by 40 hex characters.' });
|
||||
const to = address.toLowerCase(), ip = clientIp(req);
|
||||
const refused = lim.check(to, ip);
|
||||
if (refused) return json(res, 429, { ok: false, error: refused });
|
||||
const row = { t: now(), address: to, ip, tx: null };
|
||||
lim.add(row); // reserved before the send, so two asks in the same second cannot both pass
|
||||
const result = chain.then(async () => {
|
||||
const [nonceHex, block, tipHex, balHex] = await Promise.all([
|
||||
rpc('eth_getTransactionCount', [from, 'pending']),
|
||||
rpc('eth_getBlockByNumber', ['latest', false]),
|
||||
rpc('eth_maxPriorityFeePerGas').catch(() => '0x3b9aca00'),
|
||||
rpc('eth_getBalance', [from, 'latest']),
|
||||
]);
|
||||
const value = toWei(AMOUNT_IGN);
|
||||
if (BigInt(balHex) < value * 2n) throw Object.assign(new Error('The faucet is empty right now. It is being refilled; try again in an hour.'), { status: 503 });
|
||||
const baseFee = BigInt(block?.baseFeePerGas || '0x3b9aca00'), tip = BigInt(tipHex || '0x3b9aca00');
|
||||
let gas = 21000n;
|
||||
try { gas = BigInt(await rpc('eth_estimateGas', [{ from, to, value: '0x' + value.toString(16) }])); } catch { /* the plain-transfer default */ }
|
||||
const tx = { chainId, nonce: BigInt(nonceHex), maxPriorityFeePerGas: tip, maxFeePerGas: baseFee * 2n + tip, gas, to, value, data: '0x' };
|
||||
const signed = signTransaction(tx, key);
|
||||
return rpc('eth_sendRawTransaction', [signed.raw]);
|
||||
});
|
||||
chain = result.catch(() => {});
|
||||
try {
|
||||
const hash = await result;
|
||||
row.tx = hash; record(row);
|
||||
return json(res, 200, { ok: true, tx: hash, amount: String(AMOUNT_IGN), chainId, to });
|
||||
} catch (e) {
|
||||
lim.drop(row);
|
||||
return json(res, e.status || 502, { ok: false, error: e.status ? e.message : `The node did not take the transaction: ${String(e.message || e).slice(0, 200)}` });
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
if (process.argv.includes('--self-test')) {
|
||||
// known-failed first: a fake node that answers every read and refuses every send must leave the limiter empty and answer 502
|
||||
let t = 1_000_000; const now = () => t;
|
||||
const fakeNode = (sendOk = true) => async (m, p) => ({
|
||||
eth_getTransactionCount: '0x1', eth_getBlockByNumber: { baseFeePerGas: '0x174876e800' }, eth_maxPriorityFeePerGas: '0x3b9aca00',
|
||||
eth_getBalance: '0x' + (10n ** 21n).toString(16), eth_estimateGas: '0x5208',
|
||||
eth_sendRawTransaction: sendOk ? '0x' + 'ab'.repeat(32) : (() => { throw new Error('refused'); })(),
|
||||
})[m];
|
||||
const call = async (h, method, body, ip = '1.1.1.1') => new Promise(resolve => {
|
||||
const chunks = body === undefined ? [] : [Buffer.from(JSON.stringify(body))];
|
||||
const req = { method, url: '/api/faucet', headers: { 'x-forwarded-for': ip, origin: 'https://igneum.network' }, socket: {}, on(ev, cb) { if (ev === 'data') for (const c of chunks) cb(c); if (ev === 'end') cb(); return this; } };
|
||||
const res = { h: {}, setHeader(k, v) { this.h[k] = v; }, writeHead(s, hh) { this.status = s; Object.assign(this.h, hh || {}); }, end(b) { resolve({ status: this.status, body: b ? JSON.parse(b) : null }); } };
|
||||
h(req, res);
|
||||
});
|
||||
const env = { FAUCET_KEY: '0x' + '11'.repeat(32), FAUCET_RPC: 'http://fake', FAUCET_CHAIN_ID: '4463' };
|
||||
const A = '0x' + 'a1'.repeat(20), B = '0x' + 'b2'.repeat(20);
|
||||
let fails = 0; const expect = (c, msg) => { if (!c) { console.error('self-test failed: ' + msg); fails++; } };
|
||||
{ const lim = limiter(now); const h = createHandler({ env, rpc: fakeNode(false), lim, now }); const r = await call(h, 'POST', { address: A }); expect(r.status === 502 && lim.count() === 0, `a refused send must answer 502 and reserve nothing (got ${r.status}, ${lim.count()})`); }
|
||||
{ const lim = limiter(now); const h = createHandler({ env, rpc: fakeNode(), lim, now }); const r = await call(h, 'POST', { address: 'not-an-address' }); expect(r.status === 400, 'a bad address must answer 400'); }
|
||||
{ const lim = limiter(now); const recorded = []; const h = createHandler({ env, rpc: fakeNode(), lim, record: r => recorded.push(r), now });
|
||||
const r1 = await call(h, 'POST', { address: A }); expect(r1.status === 200 && r1.body.ok && r1.body.tx.startsWith('0x'), 'the first ask sends');
|
||||
expect(recorded.length === 1 && recorded[0].tx === r1.body.tx, 'the send is recorded with its hash');
|
||||
const r2 = await call(h, 'POST', { address: A }); expect(r2.status === 429 && /address/.test(r2.body.error), 'the same address inside the window is refused');
|
||||
const r3 = await call(h, 'POST', { address: B }); expect(r3.status === 429 && /connection/.test(r3.body.error), 'the same connection inside the window is refused');
|
||||
const r4 = await call(h, 'POST', { address: B }, '2.2.2.2'); expect(r4.status === 200, 'another address from another connection sends');
|
||||
t += WINDOW_MS + 1; const r5 = await call(h, 'POST', { address: A }); expect(r5.status === 200, 'after the window the address sends again');
|
||||
const s = await call(h, 'GET'); expect(s.status === 200 && s.body.network === 'igneum-devnet-3' && s.body.sends_24h === 1 && s.body.funded === true, `the status carries the network and the window count (got ${JSON.stringify(s.body)})`);
|
||||
for (let i = 0; i < DAILY_MAX - 1; i++) lim.add({ t: now(), address: '0x' + String(i).padStart(40, '0'), ip: 'x' + i, tx: '0x' });
|
||||
const r6 = await call(h, 'POST', { address: '0x' + 'c3'.repeat(20) }, '3.3.3.3'); expect(r6.status === 429 && /today/.test(r6.body.error), 'the daily total refuses the next ask'); }
|
||||
{ let threw = false; try { createHandler({ env: { ...env, FAUCET_KEY: 'bad' }, rpc: fakeNode(), now }); } catch { threw = true; } expect(threw, 'a bad key must refuse to start'); }
|
||||
expect(AMOUNT_IGN <= HARD_CAP_IGN, 'the amount is under the cap');
|
||||
if (fails) process.exit(1);
|
||||
console.log(`self-test passed: a refused send reserves nothing (502), a bad address 400, the same address and the same connection are refused inside ${WINDOW_HOURS} h (429), another pair sends, the window expires, the status counts, the ${DAILY_MAX}-a-day total refuses, a bad key refuses to start, ${AMOUNT_IGN} IGN is under the ${HARD_CAP_IGN} IGN cap`);
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
if (process.argv[1] && fileURLToPath(import.meta.url) === process.argv[1] && !process.argv.includes('--self-test')) {
|
||||
const STATE = process.env.FAUCET_STATE || join(here, 'grants.jsonl');
|
||||
const lim = limiter();
|
||||
if (existsSync(STATE)) { const cut = Date.now() - WINDOW_MS; for (const l of readFileSync(STATE, 'utf8').split('\n')) { if (!l) continue; try { const r = JSON.parse(l); if (r.t >= cut && r.tx) lim.load(r); } catch { /* a torn line */ } } }
|
||||
const handler = createHandler({ lim, record: row => appendFileSync(STATE, JSON.stringify(row) + '\n') });
|
||||
const port = Number(process.env.FAUCET_PORT || 8790);
|
||||
createServer((req, res) => { handler(req, res).catch(e => { try { res.writeHead(500, { 'Content-Type': 'application/json' }); res.end(JSON.stringify({ ok: false, error: String(e.message || e).slice(0, 200) })); } catch { /* closed */ } }); }).listen(port, '127.0.0.1', () => console.log(`${new Date().toISOString()} faucet on 127.0.0.1:${port}, ${AMOUNT_IGN} IGN per send, ${lim.count()} sends in the window, from ${addressOf(process.env.FAUCET_KEY)}`));
|
||||
}
|
||||
62
infra/build-server/faucet/faucet.sh
Executable file
62
infra/build-server/faucet/faucet.sh
Executable file
|
|
@ -0,0 +1,62 @@
|
|||
#!/usr/bin/env bash
|
||||
# The Devnet 3 faucet on a build box (the builder programme, 8 October 2026). Dry run by default, --go executes.
|
||||
# infra/build-server/faucet/faucet.sh install [--go] copy faucet.mjs and site/lib/eth.mjs to /srv/faucet (the build user's), the unit
|
||||
# to /etc/systemd/system, the Caddy block for faucet.igneum.network (validate, reload),
|
||||
# enable and start the unit, read back GET /api/faucet through the loopback
|
||||
# infra/build-server/faucet/faucet.sh status the unit, the loopback status (balance, sends in the window), the Caddy host
|
||||
# infra/build-server/faucet/faucet.sh self-test node faucet.mjs --self-test on the box
|
||||
# /srv/faucet/env (mode 600, the build user's) is written by hand on the box and never by this script: FAUCET_KEY, FAUCET_RPC
|
||||
# (the Devnet 3 node by address), FAUCET_CHAIN_ID, FAUCET_PORT, FAUCET_ORIGIN. The key is nowhere else.
|
||||
set -euo pipefail
|
||||
HERE=$(cd "$(dirname "$0")" && pwd); ROOT=$(cd "$HERE/../../.." && pwd)
|
||||
KEY="${IGNEUM_BUILD_KEY:-$HOME/.ssh/igneum_ed25519}"; HOST=$(head -1 "${IGNEUM_BUILD_HOST_FILE:-$HOME/.config/igneum/build-server}" | tr -d '[:space:]')
|
||||
IP="${HOST#*@}"
|
||||
SSHB=(ssh -i "$KEY" -o BatchMode=yes -o ConnectTimeout=15 "$HOST")
|
||||
SSHR=(ssh -i "$KEY" -o BatchMode=yes -o ConnectTimeout=15 "root@$IP")
|
||||
say() { echo "$(TZ=UTC date '+%H:%M:%SZ') faucet: $*" >&2; }
|
||||
mode="${1:-}"; shift || true; GO=0; [ "${1:-}" = --go ] && GO=1
|
||||
FAUCET_HOST="${FAUCET_HOST:-faucet.igneum.network}"; PORT="${FAUCET_PORT:-8790}"
|
||||
caddy_block() { cat <<EOF
|
||||
|
||||
# the Devnet 3 faucet (infra/build-server/faucet, 8 October 2026): one Node service on the loopback, nothing cached
|
||||
$FAUCET_HOST {
|
||||
tls {
|
||||
issuer acme
|
||||
}
|
||||
reverse_proxy 127.0.0.1:$PORT
|
||||
header Cache-Control "no-store"
|
||||
request_body {
|
||||
max_size 16KB
|
||||
}
|
||||
}
|
||||
EOF
|
||||
}
|
||||
case "$mode" in
|
||||
install)
|
||||
[ -s "$ROOT/site/lib/eth.mjs" ] || { say "no site/lib/eth.mjs under $ROOT"; exit 1; }
|
||||
if [ "$GO" = 0 ]; then
|
||||
say "DRY: scp faucet.mjs, site/lib/eth.mjs -> $HOST:/srv/faucet/; igneum-faucet.service -> root@$IP:/etc/systemd/system/; append to /etc/caddy/Caddyfile unless $FAUCET_HOST is there:"; caddy_block; say "DRY: systemctl daemon-reload, enable --now igneum-faucet; curl 127.0.0.1:$PORT/api/faucet"; exit 0
|
||||
fi
|
||||
"${SSHB[@]}" 'test -s /srv/faucet/env' || { say "/srv/faucet/env is missing on the box: write it by hand first (FAUCET_KEY, FAUCET_RPC, FAUCET_CHAIN_ID, FAUCET_PORT, FAUCET_ORIGIN)"; exit 1; }
|
||||
scp -q -i "$KEY" "$HERE/faucet.mjs" "$ROOT/site/lib/eth.mjs" "$HOST:/srv/faucet/"
|
||||
"${SSHB[@]}" 'cd /srv/faucet && node faucet.mjs --self-test' || { say "the self-test failed on the box; nothing started"; exit 1; }
|
||||
scp -q -i "$KEY" "$HERE/igneum-faucet.service" "root@$IP:/etc/systemd/system/igneum-faucet.service"
|
||||
"${SSHR[@]}" bash -s -- "$FAUCET_HOST" "$(caddy_block | base64 | tr -d '\n')" <<'REMOTE'
|
||||
set -euo pipefail; host="$1"; block="$(printf '%s' "$2" | base64 -d)"
|
||||
if ! grep -q "^$host {" /etc/caddy/Caddyfile; then
|
||||
cp /etc/caddy/Caddyfile "/etc/caddy/Caddyfile.bak-$(date -u +%Y%m%d%H%M%S)"
|
||||
printf '%s\n' "$block" >> /etc/caddy/Caddyfile
|
||||
caddy validate --config /etc/caddy/Caddyfile --adapter caddyfile >/dev/null
|
||||
systemctl reload caddy; echo "caddy: $host block appended and reloaded"
|
||||
else echo "caddy: $host block already present"; fi
|
||||
systemctl daemon-reload; systemctl enable igneum-faucet >/dev/null 2>&1; systemctl restart igneum-faucet; sleep 3; systemctl is-active igneum-faucet; journalctl -u igneum-faucet --since "-30 s" --no-pager | tail -2 | cut -c1-160
|
||||
REMOTE
|
||||
"${SSHB[@]}" "curl -s -m 10 http://127.0.0.1:$PORT/api/faucet; echo"
|
||||
;;
|
||||
status)
|
||||
"${SSHR[@]}" "systemctl is-active igneum-faucet; journalctl -u igneum-faucet --since '-10 min' --no-pager | tail -5 | cut -c1-160; grep -c '^$FAUCET_HOST {' /etc/caddy/Caddyfile"
|
||||
"${SSHB[@]}" "curl -s -m 10 http://127.0.0.1:$PORT/api/faucet; echo; wc -l /srv/faucet/grants.jsonl 2>/dev/null || echo 'no sends yet'"
|
||||
;;
|
||||
self-test) "${SSHB[@]}" 'cd /srv/faucet && node faucet.mjs --self-test' ;;
|
||||
*) sed -n '2,10p' "$0" | sed 's/^# \{0,1\}//'; exit 2 ;;
|
||||
esac
|
||||
22
infra/build-server/faucet/igneum-faucet.service
Normal file
22
infra/build-server/faucet/igneum-faucet.service
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
[Unit]
|
||||
Description=Igneum Devnet 3 faucet (infra/build-server/faucet/faucet.mjs), 127.0.0.1:8790 behind Caddy at faucet.igneum.network
|
||||
After=network-online.target
|
||||
Wants=network-online.target
|
||||
|
||||
[Service]
|
||||
User=build
|
||||
Group=build
|
||||
WorkingDirectory=/srv/faucet
|
||||
EnvironmentFile=/srv/faucet/env
|
||||
Environment=FAUCET_STATE=/srv/faucet/grants.jsonl
|
||||
ExecStart=/usr/local/bin/node /srv/faucet/faucet.mjs
|
||||
Restart=always
|
||||
RestartSec=5
|
||||
Nice=5
|
||||
NoNewPrivileges=true
|
||||
ProtectSystem=strict
|
||||
ReadWritePaths=/srv/faucet
|
||||
PrivateTmp=true
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
|
|
@ -79,6 +79,10 @@
|
|||
"vdf_scheme": 0,
|
||||
"era_vdf_t": 108000000,
|
||||
"fees_v1_activation_daa": 0,
|
||||
"proving_fee_ceiling_activation_daa": null,
|
||||
"proving_base_fee_ceiling_multiple": null,
|
||||
"difficulty_v3_activation_daa": 18446744073709551615,
|
||||
"finality_daa_rule_activation_daa": 18446744073709551615,
|
||||
"fork_gate_activation_daa": 18446744073709551615,
|
||||
"fork_gate_window_daa": 600,
|
||||
"vote_or_burn_activation_daa": 18446744073709551615,
|
||||
|
|
@ -96,5 +100,9 @@
|
|||
"latency_ladder_cache_rung": {"mib": 512, "admissible": false},
|
||||
"latency_ladder_cache_rung_activation_daa": 18446744073709551615,
|
||||
"fees": {"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},
|
||||
"peer_directory_activation_daa": null
|
||||
"peer_directory_activation_daa": null,
|
||||
"subsidy_per_block_activation_daa": null,
|
||||
"pool_split_activation_daa": null,
|
||||
"program_class_v5_activation_daa": null,
|
||||
"base_unit_decimals": 8
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,20 +1,150 @@
|
|||
{
|
||||
"version": 1,
|
||||
"doc": "scene/feed-contract.md: the one JSON shape the chain scene reads, from the observer's /api/live and from the miner app's api/live alike",
|
||||
"top": ["ok", "now", "state", "blocks", "miners", "events", "finality", "proving"],
|
||||
"top_extensions": ["partial"],
|
||||
"state": ["stale", "age_s", "network", "node_version", "height", "block_count", "header_count", "blue_score", "difficulty", "hashes_per_second_estimate", "peers", "mempool", "blocks_60s", "blocks_per_second_60s", "blocks_per_minute", "miners_10m", "observer_started_at", "observer_lag_s", "queue_depth", "updated_at"],
|
||||
"state_extensions": ["source", "you_blocks", "node"],
|
||||
"block": ["hash", "number", "blue_score", "daa", "ts", "rx", "parents", "chain", "miner", "color", "locked", "final", "shards", "proven"],
|
||||
"miner": ["id", "blocks", "share", "last_seen", "engine"],
|
||||
"event": ["ts", "kind", "text"],
|
||||
"finality": ["supported", "active", "next_index", "latest_locked_index", "latest_locked_hash", "latest_locked_blue_score", "params", "weights", "checkpoints"],
|
||||
"checkpoint": ["index", "hash", "blue_score", "daa", "state", "signed", "active", "total", "fraction_active", "fraction_total", "votes", "voters", "locked_at", "updated_at"],
|
||||
"shard": ["i", "n", "state", "prover", "lag", "payout", "pgas"],
|
||||
"proving_unsupported": ["supported", "reason"],
|
||||
"proving_supported": ["supported", "active", "activation_daa", "tip_daa", "verifier", "pool", "paid_shards_total", "shard_budget_pgas", "blocks_10m", "blocks_fully_proven_10m", "shards_proven_10m", "shards_paid_10m", "median_proof_lag_s", "provers_10m"],
|
||||
"color": ["blue", "red", "pending"],
|
||||
"shard_state": ["planned", "proving", "verified", "paid"],
|
||||
"checkpoint_state": ["pending", "locked"],
|
||||
"doc": "scene/feed-contract.md: the one JSON shape the chain scene reads, from the observer's /api/live and from the miner app's api/live alike 8 October 2026: proving carries its own health beside the counts (stale, stale_reason, status_age_s, tip_lag_daa, records_10m, last_change_at; site/lib/proving-health.mjs): the observer's node can stop crediting payouts while the DAG feed stays live, and the page says so instead of showing a frozen paid total as fresh.",
|
||||
"top": [
|
||||
"ok",
|
||||
"now",
|
||||
"state",
|
||||
"blocks",
|
||||
"miners",
|
||||
"events",
|
||||
"finality",
|
||||
"proving"
|
||||
],
|
||||
"top_extensions": [
|
||||
"partial"
|
||||
],
|
||||
"state": [
|
||||
"stale",
|
||||
"age_s",
|
||||
"network",
|
||||
"node_version",
|
||||
"height",
|
||||
"block_count",
|
||||
"header_count",
|
||||
"blue_score",
|
||||
"difficulty",
|
||||
"hashes_per_second_estimate",
|
||||
"peers",
|
||||
"mempool",
|
||||
"blocks_60s",
|
||||
"blocks_per_second_60s",
|
||||
"blocks_per_minute",
|
||||
"miners_10m",
|
||||
"observer_started_at",
|
||||
"observer_lag_s",
|
||||
"queue_depth",
|
||||
"updated_at"
|
||||
],
|
||||
"state_extensions": [
|
||||
"source",
|
||||
"you_blocks",
|
||||
"node"
|
||||
],
|
||||
"block": [
|
||||
"hash",
|
||||
"number",
|
||||
"blue_score",
|
||||
"daa",
|
||||
"ts",
|
||||
"rx",
|
||||
"parents",
|
||||
"chain",
|
||||
"miner",
|
||||
"color",
|
||||
"locked",
|
||||
"final",
|
||||
"shards",
|
||||
"proven"
|
||||
],
|
||||
"miner": [
|
||||
"id",
|
||||
"blocks",
|
||||
"share",
|
||||
"last_seen",
|
||||
"engine"
|
||||
],
|
||||
"event": [
|
||||
"ts",
|
||||
"kind",
|
||||
"text"
|
||||
],
|
||||
"finality": [
|
||||
"supported",
|
||||
"active",
|
||||
"next_index",
|
||||
"latest_locked_index",
|
||||
"latest_locked_hash",
|
||||
"latest_locked_blue_score",
|
||||
"params",
|
||||
"weights",
|
||||
"checkpoints"
|
||||
],
|
||||
"checkpoint": [
|
||||
"index",
|
||||
"hash",
|
||||
"blue_score",
|
||||
"daa",
|
||||
"state",
|
||||
"signed",
|
||||
"active",
|
||||
"total",
|
||||
"fraction_active",
|
||||
"fraction_total",
|
||||
"votes",
|
||||
"voters",
|
||||
"locked_at",
|
||||
"updated_at"
|
||||
],
|
||||
"shard": [
|
||||
"i",
|
||||
"n",
|
||||
"state",
|
||||
"prover",
|
||||
"lag",
|
||||
"payout",
|
||||
"pgas"
|
||||
],
|
||||
"proving_unsupported": [
|
||||
"supported",
|
||||
"reason"
|
||||
],
|
||||
"proving_supported": [
|
||||
"supported",
|
||||
"active",
|
||||
"activation_daa",
|
||||
"tip_daa",
|
||||
"verifier",
|
||||
"pool",
|
||||
"paid_shards_total",
|
||||
"shard_budget_pgas",
|
||||
"blocks_10m",
|
||||
"blocks_fully_proven_10m",
|
||||
"shards_proven_10m",
|
||||
"shards_paid_10m",
|
||||
"median_proof_lag_s",
|
||||
"provers_10m",
|
||||
"stale",
|
||||
"stale_reason",
|
||||
"status_age_s",
|
||||
"tip_lag_daa",
|
||||
"records_10m",
|
||||
"last_change_at"
|
||||
],
|
||||
"color": [
|
||||
"blue",
|
||||
"red",
|
||||
"pending"
|
||||
],
|
||||
"shard_state": [
|
||||
"planned",
|
||||
"proving",
|
||||
"verified",
|
||||
"paid"
|
||||
],
|
||||
"checkpoint_state": [
|
||||
"pending",
|
||||
"locked"
|
||||
],
|
||||
"miner_id": "^[0-9a-f]{8}$"
|
||||
}
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
|
|
@ -1,5 +1,7 @@
|
|||
/* Igneum DAG / Ember 2.0 (the EMBER 02 renderer pack, 7 Oct 2026). THE SHARED SOURCE: scene/live-dag.js; site/live-dag.js and
|
||||
* app/igneum-app/ui/live-dag.js are byte-equal copies written by tools/scene/sync.mjs (the gate refuses a drifted copy). Edit here.
|
||||
* 2.0.7 (8 Oct 2026): a chain block whose plan is known (block.number set, carried as plan on the normalised block) and empty reads
|
||||
* "no shards in this block"; the loading and late sentences stay for a plan the observer has not read; the fixed sentence of 2.0.5 is gone.
|
||||
* 2.0.6 (7 Oct 2026): IgneumDag.shardWords(block, nowMs) is the one shard sentence (tooltip, /live inspector, app inspector); the
|
||||
* empty case reads from the block's facts (loading, excluded, not yet ordered, off the chain) instead of one fixed sentence.
|
||||
* 2.0.5 (key-22, 7 Oct 2026): IgneumDag.legend({mine}) and renderLegend(el,{mine}) are the one key both pages render; the app's
|
||||
|
|
@ -46,14 +48,14 @@
|
|||
function cloneBlock(b) {
|
||||
return {hash:b.hash,ts:b.ts,blue_score:b.blue_score,blue:b.blue_score,daa:b.daa,
|
||||
parents:b.parents.slice(),chain:b.chain,color:b.color,miner:b.miner,locked:b.locked,
|
||||
final:b.final,proven:b.proven,shards:b.shards.map(function(s){return {state:s.state};})};
|
||||
final:b.final,proven:b.proven,plan:b.plan,shards:b.shards.map(function(s){return {state:s.state};})};
|
||||
}
|
||||
function normalize(b) {
|
||||
if (!b || typeof b.hash !== 'string' || !b.hash.length || b.hash.length>256 || !finite(b.ts) || b.ts<0) return null;
|
||||
return {hash:b.hash,ts:b.ts,blue_score:num(b.blue_score),daa:num(b.daa),
|
||||
parents:Array.isArray(b.parents)?Array.from(new Set(b.parents.filter(function(p){return typeof p==='string' && p!==b.hash;}))).slice(0,128):[],
|
||||
chain:b.chain===true,color:['blue','red','pending'].includes(b.color)?b.color:'pending',
|
||||
miner:typeof b.miner==='string'?b.miner.slice(0,256):'unknown',locked:b.locked===true,final:b.final===true,proven:b.proven===true,
|
||||
miner:typeof b.miner==='string'?b.miner.slice(0,256):'unknown',locked:b.locked===true,final:b.final===true,proven:b.proven===true,plan:finite(b.number),
|
||||
shards:Array.isArray(b.shards)?b.shards.slice(0,256).map(function(s){return {state:s && ['planned','proving','verified','paid'].includes(s.state)?s.state:'unknown'};}):[]};
|
||||
}
|
||||
function mount(canvas, opts) {
|
||||
|
|
@ -393,6 +395,7 @@
|
|||
if(b.color==='red')return {summary:'excluded, nothing to prove',items:[],state:'excluded'};
|
||||
if(b.color!=='blue')return {summary:'not yet ordered',items:[],state:'pending'};
|
||||
if(!b.chain)return {summary:'off the selected chain, no shards planned',items:[],state:'none'};
|
||||
if(b.plan===true)return {summary:'no shards in this block',items:[],state:'none'};
|
||||
if(age<10)return {summary:'shard plan loading',items:[],state:'loading'};
|
||||
return {summary:'no shard plan after '+ageWord(age),items:[],state:'late'};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -60,6 +60,7 @@ main{flex:1}
|
|||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-mine" data-group="mine" aria-expanded="false" aria-controls="nav-panel-mine" aria-haspopup="true">Mine<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-network" data-group="network" aria-expanded="false" aria-controls="nav-panel-network" aria-haspopup="true">Network<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-learn" data-group="learn" aria-expanded="false" aria-controls="nav-panel-learn" aria-haspopup="true">Learn<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-build" data-group="build" aria-expanded="false" aria-controls="nav-panel-build" aria-haspopup="true">Build<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
</div>
|
||||
<div class="nav-controls">
|
||||
<button class="btn icon-btn" type="button" data-theme-toggle aria-label="Switch to light theme"><svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><circle cx="12" cy="12" r="4"/><path d="M12 2v2m0 16v2M2 12h2m16 0h2M5 5l1 1m12 12 1 1M5 19l1-1M18 6l1-1"/></svg></button>
|
||||
|
|
@ -77,7 +78,6 @@ main{flex:1}
|
|||
<a href="/wallet" data-nav="wallet"><b>The wallet</b><span>Your coins. Final means final.</span></a>
|
||||
<a href="/miners" data-nav="miners"><b>GPU bench table</b><span>Measured rates, card by card.</span></a>
|
||||
<a href="/dev-fee" data-nav="dev-fee"><b>The dev fee</b><span>The optional one, in full view, off with one flag.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Testnet faucet</b><span>Test coin for an address, once a day.</span></a>
|
||||
<a href="/metamask" data-nav="metamask"><b>Add to MetaMask</b><span>Igneum as a network in your wallet.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -88,6 +88,9 @@ main{flex:1}
|
|||
<a href="/journey" data-nav="journey"><b>The journey</b><span>Six phases, four gates, the log behind them.</span></a>
|
||||
<a href="/bench" data-nav="bench"><b>Engineering log</b><span>Every measurement, with the commands that made it.</span></a>
|
||||
<a href="/evidence" data-nav="evidence"><b>Evidence</b><span>Every claim and how far it is tested.</span></a>
|
||||
<a href="/light" data-nav="light"><b>Light wallet</b><span>A balance your browser proves, trusting no node.</span></a>
|
||||
<a href="/receipt" data-nav="receipt"><b>Payment receipt</b><span>A receipt any third party re-verifies offline.</span></a>
|
||||
<a href="/oracle" data-nav="oracle"><b>State oracle on Sepolia</b><span>Devnet 3 balances read from another chain.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-panel" id="nav-panel-learn" data-group="learn" role="region" aria-labelledby="nav-btn-learn" hidden>
|
||||
|
|
@ -100,6 +103,14 @@ main{flex:1}
|
|||
<a href="/provenance" data-nav="provenance"><b>Built on the shoulders</b><span>Every borrowed part, credited.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-panel" id="nav-panel-build" data-group="build" role="region" aria-labelledby="nav-btn-build" hidden>
|
||||
<div class="panel-list">
|
||||
<a href="/build" data-nav="build"><b>Build on Igneum</b><span>Chain ids, RPC, a contract in five minutes.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Devnet faucet</b><span>10 IGN of devnet coin, once a day.</span></a>
|
||||
<a href="/swap" data-nav="swap"><b>Swap</b><span>Test tokens on Devnet 3; every swap is a proven block.</span></a>
|
||||
<a href="/grants" data-nav="grants"><b>Grants</b><span>Tooling, apps, infrastructure, research.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-sheet" id="nav-sheet" role="dialog" aria-modal="true" aria-label="Menu" hidden>
|
||||
|
|
@ -111,7 +122,6 @@ main{flex:1}
|
|||
<a href="/wallet" data-nav="wallet"><b>The wallet</b><span>Your coins. Final means final.</span></a>
|
||||
<a href="/miners" data-nav="miners"><b>GPU bench table</b><span>Measured rates, card by card.</span></a>
|
||||
<a href="/dev-fee" data-nav="dev-fee"><b>The dev fee</b><span>The optional one, in full view, off with one flag.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Testnet faucet</b><span>Test coin for an address, once a day.</span></a>
|
||||
<a href="/metamask" data-nav="metamask"><b>Add to MetaMask</b><span>Igneum as a network in your wallet.</span></a>
|
||||
</div>
|
||||
<div class="sheet-group"><div class="sheet-head">Network</div>
|
||||
|
|
@ -120,6 +130,9 @@ main{flex:1}
|
|||
<a href="/journey" data-nav="journey"><b>The journey</b><span>Six phases, four gates, the log behind them.</span></a>
|
||||
<a href="/bench" data-nav="bench"><b>Engineering log</b><span>Every measurement, with the commands that made it.</span></a>
|
||||
<a href="/evidence" data-nav="evidence"><b>Evidence</b><span>Every claim and how far it is tested.</span></a>
|
||||
<a href="/light" data-nav="light"><b>Light wallet</b><span>A balance your browser proves, trusting no node.</span></a>
|
||||
<a href="/receipt" data-nav="receipt"><b>Payment receipt</b><span>A receipt any third party re-verifies offline.</span></a>
|
||||
<a href="/oracle" data-nav="oracle"><b>State oracle on Sepolia</b><span>Devnet 3 balances read from another chain.</span></a>
|
||||
</div>
|
||||
<div class="sheet-group"><div class="sheet-head">Learn</div>
|
||||
<a href="/litepaper" data-nav="litepaper"><b>Litepaper</b><span>The design, as published.</span></a>
|
||||
|
|
@ -129,6 +142,12 @@ main{flex:1}
|
|||
<a href="/randomx" data-nav="randomx"><b>Igneum vs RandomX</b><span>What was kept and what was rebuilt for GPUs.</span></a>
|
||||
<a href="/provenance" data-nav="provenance"><b>Built on the shoulders</b><span>Every borrowed part, credited.</span></a>
|
||||
</div>
|
||||
<div class="sheet-group"><div class="sheet-head">Build</div>
|
||||
<a href="/build" data-nav="build"><b>Build on Igneum</b><span>Chain ids, RPC, a contract in five minutes.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Devnet faucet</b><span>10 IGN of devnet coin, once a day.</span></a>
|
||||
<a href="/swap" data-nav="swap"><b>Swap</b><span>Test tokens on Devnet 3; every swap is a proven block.</span></a>
|
||||
<a href="/grants" data-nav="grants"><b>Grants</b><span>Tooling, apps, infrastructure, research.</span></a>
|
||||
</div>
|
||||
<div class="sheet-foot">
|
||||
<a href="/download" class="btn primary big" data-nav="download">Download</a>
|
||||
<div class="sheet-social"><a href="https://discord.gg/igneum" target="_blank" rel="noopener">Discord</a><a href="https://git.igneum.network/igneum-network/spec" target="_blank" rel="noopener">Source</a><a href="https://www.reddit.com/user/Igneum_network/" target="_blank" rel="noopener">Reddit</a></div>
|
||||
|
|
@ -218,7 +237,7 @@ main{flex:1}
|
|||
<a href="/wallet">The wallet</a>
|
||||
<a href="/miners">GPU bench table</a>
|
||||
<a href="/dev-fee">The dev fee</a>
|
||||
<a href="/faucet">Testnet faucet</a>
|
||||
<a href="/faucet">Devnet faucet</a>
|
||||
<a href="/metamask">Add Igneum to MetaMask</a>
|
||||
</div></div>
|
||||
<div class="footer-column"><h4>Read</h4><div>
|
||||
|
|
@ -233,6 +252,9 @@ main{flex:1}
|
|||
<div class="footer-column"><h4>Explore</h4><div>
|
||||
<a href="/live">Live devnet</a>
|
||||
<a href="/explorer">Explorer</a>
|
||||
<a href="/build">Build on Igneum</a>
|
||||
<a href="/swap">Swap</a>
|
||||
<a href="/grants">Grants</a>
|
||||
<a href="/journey">Journey</a>
|
||||
<a href="/download">Downloads: devnet build</a>
|
||||
<a href="https://discord.gg/igneum" target="_blank" rel="noopener">Community Discord</a>
|
||||
|
|
|
|||
|
|
@ -3,15 +3,15 @@
|
|||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
|
||||
<title>Igneum address</title>
|
||||
<meta name="description" content="One Igneum address: the blocks it mined in the last day, what they earned, and its balance.">
|
||||
<title>Igneum Devnet 3 address</title>
|
||||
<meta name="description" content="One Devnet 3 address: its balance, nonce and code, its transactions of the last seven days, the blocks it mined in the last day and what they earned.">
|
||||
<link rel="canonical" href="https://igneum.network/address">
|
||||
<meta name="robots" content="noindex">
|
||||
<meta name="theme-color" content="#0C0C0E">
|
||||
<meta property="og:type" content="website">
|
||||
<meta property="og:site_name" content="Igneum">
|
||||
<meta property="og:title" content="Igneum address">
|
||||
<meta property="og:description" content="One Igneum address: the blocks it mined in the last day, what they earned, and its balance.">
|
||||
<meta property="og:description" content="One Devnet 3 address: its balance, nonce and code, its transactions of the last seven days, the blocks it mined in the last day and what they earned.">
|
||||
<meta property="og:url" content="https://igneum.network/address">
|
||||
<meta property="og:image" content="https://igneum.network/og-small.png?v=3">
|
||||
<meta property="og:image:width" content="256">
|
||||
|
|
@ -19,7 +19,7 @@
|
|||
<meta property="og:image:alt" content="Igneum. Mined by GPUs. Proven by fire.">
|
||||
<meta name="twitter:card" content="summary">
|
||||
<meta name="twitter:title" content="Igneum address">
|
||||
<meta name="twitter:description" content="One Igneum address: the blocks it mined in the last day, what they earned, and its balance.">
|
||||
<meta name="twitter:description" content="One Devnet 3 address: its balance, nonce and code, its transactions of the last seven days, the blocks it mined in the last day and what they earned.">
|
||||
<meta name="twitter:image" content="https://igneum.network/og-small.png?v=3">
|
||||
<meta name="twitter:image:alt" content="Igneum. Mined by GPUs. Proven by fire.">
|
||||
<link rel="icon" href="/favicon.ico" sizes="48x48">
|
||||
|
|
@ -92,6 +92,12 @@ dd{margin:0;overflow-wrap:anywhere;font-variant-numeric:tabular-nums}
|
|||
@media (min-width:900px){.two{grid-template-columns:1fr 1fr}.two .card{margin-top:0}}
|
||||
.two-wrap{margin-top:var(--gap)}
|
||||
main{padding-bottom:100px}.card{background:var(--row);border:1px solid var(--line);border-radius:16px;padding:25px;margin-top:24px}.card .viz-head h2{font-size:19px}.card .viz-head .eyebrow{margin:0}
|
||||
.badge{display:inline-flex;align-items:center;gap:6px;font-family:var(--f-mono);font-size:11px;letter-spacing:.06em;text-transform:uppercase;padding:4px 9px;border-radius:999px;border:1px solid var(--line-2);color:var(--ink-2);margin:0 6px 6px 0}
|
||||
.badge.ok{border-color:var(--green,#5CC48A);color:var(--green,#5CC48A)}.badge.hot{border-color:var(--molten);color:var(--molten)}.badge.bad{border-color:var(--excluded);color:var(--excluded)}.badge.wait{color:var(--ash)}
|
||||
.bar{display:inline-block;width:72px;height:7px;border-radius:4px;background:var(--line);vertical-align:middle;margin-right:7px;overflow:hidden}.bar i{display:block;height:100%;background:var(--green,#5CC48A)}.bar i.part{background:var(--molten)}
|
||||
.dagbox{position:relative;width:100%;height:320px;border:1px solid var(--line);border-radius:12px;background:var(--obsidian);overflow:hidden}.dagbox canvas{width:100%;height:100%;display:block;cursor:pointer}
|
||||
.dagtip{position:absolute;pointer-events:none;font:11px/1.5 var(--mono);color:var(--bone);background:var(--graphite);border:1px solid var(--line-2);border-radius:8px;padding:8px 10px;max-width:300px;display:none}
|
||||
.kv{color:var(--ash)}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
|
@ -108,6 +114,7 @@ main{padding-bottom:100px}.card{background:var(--row);border:1px solid var(--lin
|
|||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-mine" data-group="mine" aria-expanded="false" aria-controls="nav-panel-mine" aria-haspopup="true">Mine<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-network" data-group="network" data-active aria-expanded="false" aria-controls="nav-panel-network" aria-haspopup="true">Network<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-learn" data-group="learn" aria-expanded="false" aria-controls="nav-panel-learn" aria-haspopup="true">Learn<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-build" data-group="build" aria-expanded="false" aria-controls="nav-panel-build" aria-haspopup="true">Build<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
</div>
|
||||
<div class="nav-controls">
|
||||
<button class="btn icon-btn" type="button" data-theme-toggle aria-label="Switch to light theme"><svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><circle cx="12" cy="12" r="4"/><path d="M12 2v2m0 16v2M2 12h2m16 0h2M5 5l1 1m12 12 1 1M5 19l1-1M18 6l1-1"/></svg></button>
|
||||
|
|
@ -125,17 +132,19 @@ main{padding-bottom:100px}.card{background:var(--row);border:1px solid var(--lin
|
|||
<a href="/wallet" data-nav="wallet"><b>The wallet</b><span>Your coins. Final means final.</span></a>
|
||||
<a href="/miners" data-nav="miners"><b>GPU bench table</b><span>Measured rates, card by card.</span></a>
|
||||
<a href="/dev-fee" data-nav="dev-fee"><b>The dev fee</b><span>The optional one, in full view, off with one flag.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Testnet faucet</b><span>Test coin for an address, once a day.</span></a>
|
||||
<a href="/metamask" data-nav="metamask"><b>Add to MetaMask</b><span>Igneum as a network in your wallet.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-panel" id="nav-panel-network" data-group="network" role="region" aria-labelledby="nav-btn-network" hidden>
|
||||
<div class="panel-list">
|
||||
<a href="/live" data-nav="live" aria-current="page"><b>Live devnet</b><span>The chain as it grows, one lane per miner.</span></a>
|
||||
<a href="/explorer" data-nav="explorer"><b>Explorer</b><span>Look a block or an address up.</span></a>
|
||||
<a href="/live" data-nav="live"><b>Live devnet</b><span>The chain as it grows, one lane per miner.</span></a>
|
||||
<a href="/explorer" data-nav="explorer" aria-current="page"><b>Explorer</b><span>Look a block or an address up.</span></a>
|
||||
<a href="/journey" data-nav="journey"><b>The journey</b><span>Six phases, four gates, the log behind them.</span></a>
|
||||
<a href="/bench" data-nav="bench"><b>Engineering log</b><span>Every measurement, with the commands that made it.</span></a>
|
||||
<a href="/evidence" data-nav="evidence"><b>Evidence</b><span>Every claim and how far it is tested.</span></a>
|
||||
<a href="/light" data-nav="light"><b>Light wallet</b><span>A balance your browser proves, trusting no node.</span></a>
|
||||
<a href="/receipt" data-nav="receipt"><b>Payment receipt</b><span>A receipt any third party re-verifies offline.</span></a>
|
||||
<a href="/oracle" data-nav="oracle"><b>State oracle on Sepolia</b><span>Devnet 3 balances read from another chain.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-panel" id="nav-panel-learn" data-group="learn" role="region" aria-labelledby="nav-btn-learn" hidden>
|
||||
|
|
@ -148,6 +157,14 @@ main{padding-bottom:100px}.card{background:var(--row);border:1px solid var(--lin
|
|||
<a href="/provenance" data-nav="provenance"><b>Built on the shoulders</b><span>Every borrowed part, credited.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-panel" id="nav-panel-build" data-group="build" role="region" aria-labelledby="nav-btn-build" hidden>
|
||||
<div class="panel-list">
|
||||
<a href="/build" data-nav="build"><b>Build on Igneum</b><span>Chain ids, RPC, a contract in five minutes.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Devnet faucet</b><span>10 IGN of devnet coin, once a day.</span></a>
|
||||
<a href="/swap" data-nav="swap"><b>Swap</b><span>Test tokens on Devnet 3; every swap is a proven block.</span></a>
|
||||
<a href="/grants" data-nav="grants"><b>Grants</b><span>Tooling, apps, infrastructure, research.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-sheet" id="nav-sheet" role="dialog" aria-modal="true" aria-label="Menu" hidden>
|
||||
|
|
@ -159,15 +176,17 @@ main{padding-bottom:100px}.card{background:var(--row);border:1px solid var(--lin
|
|||
<a href="/wallet" data-nav="wallet"><b>The wallet</b><span>Your coins. Final means final.</span></a>
|
||||
<a href="/miners" data-nav="miners"><b>GPU bench table</b><span>Measured rates, card by card.</span></a>
|
||||
<a href="/dev-fee" data-nav="dev-fee"><b>The dev fee</b><span>The optional one, in full view, off with one flag.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Testnet faucet</b><span>Test coin for an address, once a day.</span></a>
|
||||
<a href="/metamask" data-nav="metamask"><b>Add to MetaMask</b><span>Igneum as a network in your wallet.</span></a>
|
||||
</div>
|
||||
<div class="sheet-group"><div class="sheet-head">Network</div>
|
||||
<a href="/live" data-nav="live" aria-current="page"><b>Live devnet</b><span>The chain as it grows, one lane per miner.</span></a>
|
||||
<a href="/explorer" data-nav="explorer"><b>Explorer</b><span>Look a block or an address up.</span></a>
|
||||
<a href="/live" data-nav="live"><b>Live devnet</b><span>The chain as it grows, one lane per miner.</span></a>
|
||||
<a href="/explorer" data-nav="explorer" aria-current="page"><b>Explorer</b><span>Look a block or an address up.</span></a>
|
||||
<a href="/journey" data-nav="journey"><b>The journey</b><span>Six phases, four gates, the log behind them.</span></a>
|
||||
<a href="/bench" data-nav="bench"><b>Engineering log</b><span>Every measurement, with the commands that made it.</span></a>
|
||||
<a href="/evidence" data-nav="evidence"><b>Evidence</b><span>Every claim and how far it is tested.</span></a>
|
||||
<a href="/light" data-nav="light"><b>Light wallet</b><span>A balance your browser proves, trusting no node.</span></a>
|
||||
<a href="/receipt" data-nav="receipt"><b>Payment receipt</b><span>A receipt any third party re-verifies offline.</span></a>
|
||||
<a href="/oracle" data-nav="oracle"><b>State oracle on Sepolia</b><span>Devnet 3 balances read from another chain.</span></a>
|
||||
</div>
|
||||
<div class="sheet-group"><div class="sheet-head">Learn</div>
|
||||
<a href="/litepaper" data-nav="litepaper"><b>Litepaper</b><span>The design, as published.</span></a>
|
||||
|
|
@ -177,6 +196,12 @@ main{padding-bottom:100px}.card{background:var(--row);border:1px solid var(--lin
|
|||
<a href="/randomx" data-nav="randomx"><b>Igneum vs RandomX</b><span>What was kept and what was rebuilt for GPUs.</span></a>
|
||||
<a href="/provenance" data-nav="provenance"><b>Built on the shoulders</b><span>Every borrowed part, credited.</span></a>
|
||||
</div>
|
||||
<div class="sheet-group"><div class="sheet-head">Build</div>
|
||||
<a href="/build" data-nav="build"><b>Build on Igneum</b><span>Chain ids, RPC, a contract in five minutes.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Devnet faucet</b><span>10 IGN of devnet coin, once a day.</span></a>
|
||||
<a href="/swap" data-nav="swap"><b>Swap</b><span>Test tokens on Devnet 3; every swap is a proven block.</span></a>
|
||||
<a href="/grants" data-nav="grants"><b>Grants</b><span>Tooling, apps, infrastructure, research.</span></a>
|
||||
</div>
|
||||
<div class="sheet-foot">
|
||||
<a href="/download" class="btn primary big" data-nav="download">Download</a>
|
||||
<div class="sheet-social"><a href="https://discord.gg/igneum" target="_blank" rel="noopener">Discord</a><a href="https://git.igneum.network/igneum-network/spec" target="_blank" rel="noopener">Source</a><a href="https://www.reddit.com/user/Igneum_network/" target="_blank" rel="noopener">Reddit</a></div>
|
||||
|
|
@ -233,7 +258,7 @@ main{padding-bottom:100px}.card{background:var(--row);border:1px solid var(--lin
|
|||
<main id="main" class="wrap">
|
||||
<div class="head">
|
||||
<div class="breadcrumb"><a href="/">Igneum</a><span>/</span><a href="/explorer">Explorer</a><span>/</span><span>Address</span></div>
|
||||
<div class="eyebrow"><a href="/explorer">Explorer</a> · address</div>
|
||||
<div class="eyebrow"><a href="/explorer">Devnet 3 explorer</a> · address</div>
|
||||
<h1 class="hash" id="title">Address</h1>
|
||||
<div id="chips"></div>
|
||||
<div class="msg" id="msg" aria-live="polite"></div>
|
||||
|
|
@ -241,11 +266,19 @@ main{padding-bottom:100px}.card{background:var(--row);border:1px solid var(--lin
|
|||
<div id="body" hidden>
|
||||
<div class="strip">
|
||||
<div class="cell"><div class="k">Balance</div><div class="v" id="a-balance">n/a</div><div class="s" id="a-balance-s">eth_getBalance</div></div>
|
||||
<div class="cell"><div class="k">Nonce</div><div class="v" id="a-nonce">n/a</div><div class="s" id="a-nonce-s">transactions sent from this account</div></div>
|
||||
<div class="cell"><div class="k">Transactions, 7 d</div><div class="v" id="a-txs">0</div><div class="s" id="a-txs-s">sent and received, as indexed</div></div>
|
||||
<div class="cell"><div class="k">Code</div><div class="v" id="a-code">n/a</div><div class="s" id="a-code-s">eth_getCode</div></div>
|
||||
<div class="cell"><div class="k">Blocks, 24 h</div><div class="v" id="a-blocks">0</div><div class="s" id="a-blocks-s"></div></div>
|
||||
<div class="cell"><div class="k">Earned, 24 h</div><div class="v" id="a-earned">0<small>IGN</small></div><div class="s">80% of each blue block's subsidy</div></div>
|
||||
<div class="cell"><div class="k">Last block</div><div class="v" id="a-last">n/a</div><div class="s" id="a-first"></div></div>
|
||||
<div class="cell"><div class="k">Network</div><div class="v">Devnet 3</div><div class="s">chain id 4463, coins have no value</div></div>
|
||||
</div>
|
||||
<div class="card"><div class="viz-head"><h2>Identity</h2></div><dl id="ident"></dl><p class="note">A miner names its EVM payout address in every coinbase (the IGNA tag) beside the coinbase script's own address, so the two forms name the same miner. The vote keys are the finality identities that signed these blocks; a card runs several.</p></div>
|
||||
<div class="card"><div class="viz-head"><h2>Transactions</h2><div class="eyebrow" id="tx-eyebrow">newest 50 of the last 7 days</div></div>
|
||||
<div class="tbl"><table><thead><tr><th>Transaction</th><th class="n">Block</th><th>Direction</th><th>Counterparty</th><th class="n">Value</th><th>Status</th><th>Time</th></tr></thead><tbody id="txs"></tbody></table></div>
|
||||
<button class="btn" id="more-tx" type="button" style="margin-top:14px">Older transactions</button>
|
||||
</div>
|
||||
<div class="card"><div class="viz-head"><h2>Blocks mined</h2><div class="eyebrow">newest 50 of the last 24 hours</div></div>
|
||||
<div class="tbl"><table><thead><tr><th>Block</th><th class="n">Number</th><th class="n">DAA</th><th class="n">Blue score</th><th>Colour</th><th class="n">Subsidy</th><th class="n">Txs</th><th>Time</th></tr></thead><tbody id="blocks"></tbody></table></div>
|
||||
</div>
|
||||
|
|
@ -273,7 +306,7 @@ main{padding-bottom:100px}.card{background:var(--row);border:1px solid var(--lin
|
|||
<a href="/wallet">The wallet</a>
|
||||
<a href="/miners">GPU bench table</a>
|
||||
<a href="/dev-fee">The dev fee</a>
|
||||
<a href="/faucet">Testnet faucet</a>
|
||||
<a href="/faucet">Devnet faucet</a>
|
||||
<a href="/metamask">Add Igneum to MetaMask</a>
|
||||
</div></div>
|
||||
<div class="footer-column"><h4>Read</h4><div>
|
||||
|
|
@ -288,6 +321,9 @@ main{padding-bottom:100px}.card{background:var(--row);border:1px solid var(--lin
|
|||
<div class="footer-column"><h4>Explore</h4><div>
|
||||
<a href="/live">Live devnet</a>
|
||||
<a href="/explorer">Explorer</a>
|
||||
<a href="/build">Build on Igneum</a>
|
||||
<a href="/swap">Swap</a>
|
||||
<a href="/grants">Grants</a>
|
||||
<a href="/journey">Journey</a>
|
||||
<a href="/download">Downloads: devnet build</a>
|
||||
<a href="https://discord.gg/igneum" target="_blank" rel="noopener">Community Discord</a>
|
||||
|
|
@ -325,26 +361,43 @@ const esc = s => String(s ?? '').replace(/&/g, '&').replace(/</g, '<').re
|
|||
const link = h => `<a class="hash" href="/block/${esc(h)}" title="${esc(h)}">${esc(shortHash(h, 10, 6))}</a>`;
|
||||
const dl = pairs => pairs.filter(p => p).map(([k, v]) => `<dt>${esc(k)}</dt><dd>${v}</dd>`).join('');
|
||||
const a = decodeURIComponent(location.pathname.split('/').pop() || '');
|
||||
let now = 0, oldestTx = 0, me = null;
|
||||
function txRow(t) {
|
||||
const out = me && t.from === me; const cp = out ? t.to : t.from;
|
||||
return `<tr><td><a class="hash" href="/tx/${esc(t.hash)}">${esc(shortHash(t.hash, 10, 6))}</a></td><td class="n"><a href="/block/${esc(t.block_hash)}">${int(t.number)}</a></td><td>${out ? '<span class="chip">out</span>' : '<span class="chip ok">in</span>'}</td><td>${cp ? `<a class="hash" href="/address/${esc(cp)}" title="${esc(cp)}">${esc(shortHash(cp, 8, 6))}</a>` : (t.contract_address ? `<span class="kv">created</span> <a class="hash" href="/address/${esc(t.contract_address)}">${esc(shortHash(t.contract_address, 8, 6))}</a>` : '<span class="kv">none</span>')}</td><td class="n">${ignFromWei(t.value_wei, 4)} IGN</td><td>${t.status === 'success' ? '<span class="chip ok">ok</span>' : t.status === 'failed' ? '<span class="chip" style="border-color:var(--excluded);color:var(--excluded)">failed</span>' : '<span class="kv">no receipt</span>'}</td><td title="${t.ts ? new Date(t.ts).toISOString() : ''}">${t.ts ? rel(now - t.ts) : 'n/a'}</td></tr>`;
|
||||
}
|
||||
async function loadMore() {
|
||||
if (!oldestTx) return;
|
||||
const j = await fetch('/api/explorer?address=' + encodeURIComponent(a) + '&before=' + oldestTx).then(r => r.json());
|
||||
if (!j.ok) return; $('txs').insertAdjacentHTML('beforeend', j.txs.map(txRow).join('')); if (j.txs.length) oldestTx = j.txs[j.txs.length - 1].number; else $('more-tx').disabled = true;
|
||||
}
|
||||
$('more-tx').addEventListener('click', () => { loadMore().catch(() => {}); });
|
||||
async function load() {
|
||||
const r = await fetch('/api/explorer?address=' + encodeURIComponent(a)); const j = await r.json();
|
||||
$('title').textContent = a;
|
||||
if (!j.ok) { $('msg').textContent = j.error || 'Not found.'; return; }
|
||||
document.title = `Igneum address ${shortHash(a, 8, 6)}`;
|
||||
const now = new Date(j.now).getTime();
|
||||
$('chips').innerHTML = `<span class="chip">${j.kind === 'evm' ? 'EVM payout address' : 'coinbase address'}</span>` + (j.blocks_10m ? '<span class="chip hot">mining now</span>' : '');
|
||||
if (j.balance.available) { $('a-balance').innerHTML = esc(ignFromWei(j.balance.wei, 4)) + '<small>IGN</small>'; $('a-balance-s').textContent = `${j.balance.source}, ${j.network || ''}`; }
|
||||
document.title = `Devnet 3 address ${shortHash(a, 8, 6)}`;
|
||||
now = new Date(j.now).getTime(); me = j.evm_address; const ac = j.account;
|
||||
$('chips').innerHTML = `<span class="chip">${j.kind === 'evm' ? (ac && ac.is_contract ? 'contract' : 'EVM account') : 'coinbase address'}</span>` + (j.blocks_10m ? '<span class="chip hot">mining now</span>' : '') + (ac && ac.miner ? '<span class="chip">miner payout address</span>' : '');
|
||||
if (j.balance.available) { $('a-balance').innerHTML = esc(ignFromWei(j.balance.wei, 4)) + '<small>IGN</small>'; $('a-balance-s').textContent = j.balance.source === 'indexer' ? `read by the indexer ${j.balance.refreshed_at ? rel(now - new Date(j.balance.refreshed_at).getTime()) : ''}` : `${j.balance.source}, live`; }
|
||||
else { $('a-balance').textContent = 'n/a'; $('a-balance-s').textContent = j.balance.reason; }
|
||||
$('a-nonce').textContent = ac && ac.nonce !== null ? int(ac.nonce) : 'n/a';
|
||||
$('a-txs').textContent = ac ? int((ac.sent || 0) + (ac.received || 0)) : '0'; $('a-txs-s').textContent = ac ? `${int(ac.sent)} sent, ${int(ac.received)} received, as indexed` : 'none indexed';
|
||||
$('a-code').textContent = ac && ac.code_bytes !== null ? (ac.is_contract ? int(ac.code_bytes) + ' B' : 'none') : 'n/a'; $('a-code-s').textContent = ac && ac.is_contract ? 'a contract: bytes of code at this address' : 'an externally owned account';
|
||||
$('a-blocks').textContent = int(j.blocks_24h); $('a-blocks-s').textContent = `${j.blocks_10m} in 10 min, ${j.blue_24h} blue, ${j.red_24h} red, ${j.chain_24h} on the chain`;
|
||||
$('a-earned').innerHTML = esc(ign(j.earned_24h_sompi, 2)) + '<small>IGN</small>';
|
||||
$('a-last').textContent = j.last_seen ? rel(now - new Date(j.last_seen).getTime()) : 'none in 24 h';
|
||||
$('a-first').textContent = j.first_seen ? 'first in the window ' + rel(now - new Date(j.first_seen).getTime()) : '';
|
||||
$('ident').innerHTML = dl([
|
||||
['EVM address', j.evm_address ? `<a class="hash" href="/address/${esc(j.evm_address)}">${esc(j.evm_address)}</a>` : '<span style="color:var(--ash)">none seen</span>'],
|
||||
['Coinbase address', j.utxo_address ? `<a class="hash" href="/address/${esc(j.utxo_address)}">${esc(j.utxo_address)}</a>` : '<span style="color:var(--ash)">none seen</span>'],
|
||||
['Vote keys', j.miner_ids.length ? j.miner_ids.map(m => `<span class="id">${esc(m.id)}</span> <span style="color:var(--ash)">${m.blocks}</span>`).join(' ') : 'none'],
|
||||
['Earned, 24 h', `${ign(j.earned_24h_sompi, 8)} IGN <span style="color:var(--ash)">${esc(j.earned_note)}</span>`],
|
||||
['EVM address', j.evm_address ? `<a class="hash" href="/address/${esc(j.evm_address)}">${esc(j.evm_address)}</a>` : '<span class="kv">none seen</span>'],
|
||||
['Coinbase address', j.utxo_address ? `<a class="hash" href="/address/${esc(j.utxo_address)}">${esc(j.utxo_address)}</a>` : '<span class="kv">none seen</span>'],
|
||||
ac ? ['First and last seen', `${ac.first_seen_number === null ? 'no transaction indexed' : `chain block ${int(ac.first_seen_number)} to ${int(ac.last_seen_number)}`}`] : null,
|
||||
['Vote keys', j.miner_ids.length ? j.miner_ids.map(m => `<span class="id">${esc(m.id)}</span> <span class="kv">${m.blocks}</span>`).join(' ') : 'none'],
|
||||
['Earned, 24 h', `${ign(j.earned_24h_sompi, 8)} IGN <span class="kv">${esc(j.earned_note)}</span>`],
|
||||
]);
|
||||
$('blocks').innerHTML = j.recent.length ? j.recent.map(b => `<tr><td><i class="sw ${b.chain ? 'chain' : b.color}"></i>${link(b.hash)}</td><td class="n">${b.number === null ? '<span style="color:var(--ash)">off chain</span>' : int(b.number)}</td><td class="n">${int(b.daa)}</td><td class="n">${int(b.blue_score)}</td><td>${b.chain ? 'chain' : esc(b.color)}</td><td class="n">${b.subsidy_sompi ? ign(b.subsidy_sompi, 4) : 'n/a'}</td><td class="n">${b.tx_count ?? 'n/a'}</td><td title="${new Date(b.ts).toISOString()}">${rel(now - b.ts)}</td></tr>`).join('') : '<tr><td colspan="8" class="empty">No blocks from this address in the last 24 hours.</td></tr>';
|
||||
$('txs').innerHTML = j.txs.length ? j.txs.map(txRow).join('') : `<tr><td colspan="7" class="empty">${j.evm_address ? 'No transaction indexed for this address in the last 7 days.' : 'A coinbase address has no EVM transactions; its EVM payout address does.'}</td></tr>`;
|
||||
if (j.txs.length) oldestTx = j.txs[j.txs.length - 1].number; else $('more-tx').hidden = true;
|
||||
$('blocks').innerHTML = j.recent.length ? j.recent.map(b => `<tr><td><i class="sw ${b.chain ? 'chain' : b.color}"></i>${link(b.hash)}</td><td class="n">${b.number === null ? '<span class="kv">off chain</span>' : int(b.number)}</td><td class="n">${int(b.daa)}</td><td class="n">${int(b.blue_score)}</td><td>${b.chain ? 'chain' : esc(b.color)}</td><td class="n">${b.subsidy_sompi ? ign(b.subsidy_sompi, 4) + ' IGN' : 'n/a'}</td><td class="n">${b.tx_count ?? 'n/a'}</td><td title="${new Date(b.ts).toISOString()}">${rel(now - b.ts)}</td></tr>`).join('') : '<tr><td colspan="8" class="empty">No block mined by this address in the last 24 hours.</td></tr>';
|
||||
$('body').hidden = false;
|
||||
}
|
||||
load().catch(e => { $('msg').textContent = 'The API did not answer: ' + e.message; });
|
||||
|
|
|
|||
|
|
@ -15,7 +15,10 @@ export function neon(url = process.env.DATABASE_URL) {
|
|||
};
|
||||
}
|
||||
export const num = v => (v === null || v === undefined ? null : Number(v));
|
||||
export const tablePrefix = () => (process.env.LIVE_TABLE_PREFIX || '').replace(/[^a-z0-9_]/gi, '');
|
||||
// LIVE_TABLE_PREFIX names the observer whose tables are read; unset means dn3_ (Devnet 3, the igneum-observer-dn3 unit on the build
|
||||
// box, the same default as live.mjs since 8 October 2026: before that the explorer, stats and supply read the first devnet's tables
|
||||
// while /api/live read Devnet 3). An empty string reads the unprefixed tables.
|
||||
export const tablePrefix = () => (process.env.LIVE_TABLE_PREFIX === undefined ? 'dn3_' : process.env.LIVE_TABLE_PREFIX).replace(/[^a-z0-9_]/gi, '');
|
||||
/** EVM chain id from the network name (docs/design/execution-layer.md 8.1: 4461 mainnet, 4462 testnet, 4463 devnet). */
|
||||
export function chainIdOf(network) {
|
||||
const n = String(network || '');
|
||||
|
|
|
|||
|
|
@ -4,8 +4,10 @@
|
|||
// selected-chain headers from the previous locked checkpoint to this one. Read from what tools/observer wrote to
|
||||
// Neon (table live_certificates, or fintest_live_certificates for the test network).
|
||||
//
|
||||
// ?source=live the live devnet (default; falls back to the test network while the live chain has no lock yet)
|
||||
// ?source=test tonight's finality test network (igneum-devnet-7)
|
||||
// ?source=live Devnet 3 (default: the dn3_ tables, or LIVE_TABLE_PREFIX; falls back to the test network while the chain has no lock yet)
|
||||
// ?source=dn3 the same as live (the Devnet 3 name, for callers that want to say so)
|
||||
// ?source=test the finality test network's tables (fintest_live_certificates)
|
||||
// ?index=N one certified checkpoint by index instead of the newest (the explorer's per-block re-check, 8 October 2026)
|
||||
//
|
||||
// Zero dependencies: Neon's HTTP SQL endpoint over Node's built-in fetch, like live.mjs.
|
||||
|
||||
|
|
@ -29,9 +31,10 @@ function neon() {
|
|||
|
||||
const num = v => (v === null || v === undefined ? null : Number(v));
|
||||
|
||||
async function latest(sql, table) {
|
||||
const tablePrefix = () => (process.env.LIVE_TABLE_PREFIX === undefined ? 'dn3_' : process.env.LIVE_TABLE_PREFIX).replace(/[^a-z0-9_]/gi, '');
|
||||
async function latest(sql, table, index = null) {
|
||||
// A table the observer has not created yet (the live chain before the cut-over) reads as "no certificate"
|
||||
const rows = await sql(`SELECT * FROM ${table} ORDER BY index DESC LIMIT 1`).catch(() => []);
|
||||
const rows = await (index === null ? sql(`SELECT * FROM ${table} ORDER BY index DESC LIMIT 1`) : sql(`SELECT * FROM ${table} WHERE index = $1 LIMIT 1`, [index])).catch(() => []);
|
||||
return rows[0] || null;
|
||||
}
|
||||
|
||||
|
|
@ -72,6 +75,34 @@ function shape(row, source) {
|
|||
};
|
||||
}
|
||||
|
||||
/** The earliest certified Devnet 3 checkpoint whose chain block number is at least `number` (the reference apps' receipt:
|
||||
* the smallest proof that a block is final), from the dn3_ rows; null when no certificate reaches that block yet.
|
||||
* `chainNumberOf(hash)` resolves a checkpoint hash to its chain block number (the exec RPC); rows are tried newest first
|
||||
* until one falls below `number`, so the cost is a few lookups. */
|
||||
export async function earliestCheckpointAbove(sql, number, chainNumberOf, table = 'dn3_live_certificates') {
|
||||
const rows = await sql(`SELECT index, hash FROM ${table} ORDER BY index DESC LIMIT 400`).catch(() => []);
|
||||
let pick = null;
|
||||
for (const r of rows) {
|
||||
const n = await chainNumberOf(r.hash).catch(() => null);
|
||||
if (n === null) continue;
|
||||
if (n >= number) pick = r; else break;
|
||||
}
|
||||
if (!pick) return null;
|
||||
const full = await sql(`SELECT * FROM ${table} WHERE index = $1 LIMIT 1`, [Number(pick.index)]);
|
||||
return full[0] ? shape(full[0], 'dn3') : null;
|
||||
}
|
||||
|
||||
/** The latest certified checkpoint of `want` ('live', 'test' or 'dn3') through `sql`, shaped for the verifier, or null
|
||||
* (the reference apps' read service calls this off Vercel: 'dn3' names the dn3_ tables whatever LIVE_TABLE_PREFIX says). */
|
||||
export async function readCheckpoint(sql, want = 'live') {
|
||||
let row = null, source = null;
|
||||
if (want === 'dn3') { row = await latest(sql, 'dn3_live_certificates'); if (row) source = 'dn3'; }
|
||||
if (!row && want !== 'test' && want !== 'dn3') { row = await latest(sql, `${tablePrefix()}live_certificates`); if (row) source = 'live'; }
|
||||
if (!row && want !== 'dn3') { row = await latest(sql, 'fintest_live_certificates'); if (row) source = 'test'; }
|
||||
return row ? shape(row, source) : null;
|
||||
}
|
||||
export { neon };
|
||||
|
||||
export default async function handler(req, res) {
|
||||
res.setHeader('Cache-Control', 'public, max-age=5');
|
||||
res.setHeader('Access-Control-Allow-Origin', '*');
|
||||
|
|
@ -82,13 +113,15 @@ export default async function handler(req, res) {
|
|||
try {
|
||||
const sql = neon();
|
||||
const want = String((req.query && req.query.source) || 'live');
|
||||
const idx = req.query && req.query.index !== undefined && /^\d{1,12}$/.test(String(req.query.index)) ? Number(req.query.index) : null;
|
||||
let row = null, source = null;
|
||||
if (want !== 'test') { row = await latest(sql, 'live_certificates'); if (row) source = 'live'; }
|
||||
if (!row) { row = await latest(sql, 'fintest_live_certificates'); if (row) source = 'test'; }
|
||||
if (want !== 'test') { row = await latest(sql, `${tablePrefix()}live_certificates`, idx); if (row) source = 'live'; }
|
||||
if (!row && idx === null) { row = await latest(sql, 'fintest_live_certificates'); if (row) source = 'test'; }
|
||||
if (!row) {
|
||||
res.setHeader('Cache-Control', 'no-store');
|
||||
return res.status(404).json({ ok: false, error: 'no certified checkpoint stored yet' });
|
||||
}
|
||||
// the hand merge of 12:22 BST (a0b62cf7) returned `...cp` with no cp bound: every caller read "cp is not defined" (8 Oct 2026, build-server lane)
|
||||
return res.status(200).json({ ok: true, now: new Date().toISOString(), ...shape(row, source) });
|
||||
} catch (e) {
|
||||
res.setHeader('Cache-Control', 'no-store');
|
||||
|
|
|
|||
|
|
@ -1,19 +1,47 @@
|
|||
// Igneum DAG explorer, server half. GET /api/explorer with one of:
|
||||
// ?blocks=N[&before=<ms>] the latest N blocks (10 to 200, default 50), older than `before` when given
|
||||
// ?block=<hash> one block: row, header detail, parents, mergeset, transactions, proof records, shards,
|
||||
// checkpoint and certificate when it is one, children, the chain block that merged it
|
||||
// Igneum Devnet 3 explorer, server half. GET /api/explorer with one of:
|
||||
// ?blocks=N[&before=<ms>] the latest N blocks (10 to 200, default 50), older than `before` when given; each with its shard
|
||||
// summary (planned, paid), its lock state and its program class
|
||||
// ?block=<hash> one block: row, header detail, parents, mergeset, transactions (from the indexer), proof records,
|
||||
// shards, checkpoint and certificate when it is one, children, the chain block that merged it,
|
||||
// the lock that covers it, its class
|
||||
// ?height=N the chain block with that number (the EVM block number), same shape as ?block
|
||||
// ?address=<0x.. | igneum..:bech32> blocks mined, 24-hour and 10-minute counts, what those blocks earned, and the
|
||||
// balance through eth_getBalance when EXPLORER_EVM_RPC names a reachable EVM JSON-RPC
|
||||
// ?tx=<hash> one EVM transaction: the indexed row (receipt, logs, the igneum fee split) and its block's state
|
||||
// ?txs=N[&before=<number>] the latest N transactions (10 to 200, default 50), from chain blocks numbered below `before`
|
||||
// ?address=<0x.. | igneum..:bech32> the account (balance, nonce, code, from the indexer), its transactions, the blocks it
|
||||
// mined, 24-hour and 10-minute counts, what those blocks earned; the balance comes live through
|
||||
// eth_getBalance when EXPLORER_EVM_RPC names a reachable EVM JSON-RPC, else from the indexer's read
|
||||
// ?proving=1 the proving view: the node's proving state, the last 60 chain blocks with their shards, the
|
||||
// provers of the last 24 hours with their payouts, the block-to-paid latency
|
||||
// ?stats=1 the network: hash rate, difficulty, DAA, blue score, chain rate, voters and weight, the newest
|
||||
// lock, the class floor and every activation the node reports, the indexer's state
|
||||
// ?dag=N the last N blocks (20 to 400, default 120) with parents, colour, miner, shards and lock, for the DAG view
|
||||
// ?search=<q> routes a hash, a height or an address to its page, or says what it is not
|
||||
// Everything is read from what tools/observer wrote to Neon; the only live call is the balance. Cached 5 s.
|
||||
// Everything is read from what tools/observer and tools/observer/explorer-indexer wrote to Neon (table prefix dn3_ by default,
|
||||
// LIVE_TABLE_PREFIX otherwise); the only live call is the balance. Cached 5 s. Every answer names the network: Devnet 3.
|
||||
import { neon, num, tablePrefix, chainIdOf } from './_neon.mjs';
|
||||
import { classify } from '../lib/explorer.mjs';
|
||||
|
||||
const STALE_AFTER_S = 30;
|
||||
export const NETWORK_LABEL = 'Devnet 3';
|
||||
const ROW = `hash, number, blue_score, daa_score, timestamp_ms, parents, parent_hashes, is_chain_block, vote_key_hash, miner_address, evm_miner, engine,
|
||||
tx_count, proof_records, subsidy_sompi, paid_sompi, selected_parent, color, received_at`;
|
||||
// the EVM's own hash for the block's number (the indexer's explorer_blocks): a block the observer called a chain block that a tip
|
||||
// reorg later replaced keeps its number in live_blocks, so the page reads it against this and says "replaced" (Devnet 3 reorgs at the
|
||||
// tip run to depth 18, igneum_getBudgets.deepestReorg read 8 October 2026 10:0x UTC)
|
||||
const evmHash = T => `(SELECT e.hash FROM ${T}explorer_blocks e WHERE e.number = b.number LIMIT 1) AS evm_hash`;
|
||||
const TXROW = `hash, block_hash, block_number, tx_index, from_addr, to_addr, value_wei, nonce, gas, gas_price, gas_used, effective_gas_price, status,
|
||||
contract_address, input_bytes, selector, logs_count, tx_type, ts_ms`;
|
||||
|
||||
/** The program class a block of this DAA score was mined under, from the node's parameters (program_class_v5_activation_daa). */
|
||||
export function classAt(daa, params) {
|
||||
const p = params || {};
|
||||
const floors = Object.entries(p).filter(([k]) => /^program_class_v(\d+)_activation_daa$/.test(k)).map(([k, v]) => ({ v: Number(k.match(/v(\d+)/)[1]), daa: Number(v) })).filter(x => Number.isFinite(x.daa)).sort((a, b) => a.v - b.v);
|
||||
let cls = 4; // class v4 is the floor of Devnet 3 (every activation at 0 in its network object)
|
||||
for (const f of floors) if (daa !== null && daa !== undefined && daa >= f.daa && f.v > cls) cls = f.v;
|
||||
return { class: `v${cls}`, floors: floors.map(f => ({ class: `v${f.v}`, daa: f.daa })) };
|
||||
}
|
||||
|
||||
let settledBelow = -1; // numbers above this are still moving at the tip; chain_now is left null for them (set per request from the indexer's number)
|
||||
function row(b) {
|
||||
return {
|
||||
hash: b.hash, number: num(b.number), blue_score: num(b.blue_score), daa: num(b.daa_score), ts: num(b.timestamp_ms), rx: new Date(b.received_at).getTime(),
|
||||
|
|
@ -21,8 +49,28 @@ function row(b) {
|
|||
miner_id: b.vote_key_hash ? String(b.vote_key_hash).slice(0, 8) : null, vote_key_hash: b.vote_key_hash || null, miner: b.miner_address || null, evm_miner: b.evm_miner || null, engine: b.engine || null,
|
||||
tx_count: num(b.tx_count), proof_records: num(b.proof_records), subsidy_sompi: b.subsidy_sompi === null || b.subsidy_sompi === undefined ? null : String(b.subsidy_sompi),
|
||||
paid_sompi: b.paid_sompi === null || b.paid_sompi === undefined ? null : String(b.paid_sompi), selected_parent: b.selected_parent || null,
|
||||
// chain_now: still the chain block of its number by the EVM's reading (null when the indexer has not reached the number)
|
||||
chain_now: b.is_chain_block ? (b.evm_hash === undefined || b.evm_hash === null || num(b.number) > settledBelow ? null : b.evm_hash === b.hash) : false,
|
||||
};
|
||||
}
|
||||
function txrow(t) {
|
||||
return {
|
||||
hash: t.hash, block_hash: t.block_hash, number: num(t.block_number), index: num(t.tx_index), from: t.from_addr, to: t.to_addr, value_wei: t.value_wei === null || t.value_wei === undefined ? '0' : String(t.value_wei),
|
||||
nonce: num(t.nonce), gas: num(t.gas), gas_price: t.gas_price === null || t.gas_price === undefined ? null : String(t.gas_price), gas_used: num(t.gas_used),
|
||||
effective_gas_price: t.effective_gas_price === null || t.effective_gas_price === undefined ? null : String(t.effective_gas_price),
|
||||
status: t.status === null || t.status === undefined ? null : (Number(t.status) === 1 ? 'success' : 'failed'), contract_address: t.contract_address || null,
|
||||
input_bytes: num(t.input_bytes), selector: t.selector || null, logs_count: num(t.logs_count), type: num(t.tx_type), ts: num(t.ts_ms),
|
||||
};
|
||||
}
|
||||
const shardSummary = s => ({ planned: num(s.planned) || 0, proving: num(s.proving) || 0, verified: num(s.verified) || 0, paid: num(s.paid) || 0, total: num(s.total) || 0, median_lag: s.median_lag === null || s.median_lag === undefined ? null : Number(s.median_lag) });
|
||||
|
||||
/** Lock state of a block against the newest lock: a chain block at or under the lock's blue score is final; a merged block is final with its merger. */
|
||||
function lockState(b, lock, mergerBlue) {
|
||||
if (!lock) return { final: false, reason: 'no lock yet' };
|
||||
if (b.chain) return b.blue_score <= lock.blue_score ? { final: true, index: lock.index, reason: `chain block under lock ${lock.index}` } : { final: false, index: lock.index, reason: `above lock ${lock.index} (blue score ${lock.blue_score})` };
|
||||
if (mergerBlue !== null && mergerBlue !== undefined) return mergerBlue <= lock.blue_score ? { final: true, index: lock.index, reason: `merged by a chain block under lock ${lock.index}` } : { final: false, index: lock.index, reason: `merged above lock ${lock.index}` };
|
||||
return { final: false, index: lock.index, reason: 'not merged yet' };
|
||||
}
|
||||
|
||||
async function evmCall(url, method, params) {
|
||||
const r = await fetch(url, { method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify({ jsonrpc: '2.0', id: 1, method, params }), signal: AbortSignal.timeout(4000) });
|
||||
|
|
@ -41,10 +89,22 @@ export function createHandler({ env = process.env, sql, evm = evmCall } = {}) {
|
|||
const EVM = env.EXPLORER_EVM_RPC || null;
|
||||
try {
|
||||
sql = sql || neon(env.DATABASE_URL);
|
||||
const head = await sql(`SELECT now() AS now, (SELECT row_to_json(s) FROM ${T}live_state s WHERE s.id = 1) AS state`);
|
||||
const now = new Date(head[0].now).getTime(); const s = head[0].state || null;
|
||||
const head = await sql(`SELECT now() AS now, (SELECT row_to_json(s) FROM ${T}live_state s WHERE s.id = 1) AS state,
|
||||
(SELECT row_to_json(x) FROM ${T}explorer_state x WHERE x.id = 1) AS indexer, (SELECT max(number) FROM ${T}explorer_blocks) AS indexed_max`).catch(async e => {
|
||||
if (/explorer_state/.test(String(e.message))) return sql(`SELECT now() AS now, (SELECT row_to_json(s) FROM ${T}live_state s WHERE s.id = 1) AS state, NULL AS indexer`);
|
||||
throw e;
|
||||
});
|
||||
const now = new Date(head[0].now).getTime(); const s = head[0].state || null; const ix = head[0].indexer || null;
|
||||
const updated = s && s.updated_at ? new Date(s.updated_at).getTime() : null;
|
||||
const base = { ok: true, now: new Date(now).toISOString(), network: s ? s.network : null, chain_id: s ? chainIdOf(s.network) : null, stale: updated === null || (now - updated) / 1000 > STALE_AFTER_S, evm_rpc_configured: !!EVM };
|
||||
const params = ix && ix.node_info && ix.node_info.params ? ix.node_info.params : null;
|
||||
const indexer = ix ? { indexed_number: num(ix.indexed_number), tip_number: num(ix.tip_number), backlog: num(ix.backlog), txs_total: num(ix.txs_total), accounts_total: num(ix.accounts_total), blocks_per_s: num(ix.blocks_per_s), updated_at: ix.updated_at, stale: !ix.updated_at || (now - new Date(ix.updated_at).getTime()) / 1000 > STALE_AFTER_S, last_error: ix.last_error || null } : { stale: true, reason: 'the explorer indexer has not written yet' };
|
||||
// the highest number the indexer has ever read, less three: a node re-syncing from a snapshot reports a low tip for a while
|
||||
// (10:21 UTC on 8 October 2026: the observer node restarted and its tip read 1,981 against 27,145 indexed) and must not unsettle the table
|
||||
settledBelow = head[0].indexed_max === null || head[0].indexed_max === undefined ? -1 : Number(head[0].indexed_max) - 3;
|
||||
const base = { ok: true, now: new Date(now).toISOString(), network: s ? s.network : null, network_label: NETWORK_LABEL, chain_id: ix && ix.chain_id ? num(ix.chain_id) : (s ? chainIdOf(s.network) : null), stale: updated === null || (now - updated) / 1000 > STALE_AFTER_S, evm_rpc_configured: !!EVM, indexer };
|
||||
const lockRow = await sql(`SELECT index, hash, blue_score, daa_score, fraction_total, voters, locked_at FROM ${T}live_checkpoints WHERE state = 'locked' ORDER BY index DESC LIMIT 1`).catch(() => []);
|
||||
const lock = lockRow[0] ? { index: num(lockRow[0].index), hash: lockRow[0].hash, blue_score: num(lockRow[0].blue_score), daa: num(lockRow[0].daa_score), fraction_total: num(lockRow[0].fraction_total), voters: num(lockRow[0].voters), locked_at: lockRow[0].locked_at } : null;
|
||||
base.lock = lock;
|
||||
|
||||
// ---- search ----
|
||||
if (q.has('search')) {
|
||||
|
|
@ -58,20 +118,110 @@ export function createHandler({ env = process.env, sql, evm = evmCall } = {}) {
|
|||
}
|
||||
const b = await sql(`SELECT hash FROM ${T}live_blocks WHERE hash = $1`, [c.value]);
|
||||
if (b.length) return res.status(200).json({ ...base, type: 'block', href: `/block/${c.value}` });
|
||||
const t = await sql(`SELECT hash FROM ${T}live_blocks WHERE tx_count > 0 AND detail->'txs' @> $1::jsonb LIMIT 1`, [JSON.stringify([{ hash: '0x' + c.value }])]);
|
||||
if (t.length) return res.status(200).json({ ...base, type: 'tx', href: `/block/${t[0].hash}#tx-${c.value}` });
|
||||
return res.status(404).json({ ...base, ok: false, error: 'No block or transaction with that hash in the last 24 hours.' });
|
||||
const t = await sql(`SELECT hash FROM ${T}live_txs WHERE hash = $1`, ['0x' + c.value]).catch(() => []);
|
||||
if (t.length) return res.status(200).json({ ...base, type: 'tx', href: `/tx/0x${c.value}` });
|
||||
return res.status(404).json({ ...base, ok: false, error: 'No block in the last 24 hours and no transaction in the last 7 days with that hash.' });
|
||||
}
|
||||
|
||||
// ---- stats ----
|
||||
if (q.has('stats')) {
|
||||
const [chain10, fin] = await Promise.all([
|
||||
sql(`SELECT count(*)::int AS blocks_10m, count(*) FILTER (WHERE is_chain_block)::int AS chain_10m, count(DISTINCT vote_key_hash)::int AS miners_10m, max(daa_score) AS daa, max(number) AS height FROM ${T}live_blocks WHERE received_at > now() - interval '10 minutes'`),
|
||||
Promise.resolve(s && s.finality ? s.finality : null),
|
||||
]);
|
||||
const c = chain10[0] || {};
|
||||
const w = fin && fin.weights ? fin.weights : null;
|
||||
const activations = params ? Object.entries(params).filter(([k, v]) => /_activation_daa$/.test(k) && Number.isFinite(Number(v))).map(([k, v]) => ({ name: k.replace(/_activation_daa$/, ''), daa: Number(v) })) : [];
|
||||
return res.status(200).json({
|
||||
...base,
|
||||
node_version: s ? s.node_version : null, height: num(c.height), daa: num(c.daa), blue_score: s ? num(s.blue_score) : null, block_count: s ? num(s.block_count) : null,
|
||||
difficulty: s ? num(s.difficulty) : null, hashrate: s ? num(s.hashes_per_second_estimate) : null, peers: s ? num(s.peers) : null, mempool: s ? num(s.mempool) : null,
|
||||
blocks_10m: num(c.blocks_10m), chain_blocks_10m: num(c.chain_10m), blocks_per_s_10m: c.blocks_10m === null ? null : Math.round(Number(c.blocks_10m) / 600 * 100) / 100, chain_blocks_per_s_10m: c.chain_10m === null ? null : Math.round(Number(c.chain_10m) / 600 * 100) / 100,
|
||||
miners_10m: num(c.miners_10m),
|
||||
finality: fin ? { active: !!fin.finality_active, voters: w ? num(w.voters) : null, total_weight: w ? num(w.total_weight) : null, active_weight: w ? num(w.active_weight) : null, keys: w && Array.isArray(w.keys) ? w.keys.length : null, latest_locked_index: num(fin.latest_locked_index), latest_locked_blue_score: num(fin.latest_locked_blue_score), params: fin.params || null } : null,
|
||||
proving: s && s.proving ? s.proving : null,
|
||||
class: classAt(num(c.daa), params), activations, digest: ix && ix.node_info ? ix.node_info.digest : null, genesis: ix && ix.node_info ? ix.node_info.genesis : null,
|
||||
budgets: null,
|
||||
});
|
||||
}
|
||||
|
||||
// ---- proving view ----
|
||||
if (q.has('proving')) {
|
||||
const [blocks, provers24, provers1, lat, totals] = await Promise.all([
|
||||
sql(`SELECT b.hash, b.number, b.daa_score, b.blue_score, b.timestamp_ms, b.vote_key_hash, b.evm_miner, b.tx_count, b.proof_records,
|
||||
count(p.shard)::int AS total, count(*) FILTER (WHERE p.state = 'planned')::int AS planned, count(*) FILTER (WHERE p.state = 'proving')::int AS proving,
|
||||
count(*) FILTER (WHERE p.state = 'verified')::int AS verified, count(*) FILTER (WHERE p.state = 'paid')::int AS paid,
|
||||
percentile_cont(0.5) WITHIN GROUP (ORDER BY p.lag_daa) FILTER (WHERE p.state = 'paid') AS median_lag, sum(p.pgas) AS pgas
|
||||
FROM ${T}live_blocks b LEFT JOIN ${T}live_proofs p ON p.block_hash = b.hash
|
||||
WHERE b.is_chain_block AND b.number IS NOT NULL AND b.received_at > now() - interval '24 hours'
|
||||
GROUP BY b.hash, b.number, b.daa_score, b.blue_score, b.timestamp_ms, b.vote_key_hash, b.evm_miner, b.tx_count, b.proof_records ORDER BY b.number DESC LIMIT 60`),
|
||||
sql(`SELECT prover, count(*)::int AS shards, sum(payout_wei::numeric)::text AS payout_wei, percentile_cont(0.5) WITHIN GROUP (ORDER BY lag_daa) AS median_lag, max(updated_at) AS last_paid
|
||||
FROM ${T}live_proofs WHERE state = 'paid' AND updated_at > now() - interval '24 hours' AND prover IS NOT NULL GROUP BY prover ORDER BY shards DESC LIMIT 64`),
|
||||
sql(`SELECT prover, count(*)::int AS shards, sum(payout_wei::numeric)::text AS payout_wei FROM ${T}live_proofs WHERE state = 'paid' AND updated_at > now() - interval '1 hour' AND prover IS NOT NULL GROUP BY prover`),
|
||||
sql(`SELECT count(*)::int AS paid_1h, percentile_cont(0.5) WITHIN GROUP (ORDER BY lag_daa) AS p50, percentile_cont(0.9) WITHIN GROUP (ORDER BY lag_daa) AS p90, max(lag_daa) AS max_lag, min(lag_daa) AS min_lag
|
||||
FROM ${T}live_proofs WHERE state = 'paid' AND updated_at > now() - interval '1 hour'`),
|
||||
sql(`SELECT state, count(*)::int AS n, sum(payout_wei::numeric)::text AS payout_wei FROM ${T}live_proofs WHERE received_at > now() - interval '24 hours' GROUP BY state`),
|
||||
]);
|
||||
const hour = new Map(provers1.map(p => [p.prover, p]));
|
||||
return res.status(200).json({
|
||||
...base, proving: s && s.proving ? s.proving : null,
|
||||
blocks: blocks.map(b => ({ hash: b.hash, number: num(b.number), daa: num(b.daa_score), blue_score: num(b.blue_score), ts: num(b.timestamp_ms), miner_id: b.vote_key_hash ? String(b.vote_key_hash).slice(0, 8) : null, evm_miner: b.evm_miner, tx_count: num(b.tx_count), proof_records: num(b.proof_records), pgas: num(b.pgas), shards: shardSummary(b), class: classAt(num(b.daa_score), params).class })),
|
||||
provers: provers24.map(p => ({ id: p.prover, shards_24h: num(p.shards), payout_wei_24h: p.payout_wei || '0', median_lag_24h: p.median_lag === null ? null : Number(p.median_lag), shards_1h: hour.has(p.prover) ? num(hour.get(p.prover).shards) : 0, payout_wei_1h: hour.has(p.prover) ? hour.get(p.prover).payout_wei || '0' : '0', last_paid: p.last_paid })),
|
||||
latency_1h: lat[0] ? { paid: num(lat[0].paid_1h), p50_daa: lat[0].p50 === null ? null : Number(lat[0].p50), p90_daa: lat[0].p90 === null ? null : Number(lat[0].p90), min_daa: num(lat[0].min_lag), max_daa: num(lat[0].max_lag), note: 'lag in DAA score from the proven block to the block whose coinbase paid the shard; Devnet 3 targets one DAA step per second' } : null,
|
||||
totals_24h: Object.fromEntries(totals.map(t => [t.state, { shards: num(t.n), payout_wei: t.payout_wei || '0' }])),
|
||||
});
|
||||
}
|
||||
|
||||
// ---- the DAG ----
|
||||
if (q.has('dag')) {
|
||||
const n = Math.max(20, Math.min(400, Number(q.get('dag')) || 120));
|
||||
const rows = await sql(`SELECT ${ROW}, ${evmHash(T)}, (SELECT json_build_object('total', count(*), 'paid', count(*) FILTER (WHERE state = 'paid'), 'planned', count(*) FILTER (WHERE state = 'planned'), 'proving', count(*) FILTER (WHERE state = 'proving'), 'verified', count(*) FILTER (WHERE state = 'verified')) FROM ${T}live_proofs p WHERE p.block_hash = b.hash) AS sh
|
||||
FROM ${T}live_blocks b ORDER BY received_at DESC LIMIT $1`, [n]).catch(() => sql(`SELECT ${ROW} FROM ${T}live_blocks b ORDER BY received_at DESC LIMIT $1`, [n]));
|
||||
const cps = await sql(`SELECT hash, index, state FROM ${T}live_checkpoints ORDER BY index DESC LIMIT 400`).catch(() => []);
|
||||
const cp = new Map(cps.map(c => [c.hash, { index: num(c.index), state: c.state }]));
|
||||
return res.status(200).json({ ...base, blocks: rows.map(b => { const r = row(b); return { ...r, shards: b.sh ? shardSummary(b.sh) : null, checkpoint: cp.get(b.hash) || null, final: lockState(r, lock, null).final, class: classAt(r.daa, params).class }; }).reverse() });
|
||||
}
|
||||
|
||||
// ---- latest transactions ----
|
||||
if (q.has('txs')) {
|
||||
const n = Math.max(10, Math.min(200, Number(q.get('txs')) || 50));
|
||||
const before = Number(q.get('before')) || 0;
|
||||
const rows = before
|
||||
? await sql(`SELECT ${TXROW} FROM ${T}live_txs WHERE block_number < $2 ORDER BY block_number DESC, tx_index ASC LIMIT $1`, [n, before])
|
||||
: await sql(`SELECT ${TXROW} FROM ${T}live_txs ORDER BY block_number DESC, tx_index ASC LIMIT $1`, [n]);
|
||||
return res.status(200).json({ ...base, txs: rows.map(txrow) });
|
||||
}
|
||||
|
||||
// ---- one transaction ----
|
||||
if (q.has('tx')) {
|
||||
const h = String(q.get('tx') || '').toLowerCase().replace(/^(0x)?/, '0x');
|
||||
if (!/^0x[0-9a-f]{64}$/.test(h)) return res.status(400).json({ ...base, ok: false, error: 'A transaction hash is 0x plus 64 hex characters.' });
|
||||
const rows = await sql(`SELECT ${TXROW}, logs, igneum FROM ${T}live_txs WHERE hash = $1`, [h]);
|
||||
if (!rows.length) return res.status(404).json({ ...base, ok: false, error: 'No transaction with that hash in the last 7 days. The explorer keeps seven days of transactions; older ones live in the node.' });
|
||||
const t = rows[0];
|
||||
const [blk, sh, acct] = await Promise.all([
|
||||
sql(`SELECT ${ROW}, ${evmHash(T)} FROM ${T}live_blocks b WHERE hash = $1`, [t.block_hash]),
|
||||
sql(`SELECT count(*)::int AS total, count(*) FILTER (WHERE state = 'planned')::int AS planned, count(*) FILTER (WHERE state = 'proving')::int AS proving, count(*) FILTER (WHERE state = 'verified')::int AS verified, count(*) FILTER (WHERE state = 'paid')::int AS paid, percentile_cont(0.5) WITHIN GROUP (ORDER BY lag_daa) FILTER (WHERE state = 'paid') AS median_lag FROM ${T}live_proofs WHERE block_hash = $1`, [t.block_hash]).catch(() => []),
|
||||
sql(`SELECT address, is_contract, code_bytes FROM ${T}live_accounts WHERE address = ANY($1::text[])`, [[t.from_addr, t.to_addr, t.contract_address].filter(Boolean)]).catch(() => []),
|
||||
]);
|
||||
const b = blk[0] ? row(blk[0]) : null;
|
||||
const contracts = Object.fromEntries(acct.filter(a => a.is_contract).map(a => [a.address, num(a.code_bytes)]));
|
||||
return res.status(200).json({
|
||||
...base, tx: { ...txrow(t), logs: t.logs || [], igneum: t.igneum || null, contracts },
|
||||
block: b ? { ...b, class: classAt(b.daa, params).class, shards: sh[0] ? shardSummary(sh[0]) : null, lock: lockState(b, lock, null), in_observer: true } : { hash: t.block_hash, number: num(t.block_number), in_observer: false, note: 'the observer keeps one day of blocks; the transaction is older or its block left the observer window' },
|
||||
});
|
||||
}
|
||||
|
||||
// ---- latest blocks ----
|
||||
if (q.has('blocks') || (!q.has('block') && !q.has('height') && !q.has('address'))) {
|
||||
const n = Math.max(10, Math.min(200, Number(q.get('blocks')) || 50));
|
||||
const before = Number(q.get('before')) || 0;
|
||||
const sel = `SELECT ${ROW}, ${evmHash(T)}, (SELECT json_build_object('total', count(*), 'paid', count(*) FILTER (WHERE state = 'paid'), 'planned', count(*) FILTER (WHERE state = 'planned'), 'proving', count(*) FILTER (WHERE state = 'proving'), 'verified', count(*) FILTER (WHERE state = 'verified')) FROM ${T}live_proofs p WHERE p.block_hash = b.hash) AS sh FROM ${T}live_blocks b`;
|
||||
const rows = before
|
||||
? await sql(`SELECT ${ROW} FROM ${T}live_blocks WHERE received_at < to_timestamp($2 / 1000.0) ORDER BY received_at DESC LIMIT $1`, [n, before])
|
||||
: await sql(`SELECT ${ROW} FROM ${T}live_blocks ORDER BY received_at DESC LIMIT $1`, [n]);
|
||||
? await sql(`${sel} WHERE received_at < to_timestamp($2 / 1000.0) ORDER BY received_at DESC LIMIT $1`, [n, before])
|
||||
: await sql(`${sel} ORDER BY received_at DESC LIMIT $1`, [n]);
|
||||
const locked = new Set((await sql(`SELECT hash FROM ${T}live_checkpoints WHERE state = 'locked' ORDER BY index DESC LIMIT 200`).catch(() => [])).map(c => c.hash));
|
||||
return res.status(200).json({ ...base, blocks: rows.map(b => ({ ...row(b), locked: locked.has(b.hash) })) });
|
||||
return res.status(200).json({ ...base, blocks: rows.map(b => { const r = row(b); return { ...r, locked: locked.has(b.hash), shards: b.sh ? shardSummary(b.sh) : null, final: lockState(r, lock, null).final, class: classAt(r.daa, params).class }; }) });
|
||||
}
|
||||
|
||||
// ---- one block ----
|
||||
|
|
@ -83,30 +233,34 @@ export function createHandler({ env = process.env, sql, evm = evmCall } = {}) {
|
|||
hash = r[0].hash;
|
||||
}
|
||||
if (!/^[0-9a-f]{64}$/.test(hash)) return res.status(400).json({ ...base, ok: false, error: 'A block hash is 64 hex characters.' });
|
||||
const rows = await sql(`SELECT ${ROW}, detail FROM ${T}live_blocks WHERE hash = $1`, [hash]);
|
||||
if (!rows.length) return res.status(404).json({ ...base, ok: false, error: 'No block with that hash in the last 24 hours. The explorer keeps one day; older blocks live in the node.' });
|
||||
const rows = await sql(`SELECT ${ROW}, ${evmHash(T)}, detail FROM ${T}live_blocks b WHERE hash = $1`, [hash]).catch(() => sql(`SELECT ${ROW}, detail FROM ${T}live_blocks WHERE hash = $1`, [hash]));
|
||||
if (!rows.length) return res.status(404).json({ ...base, ok: false, error: 'No block with that hash in the last 24 hours. The explorer keeps one day of blocks; older blocks live in the node.' });
|
||||
const b = rows[0];
|
||||
const [shards, cps, certs, children, mergedBy] = await Promise.all([
|
||||
sql(`SELECT shard, shards, state, prover, lag_daa, payout_wei, pgas, carried_by, carrier_number FROM ${T}live_proofs WHERE block_hash = $1 ORDER BY shard`, [hash]).catch(() => []),
|
||||
const [shards, cps, certs, children, mergedBy, txs] = await Promise.all([
|
||||
sql(`SELECT shard, shards, state, prover, lag_daa, payout_wei, pgas, carried_by, carrier_number, verified FROM ${T}live_proofs WHERE block_hash = $1 ORDER BY shard`, [hash]).catch(() => []),
|
||||
sql(`SELECT index, state, signed_weight, active_weight, total_weight, fraction_active, fraction_total, votes_seen, voters, locked_at FROM ${T}live_checkpoints WHERE hash = $1`, [hash]).catch(() => []),
|
||||
sql(`SELECT index, hash, carrier, voter_count, aggregator, total_weight, active_weight, prev_index, prev_hash, headers_complete, created_at FROM ${T}live_certificates WHERE hash = $1 OR carrier = $1`, [hash]).catch(() => []),
|
||||
sql(`SELECT hash FROM ${T}live_blocks WHERE received_at >= $2::timestamptz - interval '10 seconds' AND received_at < $2::timestamptz + interval '10 minutes' AND $1 = ANY(parent_hashes) ORDER BY received_at LIMIT 20`, [hash, b.received_at]),
|
||||
b.is_chain_block ? Promise.resolve([]) : sql(`SELECT hash FROM ${T}live_blocks WHERE is_chain_block AND received_at >= $2::timestamptz - interval '10 seconds' AND received_at < $2::timestamptz + interval '10 minutes' AND (detail->'mergeset'->'blues' ? $1 OR detail->'mergeset'->'reds' ? $1) LIMIT 1`, [hash, b.received_at]),
|
||||
b.is_chain_block ? Promise.resolve([]) : sql(`SELECT hash, blue_score FROM ${T}live_blocks WHERE is_chain_block AND received_at >= $2::timestamptz - interval '10 seconds' AND received_at < $2::timestamptz + interval '10 minutes' AND (detail->'mergeset'->'blues' ? $1 OR detail->'mergeset'->'reds' ? $1) LIMIT 1`, [hash, b.received_at]),
|
||||
sql(`SELECT ${TXROW} FROM ${T}live_txs WHERE block_hash = $1 ORDER BY tx_index LIMIT 500`, [hash]).catch(() => []),
|
||||
]);
|
||||
let evmView = null; // the EVM's view of a chain block, when the deployment has an EVM RPC
|
||||
if (EVM && b.is_chain_block) {
|
||||
try {
|
||||
const e = await evm(EVM, 'eth_getBlockByHash', ['0x' + hash, true]);
|
||||
const e = await evm(EVM, 'eth_getBlockByHash', ['0x' + hash, false]);
|
||||
if (e) evmView = { number: parseInt(e.number, 16), gas_used: parseInt(e.gasUsed, 16), base_fee_per_gas: e.baseFeePerGas, state_root: e.stateRoot, miner: e.miner,
|
||||
transactions: (e.transactions || []).map(t => ({ hash: t.hash, from: t.from, to: t.to, value: t.value, nonce: parseInt(t.nonce, 16), gas: parseInt(t.gas, 16) })),
|
||||
igneum: e.igneum ? { rewards: e.igneum.rewards, proving_pool_credit: e.igneum.provingPoolCredit, pgas_used: e.igneum.pgasUsed, skipped: e.igneum.skipped } : null };
|
||||
} catch (err) { evmView = { error: String(err.message || err).slice(0, 120) }; }
|
||||
}
|
||||
const r = row(b);
|
||||
const mergerBlue = b.is_chain_block ? null : (mergedBy[0] ? num(mergedBy[0].blue_score) : null);
|
||||
const counts = { total: shards.length, planned: shards.filter(x => x.state === 'planned').length, proving: shards.filter(x => x.state === 'proving').length, verified: shards.filter(x => x.state === 'verified').length, paid: shards.filter(x => x.state === 'paid').length };
|
||||
return res.status(200).json({
|
||||
...base, block: { ...row(b), detail: b.detail || null }, shards: shards.map(x => ({ i: num(x.shard), n: num(x.shards), state: x.state, prover: x.prover, lag: num(x.lag_daa), payout_wei: x.payout_wei, pgas: num(x.pgas), carried_by: x.carried_by, carrier_number: num(x.carrier_number) })),
|
||||
...base, block: { ...r, detail: b.detail || null, class: classAt(r.daa, params), lock: lockState(r, lock, mergerBlue), shard_summary: counts },
|
||||
shards: shards.map(x => ({ i: num(x.shard), n: num(x.shards), state: x.state, prover: x.prover, lag: num(x.lag_daa), payout_wei: x.payout_wei, pgas: num(x.pgas), carried_by: x.carried_by, carrier_number: num(x.carrier_number), node_verified: x.verified === null || x.verified === undefined ? null : !!x.verified })),
|
||||
checkpoint: cps[0] ? { index: num(cps[0].index), state: cps[0].state, signed: num(cps[0].signed_weight), active: num(cps[0].active_weight), total: num(cps[0].total_weight), fraction_active: num(cps[0].fraction_active), fraction_total: num(cps[0].fraction_total), votes: num(cps[0].votes_seen), voters: num(cps[0].voters), locked_at: cps[0].locked_at } : null,
|
||||
certificates: certs.map(c => ({ index: num(c.index), checkpoint: c.hash, carrier: c.carrier, role: c.hash === hash ? 'checkpoint' : 'carrier', voter_count: num(c.voter_count), aggregator: c.aggregator, total_weight: num(c.total_weight), active_weight: num(c.active_weight), previous: c.prev_index === null ? null : { index: num(c.prev_index), hash: c.prev_hash }, headers_complete: !!c.headers_complete })),
|
||||
children: children.map(c => c.hash), merged_by: b.is_chain_block ? hash : (mergedBy[0] ? mergedBy[0].hash : null), evm: evmView,
|
||||
children: children.map(c => c.hash), merged_by: b.is_chain_block ? hash : (mergedBy[0] ? mergedBy[0].hash : null), evm: evmView, txs: txs.map(txrow),
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -122,30 +276,40 @@ export function createHandler({ env = process.env, sql, evm = evmCall } = {}) {
|
|||
coalesce(sum(subsidy_sompi) FILTER (WHERE color = 'blue'), 0)::text AS blue_subsidy_sompi,
|
||||
max(evm_miner) AS evm_miner, max(miner_address) AS miner_address
|
||||
FROM ${T}live_blocks WHERE ${col} = $1`, [c.value]),
|
||||
sql(`SELECT ${ROW} FROM ${T}live_blocks WHERE ${col} = $1 ORDER BY received_at DESC LIMIT 50`, [c.value]),
|
||||
sql(`SELECT ${ROW}, ${evmHash(T)} FROM ${T}live_blocks b WHERE ${col} = $1 ORDER BY received_at DESC LIMIT 50`, [c.value]),
|
||||
sql(`SELECT vote_key_hash, count(*)::int AS n FROM ${T}live_blocks WHERE ${col} = $1 AND vote_key_hash IS NOT NULL GROUP BY 1 ORDER BY n DESC LIMIT 32`, [c.value]),
|
||||
]);
|
||||
const t = sum[0];
|
||||
const evmAddress = c.kind === 'evm' ? c.value : (t.evm_miner || null);
|
||||
let balance = { available: false, reason: EVM ? 'no EVM address known for this coinbase address' : 'no EVM RPC configured on this deployment (EXPLORER_EVM_RPC)' };
|
||||
let account = null, txs = [];
|
||||
if (evmAddress) {
|
||||
const before = Number(q.get('before')) || 0;
|
||||
const [a, tx] = await Promise.all([
|
||||
sql(`SELECT address, balance_wei, nonce, code_bytes, is_contract, sent, received, first_seen_number, last_seen_number, miner, refreshed_at FROM ${T}live_accounts WHERE address = $1`, [evmAddress]).catch(() => []),
|
||||
sql(`SELECT ${TXROW} FROM ${T}live_txs WHERE (from_addr = $1 OR to_addr = $1) ${before ? 'AND block_number < $2' : ''} ORDER BY block_number DESC, tx_index ASC LIMIT 50`, before ? [evmAddress, before] : [evmAddress]).catch(() => []),
|
||||
]);
|
||||
if (a[0]) account = { address: a[0].address, balance_wei: a[0].balance_wei === null ? null : String(a[0].balance_wei), nonce: num(a[0].nonce), code_bytes: num(a[0].code_bytes), is_contract: !!a[0].is_contract, sent: num(a[0].sent), received: num(a[0].received), first_seen_number: num(a[0].first_seen_number), last_seen_number: num(a[0].last_seen_number), miner: !!a[0].miner, refreshed_at: a[0].refreshed_at, source: 'the explorer indexer (eth_getBalance, eth_getTransactionCount, eth_getCode on the observer node)' };
|
||||
txs = tx.map(txrow);
|
||||
}
|
||||
let balance = account && account.balance_wei !== null ? { available: true, wei: account.balance_wei, address: evmAddress, source: 'indexer', refreshed_at: account.refreshed_at } : { available: false, reason: evmAddress ? 'not read yet: the indexer reads an address after its first transaction or mined block' : 'no EVM address known for this coinbase address' };
|
||||
if (EVM && evmAddress) {
|
||||
try { const wei = await evm(EVM, 'eth_getBalance', [evmAddress, 'latest']); balance = { available: true, wei: BigInt(wei).toString(), address: evmAddress, source: 'eth_getBalance latest' }; }
|
||||
catch (err) { balance = { available: false, reason: String(err.message || err).slice(0, 120) }; }
|
||||
catch (err) { if (!balance.available) balance = { available: false, reason: String(err.message || err).slice(0, 120) }; }
|
||||
}
|
||||
// what the blocks earned: each blue block pays 80% of the subsidy its payload declares to this miner, through the coinbase of the block that merges it
|
||||
const blue = BigInt(t.blue_subsidy_sompi || 0); const earned = blue * 80n / 100n;
|
||||
return res.status(200).json({
|
||||
...base, address: c.value, kind: c.kind, evm_address: evmAddress, utxo_address: c.kind === 'utxo' ? c.value : (t.miner_address || null),
|
||||
account, txs,
|
||||
blocks_24h: t.blocks_24h, blocks_10m: t.blocks_10m, blue_24h: t.blue_24h, red_24h: t.red_24h, chain_24h: t.chain_24h,
|
||||
first_seen: t.first_ts ? new Date(num(t.first_ts)).toISOString() : null, last_seen: t.last_ts ? new Date(num(t.last_ts)).toISOString() : null,
|
||||
earned_24h_sompi: earned.toString(), earned_note: '80% of the declared subsidy of every blue block this address mined in the last 24 hours, paid by the coinbase of the block that merged each one (coinbase.rs); red blocks pay the merging miner instead',
|
||||
miner_ids: ids.map(i => ({ id: String(i.vote_key_hash).slice(0, 8), blocks: i.n })), balance, recent: recent.map(row),
|
||||
});
|
||||
}
|
||||
return res.status(400).json({ ...base, ok: false, error: 'blocks, block, height, address or search' });
|
||||
return res.status(400).json({ ...base, ok: false, error: 'blocks, block, height, tx, txs, address, proving, stats, dag or search' });
|
||||
} catch (e) {
|
||||
res.setHeader('Cache-Control', 'no-store');
|
||||
return res.status(500).json({ ok: false, error: String(e.message || e) });
|
||||
return res.status(500).json({ ok: false, network_label: NETWORK_LABEL, error: String(e.message || e) });
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,6 +6,8 @@
|
|||
// 7 October 2026 evening by the founder word) reads another observer's tables (empty = the first devnet's, fintest_live_*, provtest_live_*).
|
||||
// Zero dependencies: Neon's HTTP SQL endpoint over Node's built-in fetch.
|
||||
|
||||
import { provingHealth } from '../lib/proving-health.mjs';
|
||||
|
||||
const STALE_AFTER_S = 30;
|
||||
const T = (process.env.LIVE_TABLE_PREFIX === undefined ? 'dn3_' : process.env.LIVE_TABLE_PREFIX).replace(/[^a-z0-9_]/gi, '');
|
||||
|
||||
|
|
@ -45,11 +47,12 @@ export default async function handler(req, res) {
|
|||
// ?summary=1: the counts of the window alone (blocks, chain blocks, proven, shards by state), for a tile that reads a long
|
||||
// window every 10 s while the scene keeps its short one (7 October 2026); no block rows, no miners, no events
|
||||
const summary = q.get('summary') === '1';
|
||||
const [head, blockRows, minerRows, checkpointRows, proofRows] = await Promise.all([
|
||||
const [head, blockRows, minerRows, checkpointRows, proofRows, provingRows] = await Promise.all([
|
||||
sql(`SELECT now() AS now,
|
||||
(SELECT row_to_json(s) FROM ${T}live_state s WHERE s.id = 1) AS state,
|
||||
(SELECT json_agg(e) FROM (SELECT ts, kind, text FROM ${T}live_events ORDER BY ts DESC LIMIT 30) e) AS events,
|
||||
(SELECT max(number) FROM ${T}live_blocks WHERE number IS NOT NULL AND received_at > now() - interval '10 minutes') AS height`),
|
||||
(SELECT max(number) FROM ${T}live_blocks WHERE number IS NOT NULL AND received_at > now() - interval '10 minutes') AS height,
|
||||
(SELECT max(daa_score) FROM ${T}live_blocks WHERE received_at > now() - interval '2 minutes') AS newest_daa`),
|
||||
sql(`SELECT hash, blue_score, daa_score, timestamp_ms, parent_hashes, is_chain_block, vote_key_hash, received_at, color, number
|
||||
FROM ${T}live_blocks
|
||||
WHERE received_at > now() - ($1 || ' seconds')::interval
|
||||
|
|
@ -72,6 +75,10 @@ export default async function handler(req, res) {
|
|||
FROM ${T}live_proofs p
|
||||
WHERE p.block_hash IN (SELECT hash FROM ${T}live_blocks WHERE received_at > now() - ($1 || ' seconds')::interval ORDER BY received_at DESC LIMIT 1800)
|
||||
ORDER BY p.block_hash, p.shard`, [String(windowS)]).catch(() => []),
|
||||
// the proving feed's own health (8 October 2026, site/lib/proving-health.mjs): the records blocks carried in the last
|
||||
// 10 minutes against the last shard the observer's node credited; an older observer has no proofs table
|
||||
sql(`SELECT (SELECT coalesce(sum(proof_records), 0)::int FROM ${T}live_blocks WHERE received_at > now() - interval '10 minutes') AS records_10m,
|
||||
(SELECT max(updated_at) FROM ${T}live_proofs WHERE state IN ('verified', 'paid')) AS last_change`).catch(() => [{ records_10m: 0, last_change: null }]),
|
||||
]);
|
||||
|
||||
const now = new Date(head[0].now).getTime();
|
||||
|
|
@ -138,12 +145,17 @@ export default async function handler(req, res) {
|
|||
shardsOf.get(k).push({ i: num(r.shard), n: num(r.shards), state: r.state, prover: r.prover || null, lag: num(r.lag_daa), payout, pgas: num(r.pgas) });
|
||||
}
|
||||
const pv = (s && s.proving) || null;
|
||||
const proving = pv && pv.supported ? {
|
||||
const provingBase = pv && pv.supported ? {
|
||||
supported: true, active: !!pv.active, activation_daa: num(pv.activation_daa), tip_daa: num(pv.tip_daa), verifier: pv.verifier || null, pool: pv.pool || null,
|
||||
paid_shards_total: num(pv.paid_shards_total), shard_budget_pgas: num(pv.shard_budget_pgas),
|
||||
blocks_10m: num(pv.blocks_10m), blocks_fully_proven_10m: num(pv.blocks_fully_proven_10m), shards_proven_10m: num(pv.shards_proven_10m), shards_paid_10m: num(pv.shards_paid_10m),
|
||||
median_proof_lag_s: num(pv.median_proof_lag_s), provers_10m: num(pv.provers_10m),
|
||||
} : { supported: false, reason: pv ? (pv.reason || 'node without proving') : 'observer has not reported the proving layer' };
|
||||
// the feed's own staleness beside the counts: stale (bool) and stale_reason in words, status_age_s (the observer's last
|
||||
// status read, null on an older observer), tip_lag_daa, records_10m, last_change_at (the last shard credited)
|
||||
const ph = provingHealth({ proving: provingBase, newestDaa: num(head[0].newest_daa), records10m: provingRows[0] ? provingRows[0].records_10m : 0,
|
||||
lastChangeAt: provingRows[0] && provingRows[0].last_change ? new Date(provingRows[0].last_change).toISOString() : null, statusAt: pv && pv.status_at ? pv.status_at : null, now });
|
||||
const proving = provingBase.supported ? { ...provingBase, stale: ph.stale, stale_reason: ph.reason, status_age_s: ph.status_age_s, tip_lag_daa: ph.tip_lag_daa, records_10m: ph.records_10m, last_change_at: ph.last_change_at } : provingBase;
|
||||
|
||||
const blocks = blockRows.reverse().map(b => ({
|
||||
hash: short(b.hash),
|
||||
|
|
|
|||
|
|
@ -82,6 +82,7 @@
|
|||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-mine" data-group="mine" data-active aria-expanded="false" aria-controls="nav-panel-mine" aria-haspopup="true">Mine<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-network" data-group="network" aria-expanded="false" aria-controls="nav-panel-network" aria-haspopup="true">Network<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-learn" data-group="learn" aria-expanded="false" aria-controls="nav-panel-learn" aria-haspopup="true">Learn<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-build" data-group="build" aria-expanded="false" aria-controls="nav-panel-build" aria-haspopup="true">Build<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
</div>
|
||||
<div class="nav-controls">
|
||||
<button class="btn icon-btn" type="button" data-theme-toggle aria-label="Switch to light theme"><svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><circle cx="12" cy="12" r="4"/><path d="M12 2v2m0 16v2M2 12h2m16 0h2M5 5l1 1m12 12 1 1M5 19l1-1M18 6l1-1"/></svg></button>
|
||||
|
|
@ -99,7 +100,6 @@
|
|||
<a href="/wallet" data-nav="wallet"><b>The wallet</b><span>Your coins. Final means final.</span></a>
|
||||
<a href="/miners" data-nav="miners"><b>GPU bench table</b><span>Measured rates, card by card.</span></a>
|
||||
<a href="/dev-fee" data-nav="dev-fee"><b>The dev fee</b><span>The optional one, in full view, off with one flag.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Testnet faucet</b><span>Test coin for an address, once a day.</span></a>
|
||||
<a href="/metamask" data-nav="metamask"><b>Add to MetaMask</b><span>Igneum as a network in your wallet.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -110,6 +110,9 @@
|
|||
<a href="/journey" data-nav="journey"><b>The journey</b><span>Six phases, four gates, the log behind them.</span></a>
|
||||
<a href="/bench" data-nav="bench"><b>Engineering log</b><span>Every measurement, with the commands that made it.</span></a>
|
||||
<a href="/evidence" data-nav="evidence"><b>Evidence</b><span>Every claim and how far it is tested.</span></a>
|
||||
<a href="/light" data-nav="light"><b>Light wallet</b><span>A balance your browser proves, trusting no node.</span></a>
|
||||
<a href="/receipt" data-nav="receipt"><b>Payment receipt</b><span>A receipt any third party re-verifies offline.</span></a>
|
||||
<a href="/oracle" data-nav="oracle"><b>State oracle on Sepolia</b><span>Devnet 3 balances read from another chain.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-panel" id="nav-panel-learn" data-group="learn" role="region" aria-labelledby="nav-btn-learn" hidden>
|
||||
|
|
@ -122,6 +125,14 @@
|
|||
<a href="/provenance" data-nav="provenance"><b>Built on the shoulders</b><span>Every borrowed part, credited.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-panel" id="nav-panel-build" data-group="build" role="region" aria-labelledby="nav-btn-build" hidden>
|
||||
<div class="panel-list">
|
||||
<a href="/build" data-nav="build"><b>Build on Igneum</b><span>Chain ids, RPC, a contract in five minutes.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Devnet faucet</b><span>10 IGN of devnet coin, once a day.</span></a>
|
||||
<a href="/swap" data-nav="swap"><b>Swap</b><span>Test tokens on Devnet 3; every swap is a proven block.</span></a>
|
||||
<a href="/grants" data-nav="grants"><b>Grants</b><span>Tooling, apps, infrastructure, research.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-sheet" id="nav-sheet" role="dialog" aria-modal="true" aria-label="Menu" hidden>
|
||||
|
|
@ -133,7 +144,6 @@
|
|||
<a href="/wallet" data-nav="wallet"><b>The wallet</b><span>Your coins. Final means final.</span></a>
|
||||
<a href="/miners" data-nav="miners"><b>GPU bench table</b><span>Measured rates, card by card.</span></a>
|
||||
<a href="/dev-fee" data-nav="dev-fee"><b>The dev fee</b><span>The optional one, in full view, off with one flag.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Testnet faucet</b><span>Test coin for an address, once a day.</span></a>
|
||||
<a href="/metamask" data-nav="metamask"><b>Add to MetaMask</b><span>Igneum as a network in your wallet.</span></a>
|
||||
</div>
|
||||
<div class="sheet-group"><div class="sheet-head">Network</div>
|
||||
|
|
@ -142,6 +152,9 @@
|
|||
<a href="/journey" data-nav="journey"><b>The journey</b><span>Six phases, four gates, the log behind them.</span></a>
|
||||
<a href="/bench" data-nav="bench"><b>Engineering log</b><span>Every measurement, with the commands that made it.</span></a>
|
||||
<a href="/evidence" data-nav="evidence"><b>Evidence</b><span>Every claim and how far it is tested.</span></a>
|
||||
<a href="/light" data-nav="light"><b>Light wallet</b><span>A balance your browser proves, trusting no node.</span></a>
|
||||
<a href="/receipt" data-nav="receipt"><b>Payment receipt</b><span>A receipt any third party re-verifies offline.</span></a>
|
||||
<a href="/oracle" data-nav="oracle"><b>State oracle on Sepolia</b><span>Devnet 3 balances read from another chain.</span></a>
|
||||
</div>
|
||||
<div class="sheet-group"><div class="sheet-head">Learn</div>
|
||||
<a href="/litepaper" data-nav="litepaper"><b>Litepaper</b><span>The design, as published.</span></a>
|
||||
|
|
@ -151,6 +164,12 @@
|
|||
<a href="/randomx" data-nav="randomx"><b>Igneum vs RandomX</b><span>What was kept and what was rebuilt for GPUs.</span></a>
|
||||
<a href="/provenance" data-nav="provenance"><b>Built on the shoulders</b><span>Every borrowed part, credited.</span></a>
|
||||
</div>
|
||||
<div class="sheet-group"><div class="sheet-head">Build</div>
|
||||
<a href="/build" data-nav="build"><b>Build on Igneum</b><span>Chain ids, RPC, a contract in five minutes.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Devnet faucet</b><span>10 IGN of devnet coin, once a day.</span></a>
|
||||
<a href="/swap" data-nav="swap"><b>Swap</b><span>Test tokens on Devnet 3; every swap is a proven block.</span></a>
|
||||
<a href="/grants" data-nav="grants"><b>Grants</b><span>Tooling, apps, infrastructure, research.</span></a>
|
||||
</div>
|
||||
<div class="sheet-foot">
|
||||
<a href="/download" class="btn primary big" data-nav="download">Download</a>
|
||||
<div class="sheet-social"><a href="https://discord.gg/igneum" target="_blank" rel="noopener">Discord</a><a href="https://git.igneum.network/igneum-network/spec" target="_blank" rel="noopener">Source</a><a href="https://www.reddit.com/user/Igneum_network/" target="_blank" rel="noopener">Reddit</a></div>
|
||||
|
|
@ -470,7 +489,7 @@
|
|||
<a href="/wallet">The wallet</a>
|
||||
<a href="/miners">GPU bench table</a>
|
||||
<a href="/dev-fee">The dev fee</a>
|
||||
<a href="/faucet">Testnet faucet</a>
|
||||
<a href="/faucet">Devnet faucet</a>
|
||||
<a href="/metamask">Add Igneum to MetaMask</a>
|
||||
</div></div>
|
||||
<div class="footer-column"><h4>Read</h4><div>
|
||||
|
|
@ -485,6 +504,9 @@
|
|||
<div class="footer-column"><h4>Explore</h4><div>
|
||||
<a href="/live">Live devnet</a>
|
||||
<a href="/explorer">Explorer</a>
|
||||
<a href="/build">Build on Igneum</a>
|
||||
<a href="/swap">Swap</a>
|
||||
<a href="/grants">Grants</a>
|
||||
<a href="/journey">Journey</a>
|
||||
<a href="/download">Downloads: devnet build</a>
|
||||
<a href="https://discord.gg/igneum" target="_blank" rel="noopener">Community Discord</a>
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
111
site/block.html
111
site/block.html
|
|
@ -3,7 +3,7 @@
|
|||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
|
||||
<title>Igneum block</title>
|
||||
<title>Igneum Devnet 3 block</title>
|
||||
<meta name="description" content="One Igneum block: header, parents, mergeset, transactions, proof records and, when it is a checkpoint, its finality certificate.">
|
||||
<link rel="canonical" href="https://igneum.network/block">
|
||||
<meta name="robots" content="noindex">
|
||||
|
|
@ -92,6 +92,12 @@ dd{margin:0;overflow-wrap:anywhere;font-variant-numeric:tabular-nums}
|
|||
@media (min-width:900px){.two{grid-template-columns:1fr 1fr}.two .card{margin-top:0}}
|
||||
.two-wrap{margin-top:var(--gap)}
|
||||
main{padding-bottom:100px}.card{background:var(--row);border:1px solid var(--line);border-radius:16px;padding:25px;margin-top:24px}.card .viz-head h2{font-size:19px}.card .viz-head .eyebrow{margin:0}
|
||||
.badge{display:inline-flex;align-items:center;gap:6px;font-family:var(--f-mono);font-size:11px;letter-spacing:.06em;text-transform:uppercase;padding:4px 9px;border-radius:999px;border:1px solid var(--line-2);color:var(--ink-2);margin:0 6px 6px 0}
|
||||
.badge.ok{border-color:var(--green,#5CC48A);color:var(--green,#5CC48A)}.badge.hot{border-color:var(--molten);color:var(--molten)}.badge.bad{border-color:var(--excluded);color:var(--excluded)}.badge.wait{color:var(--ash)}
|
||||
.bar{display:inline-block;width:72px;height:7px;border-radius:4px;background:var(--line);vertical-align:middle;margin-right:7px;overflow:hidden}.bar i{display:block;height:100%;background:var(--green,#5CC48A)}.bar i.part{background:var(--molten)}
|
||||
.dagbox{position:relative;width:100%;height:320px;border:1px solid var(--line);border-radius:12px;background:var(--obsidian);overflow:hidden}.dagbox canvas{width:100%;height:100%;display:block;cursor:pointer}
|
||||
.dagtip{position:absolute;pointer-events:none;font:11px/1.5 var(--mono);color:var(--bone);background:var(--graphite);border:1px solid var(--line-2);border-radius:8px;padding:8px 10px;max-width:300px;display:none}
|
||||
.kv{color:var(--ash)}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
|
@ -108,6 +114,7 @@ main{padding-bottom:100px}.card{background:var(--row);border:1px solid var(--lin
|
|||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-mine" data-group="mine" aria-expanded="false" aria-controls="nav-panel-mine" aria-haspopup="true">Mine<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-network" data-group="network" data-active aria-expanded="false" aria-controls="nav-panel-network" aria-haspopup="true">Network<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-learn" data-group="learn" aria-expanded="false" aria-controls="nav-panel-learn" aria-haspopup="true">Learn<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-build" data-group="build" aria-expanded="false" aria-controls="nav-panel-build" aria-haspopup="true">Build<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
</div>
|
||||
<div class="nav-controls">
|
||||
<button class="btn icon-btn" type="button" data-theme-toggle aria-label="Switch to light theme"><svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><circle cx="12" cy="12" r="4"/><path d="M12 2v2m0 16v2M2 12h2m16 0h2M5 5l1 1m12 12 1 1M5 19l1-1M18 6l1-1"/></svg></button>
|
||||
|
|
@ -125,17 +132,19 @@ main{padding-bottom:100px}.card{background:var(--row);border:1px solid var(--lin
|
|||
<a href="/wallet" data-nav="wallet"><b>The wallet</b><span>Your coins. Final means final.</span></a>
|
||||
<a href="/miners" data-nav="miners"><b>GPU bench table</b><span>Measured rates, card by card.</span></a>
|
||||
<a href="/dev-fee" data-nav="dev-fee"><b>The dev fee</b><span>The optional one, in full view, off with one flag.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Testnet faucet</b><span>Test coin for an address, once a day.</span></a>
|
||||
<a href="/metamask" data-nav="metamask"><b>Add to MetaMask</b><span>Igneum as a network in your wallet.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-panel" id="nav-panel-network" data-group="network" role="region" aria-labelledby="nav-btn-network" hidden>
|
||||
<div class="panel-list">
|
||||
<a href="/live" data-nav="live" aria-current="page"><b>Live devnet</b><span>The chain as it grows, one lane per miner.</span></a>
|
||||
<a href="/explorer" data-nav="explorer"><b>Explorer</b><span>Look a block or an address up.</span></a>
|
||||
<a href="/live" data-nav="live"><b>Live devnet</b><span>The chain as it grows, one lane per miner.</span></a>
|
||||
<a href="/explorer" data-nav="explorer" aria-current="page"><b>Explorer</b><span>Look a block or an address up.</span></a>
|
||||
<a href="/journey" data-nav="journey"><b>The journey</b><span>Six phases, four gates, the log behind them.</span></a>
|
||||
<a href="/bench" data-nav="bench"><b>Engineering log</b><span>Every measurement, with the commands that made it.</span></a>
|
||||
<a href="/evidence" data-nav="evidence"><b>Evidence</b><span>Every claim and how far it is tested.</span></a>
|
||||
<a href="/light" data-nav="light"><b>Light wallet</b><span>A balance your browser proves, trusting no node.</span></a>
|
||||
<a href="/receipt" data-nav="receipt"><b>Payment receipt</b><span>A receipt any third party re-verifies offline.</span></a>
|
||||
<a href="/oracle" data-nav="oracle"><b>State oracle on Sepolia</b><span>Devnet 3 balances read from another chain.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-panel" id="nav-panel-learn" data-group="learn" role="region" aria-labelledby="nav-btn-learn" hidden>
|
||||
|
|
@ -148,6 +157,14 @@ main{padding-bottom:100px}.card{background:var(--row);border:1px solid var(--lin
|
|||
<a href="/provenance" data-nav="provenance"><b>Built on the shoulders</b><span>Every borrowed part, credited.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-panel" id="nav-panel-build" data-group="build" role="region" aria-labelledby="nav-btn-build" hidden>
|
||||
<div class="panel-list">
|
||||
<a href="/build" data-nav="build"><b>Build on Igneum</b><span>Chain ids, RPC, a contract in five minutes.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Devnet faucet</b><span>10 IGN of devnet coin, once a day.</span></a>
|
||||
<a href="/swap" data-nav="swap"><b>Swap</b><span>Test tokens on Devnet 3; every swap is a proven block.</span></a>
|
||||
<a href="/grants" data-nav="grants"><b>Grants</b><span>Tooling, apps, infrastructure, research.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-sheet" id="nav-sheet" role="dialog" aria-modal="true" aria-label="Menu" hidden>
|
||||
|
|
@ -159,15 +176,17 @@ main{padding-bottom:100px}.card{background:var(--row);border:1px solid var(--lin
|
|||
<a href="/wallet" data-nav="wallet"><b>The wallet</b><span>Your coins. Final means final.</span></a>
|
||||
<a href="/miners" data-nav="miners"><b>GPU bench table</b><span>Measured rates, card by card.</span></a>
|
||||
<a href="/dev-fee" data-nav="dev-fee"><b>The dev fee</b><span>The optional one, in full view, off with one flag.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Testnet faucet</b><span>Test coin for an address, once a day.</span></a>
|
||||
<a href="/metamask" data-nav="metamask"><b>Add to MetaMask</b><span>Igneum as a network in your wallet.</span></a>
|
||||
</div>
|
||||
<div class="sheet-group"><div class="sheet-head">Network</div>
|
||||
<a href="/live" data-nav="live" aria-current="page"><b>Live devnet</b><span>The chain as it grows, one lane per miner.</span></a>
|
||||
<a href="/explorer" data-nav="explorer"><b>Explorer</b><span>Look a block or an address up.</span></a>
|
||||
<a href="/live" data-nav="live"><b>Live devnet</b><span>The chain as it grows, one lane per miner.</span></a>
|
||||
<a href="/explorer" data-nav="explorer" aria-current="page"><b>Explorer</b><span>Look a block or an address up.</span></a>
|
||||
<a href="/journey" data-nav="journey"><b>The journey</b><span>Six phases, four gates, the log behind them.</span></a>
|
||||
<a href="/bench" data-nav="bench"><b>Engineering log</b><span>Every measurement, with the commands that made it.</span></a>
|
||||
<a href="/evidence" data-nav="evidence"><b>Evidence</b><span>Every claim and how far it is tested.</span></a>
|
||||
<a href="/light" data-nav="light"><b>Light wallet</b><span>A balance your browser proves, trusting no node.</span></a>
|
||||
<a href="/receipt" data-nav="receipt"><b>Payment receipt</b><span>A receipt any third party re-verifies offline.</span></a>
|
||||
<a href="/oracle" data-nav="oracle"><b>State oracle on Sepolia</b><span>Devnet 3 balances read from another chain.</span></a>
|
||||
</div>
|
||||
<div class="sheet-group"><div class="sheet-head">Learn</div>
|
||||
<a href="/litepaper" data-nav="litepaper"><b>Litepaper</b><span>The design, as published.</span></a>
|
||||
|
|
@ -177,6 +196,12 @@ main{padding-bottom:100px}.card{background:var(--row);border:1px solid var(--lin
|
|||
<a href="/randomx" data-nav="randomx"><b>Igneum vs RandomX</b><span>What was kept and what was rebuilt for GPUs.</span></a>
|
||||
<a href="/provenance" data-nav="provenance"><b>Built on the shoulders</b><span>Every borrowed part, credited.</span></a>
|
||||
</div>
|
||||
<div class="sheet-group"><div class="sheet-head">Build</div>
|
||||
<a href="/build" data-nav="build"><b>Build on Igneum</b><span>Chain ids, RPC, a contract in five minutes.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Devnet faucet</b><span>10 IGN of devnet coin, once a day.</span></a>
|
||||
<a href="/swap" data-nav="swap"><b>Swap</b><span>Test tokens on Devnet 3; every swap is a proven block.</span></a>
|
||||
<a href="/grants" data-nav="grants"><b>Grants</b><span>Tooling, apps, infrastructure, research.</span></a>
|
||||
</div>
|
||||
<div class="sheet-foot">
|
||||
<a href="/download" class="btn primary big" data-nav="download">Download</a>
|
||||
<div class="sheet-social"><a href="https://discord.gg/igneum" target="_blank" rel="noopener">Discord</a><a href="https://git.igneum.network/igneum-network/spec" target="_blank" rel="noopener">Source</a><a href="https://www.reddit.com/user/Igneum_network/" target="_blank" rel="noopener">Reddit</a></div>
|
||||
|
|
@ -233,7 +258,7 @@ main{padding-bottom:100px}.card{background:var(--row);border:1px solid var(--lin
|
|||
<main id="main" class="wrap">
|
||||
<div class="head">
|
||||
<div class="breadcrumb"><a href="/">Igneum</a><span>/</span><a href="/explorer">Explorer</a><span>/</span><span>Block</span></div>
|
||||
<div class="eyebrow"><a href="/explorer">Explorer</a> · block</div>
|
||||
<div class="eyebrow"><a href="/explorer">Devnet 3 explorer</a> · block</div>
|
||||
<h1 class="hash" id="title">Block</h1>
|
||||
<div id="chips"></div>
|
||||
<div class="msg" id="msg" aria-live="polite"></div>
|
||||
|
|
@ -248,8 +273,8 @@ main{padding-bottom:100px}.card{background:var(--row);border:1px solid var(--lin
|
|||
<div class="card"><div class="viz-head"><h2>Mergeset</h2><div class="eyebrow">what this block merges</div></div><div id="mergeset"></div><p class="note">A chain block merges the blocks in its past that no earlier chain block merged. Blue ones are paid by this block's coinbase; red ones are excluded from the order and their reward goes to this block's miner.</p></div>
|
||||
</div>
|
||||
<div class="card"><div class="viz-head"><h2>Transactions</h2><div class="eyebrow" id="tx-n"></div></div><div id="coinbase"></div><div class="tbl" id="txs"></div></div>
|
||||
<div class="card"><div class="viz-head"><h2>Proof records and shards</h2><div class="eyebrow" id="proof-eyebrow"></div></div><div id="proofs"></div></div>
|
||||
<div class="card"><div class="viz-head"><h2>Finality</h2><div class="eyebrow" id="fin-eyebrow"></div></div><div id="finality"></div></div>
|
||||
<div class="card"><div class="viz-head"><h2>Shard plan and proofs</h2><div class="eyebrow" id="proof-eyebrow"></div></div><div id="proofs"></div></div>
|
||||
<div class="card"><div class="viz-head"><h2>Finality</h2><div class="eyebrow" id="fin-eyebrow"></div></div><div id="finality"></div><div id="recheck"></div></div>
|
||||
</div>
|
||||
</main>
|
||||
<!-- footer:start -->
|
||||
|
|
@ -274,7 +299,7 @@ main{padding-bottom:100px}.card{background:var(--row);border:1px solid var(--lin
|
|||
<a href="/wallet">The wallet</a>
|
||||
<a href="/miners">GPU bench table</a>
|
||||
<a href="/dev-fee">The dev fee</a>
|
||||
<a href="/faucet">Testnet faucet</a>
|
||||
<a href="/faucet">Devnet faucet</a>
|
||||
<a href="/metamask">Add Igneum to MetaMask</a>
|
||||
</div></div>
|
||||
<div class="footer-column"><h4>Read</h4><div>
|
||||
|
|
@ -289,6 +314,9 @@ main{padding-bottom:100px}.card{background:var(--row);border:1px solid var(--lin
|
|||
<div class="footer-column"><h4>Explore</h4><div>
|
||||
<a href="/live">Live devnet</a>
|
||||
<a href="/explorer">Explorer</a>
|
||||
<a href="/build">Build on Igneum</a>
|
||||
<a href="/swap">Swap</a>
|
||||
<a href="/grants">Grants</a>
|
||||
<a href="/journey">Journey</a>
|
||||
<a href="/download">Downloads: devnet build</a>
|
||||
<a href="https://discord.gg/igneum" target="_blank" rel="noopener">Community Discord</a>
|
||||
|
|
@ -328,28 +356,47 @@ const addr = a => a ? `<a class="hash" href="/address/${esc(a)}">${esc(a)}</a>`
|
|||
const dl = pairs => pairs.filter(p => p).map(([k, v]) => `<dt>${esc(k)}</dt><dd>${v}</dd>`).join('');
|
||||
const id = decodeURIComponent(location.pathname.split('/').pop() || '');
|
||||
const query = /^\d{1,12}$/.test(id) ? 'height=' + id : 'block=' + encodeURIComponent(id.replace(/^0x/i, ''));
|
||||
async function recheck(index, blockHash, isCheckpoint) {
|
||||
// the verified badge: this browser fetches the certificate that covers the block and checks it with the site's light client
|
||||
const el = $('recheck'); el.innerHTML = `<p class="note" id="rc-line">Re-checking certificate ${int(index)} in this browser.</p>`;
|
||||
const badge = document.createElement('span'); badge.className = 'badge wait'; badge.textContent = 'checking the certificate'; $('chips').appendChild(badge);
|
||||
try {
|
||||
const { fetchCheckpoint, verify } = await import('/verify/verify.js');
|
||||
const data = await fetchCheckpoint('/api/checkpoint?index=' + index);
|
||||
const r = verify(data);
|
||||
if (r.verified) {
|
||||
badge.className = 'badge ok'; badge.textContent = isCheckpoint ? 'verified in this browser' : `verified under lock ${int(index)} in this browser`;
|
||||
$('rc-line').innerHTML = `Certificate ${int(index)} re-checked in this browser in ${r.ms} ms: ${int(r.headers_checked)} header hashes recomputed, ${int(r.signers)} of ${int(r.voters)} voters' BLS keys aggregated, the signature verifies over ${(r.weight_fraction_total * 100).toFixed(1)}% of all weight. ${isCheckpoint ? 'This block is the certified checkpoint.' : 'This block sits under that lock on the selected chain.'} The light client is <a href="/verify/core.js">/verify/core.js</a>; the data it checked is <a href="/api/checkpoint?index=${index}">/api/checkpoint?index=${index}</a>.`;
|
||||
} else { badge.className = 'badge bad'; badge.textContent = 'certificate did not verify'; $('rc-line').textContent = `Certificate ${int(index)} did not verify in this browser: ${r.error || 'unknown reason'}.`; }
|
||||
} catch (e) { badge.className = 'badge wait'; badge.textContent = 're-check unavailable'; $('rc-line').textContent = 'The re-check could not run: ' + (e.message || e); }
|
||||
}
|
||||
async function load() {
|
||||
const r = await fetch('/api/explorer?' + query); const j = await r.json();
|
||||
if (!j.ok) { $('msg').textContent = j.error || 'Not found.'; $('title').textContent = /^\d/.test(id) ? 'Chain block ' + id : shortHash(id, 10, 8); return; }
|
||||
const b = j.block, d = b.detail || {}, now = new Date(j.now).getTime();
|
||||
document.title = `Igneum block ${shortHash(b.hash, 8, 6)}`;
|
||||
const b = j.block, d = b.detail || {}, now = new Date(j.now).getTime(), sum = b.shard_summary || { total: 0, paid: 0 };
|
||||
document.title = `Devnet 3 block ${shortHash(b.hash, 8, 6)}`;
|
||||
$('title').textContent = b.hash;
|
||||
const chips = [b.chain ? '<span class="chip hot">chain block</span>' : `<span class="chip">${esc(b.color)}</span>`];
|
||||
const chips = [b.chain ? (b.chain_now === false ? '<span class="chip" title="the observer saw it as the chain block of its number; a tip reorg gave the number to another block">chain block, replaced</span>' : '<span class="chip hot">chain block</span>') : `<span class="chip">${esc(b.color)}</span>`, `<span class="chip" title="the hash program family this block was mined under">class ${esc(b.class ? b.class.class : 'v4')}</span>`];
|
||||
if (j.checkpoint) chips.push(`<span class="chip ${j.checkpoint.state === 'locked' ? 'ok' : ''}">checkpoint ${j.checkpoint.index}, ${esc(j.checkpoint.state)}</span>`);
|
||||
if (b.proof_records) chips.push(`<span class="chip">${b.proof_records} proof record${b.proof_records === 1 ? '' : 's'}</span>`);
|
||||
if (b.tx_count) chips.push(`<span class="chip">${b.tx_count} transaction${b.tx_count === 1 ? '' : 's'}</span>`);
|
||||
chips.push(b.lock && b.lock.final ? `<span class="chip ok" title="${esc(b.lock.reason)}">final under lock ${int(b.lock.index)}</span>` : `<span class="chip" title="${esc(b.lock ? b.lock.reason : '')}">not under a lock yet</span>`);
|
||||
if (b.chain) chips.push(sum.total ? `<span class="chip ${sum.paid === sum.total ? 'ok' : ''}">${sum.paid} of ${sum.total} shards paid</span>` : '<span class="chip">plan not read yet</span>');
|
||||
if (b.proof_records) chips.push(`<span class="chip">carries ${b.proof_records} proof record${b.proof_records === 1 ? '' : 's'}</span>`);
|
||||
if (j.txs.length) chips.push(`<span class="chip">${j.txs.length} transaction${j.txs.length === 1 ? '' : 's'} executed</span>`);
|
||||
$('chips').innerHTML = chips.join('');
|
||||
$('summary').innerHTML = dl([
|
||||
['Number', b.number === null ? '<span style="color:var(--ash)">none, not a chain block</span>' : int(b.number)],
|
||||
['Time', `${utc(b.ts)} <span style="color:var(--ash)">(${rel(now - b.ts)})</span>`],
|
||||
['Network', 'Devnet 3, chain id ' + esc(j.chain_id ?? 4463)],
|
||||
['Number', b.number === null ? '<span class="kv">none, not a chain block</span>' : (b.chain_now === false ? `${int(b.number)} <span class="kv">as the observer first saw it; a tip reorg gave this number to another block, so the EVM executed that one</span>` : int(b.number))],
|
||||
['Time', `${utc(b.ts)} <span class="kv">(${rel(now - b.ts)})</span>`],
|
||||
['DAA score', int(b.daa)], ['Blue score', int(b.blue_score)],
|
||||
['Class', `${esc(b.class ? b.class.class : 'v4')} <span class="kv">${b.class && b.class.floors ? b.class.floors.map(f => `${f.class} from DAA ${int(f.daa)}`).join(', ') : ''}</span>`],
|
||||
['Lock state', b.lock ? `${b.lock.final ? 'final' : 'not final'} <span class="kv">${esc(b.lock.reason)}${j.lock ? `; newest lock ${int(j.lock.index)} at blue score ${int(j.lock.blue_score)}, ${(j.lock.fraction_total * 100).toFixed(1)}% of all weight` : ''}</span>` : 'n/a'],
|
||||
['Miner', addr(b.evm_miner)], ['Coinbase address', addr(b.miner)],
|
||||
['Vote key', `<span class="id">${esc(b.miner_id || 'n/a')}</span> <span class="hash" style="color:var(--ash);font-size:12px">${esc(b.vote_key_hash || '')}</span>`],
|
||||
['Vote key', `<span class="id">${esc(b.miner_id || 'n/a')}</span> <span class="hash kv" style="font-size:12px">${esc(b.vote_key_hash || '')}</span>`],
|
||||
b.engine ? ['Engine', esc(b.engine)] : null,
|
||||
['Difficulty', d.difficulty ? int(d.difficulty) : 'n/a'],
|
||||
['Declared subsidy', b.subsidy_sompi ? `${ign(b.subsidy_sompi, 8)} IGN <span style="color:var(--ash)">E(DAA) of spec 2.5, paid when a later chain block merges this one</span>` : 'n/a'],
|
||||
['Coinbase paid', b.paid_sompi ? `${ign(b.paid_sompi, 8)} IGN <span style="color:var(--ash)">to the blocks it merges</span>` : 'n/a'],
|
||||
['Merged by', b.chain ? 'itself (chain block)' : (j.merged_by ? link(j.merged_by) : '<span style="color:var(--ash)">not yet</span>')],
|
||||
['Declared subsidy', b.subsidy_sompi ? `${ign(b.subsidy_sompi, 8)} IGN <span class="kv">E(DAA) of spec 2.5, paid when a later chain block merges this one</span>` : 'n/a'],
|
||||
['Coinbase paid', b.paid_sompi ? `${ign(b.paid_sompi, 8)} IGN <span class="kv">to the blocks it merges</span>` : 'n/a'],
|
||||
['Merged by', b.chain ? 'itself (chain block)' : (j.merged_by ? link(j.merged_by) : '<span class="kv">not yet</span>')],
|
||||
['Selected parent', b.selected_parent ? link(b.selected_parent) : 'n/a'],
|
||||
]);
|
||||
$('header').innerHTML = dl([
|
||||
|
|
@ -364,21 +411,25 @@ async function load() {
|
|||
const ms = d.mergeset || { blues: [], reds: [] };
|
||||
$('mergeset').innerHTML = (ms.blues.length || ms.reds.length) ? `<div style="display:flex;flex-direction:column;gap:6px">${ms.blues.map(h => `<div><i class="sw blue"></i>${link(h)}</div>`).join('')}${ms.reds.map(h => `<div><i class="sw red"></i>${link(h)}</div>`).join('')}</div>` : '<div class="empty">Empty.</div>';
|
||||
const cb = d.coinbase;
|
||||
$('tx-n').textContent = `${b.tx_count ?? 0} EVM, 1 coinbase`;
|
||||
$('coinbase').innerHTML = cb ? `<dl>${dl([['Coinbase', `<span class="hash">${esc(cb.id)}</span>`], ['Outputs', cb.outputs.map(o => `${o.pool ? '<span style="color:var(--ash)">proving pool (burns on the UTXO side, credited on the EVM side)</span>' : addr(o.address)} <b>${ign(o.value, 8)} IGN</b>`).join('<br>') || 'none'], ['Carries', `${cb.records} proof record${cb.records === 1 ? '' : 's'}${cb.reveal ? ', a key reveal' : ''}${(d.certificates || []).length ? `, certificate ${d.certificates.join(', ')}` : ''}`]])}</dl>` : '<div class="empty">No coinbase decoded.</div>';
|
||||
const txs = d.txs || []; const ev = j.evm && j.evm.transactions ? new Map(j.evm.transactions.map(t => [t.hash, t])) : null;
|
||||
$('txs').innerHTML = txs.length ? `<table><thead><tr><th>Transaction</th><th>From</th><th>To</th><th class="n">Value</th><th class="n">Bytes</th></tr></thead><tbody>${txs.map(t => { const e = ev && ev.get(t.hash); return `<tr id="tx-${esc((t.hash || '').replace(/^0x/, ''))}"><td class="hash">${esc(t.hash || '?')}</td><td>${e ? addr(e.from) : '<span style="color:var(--ash)">needs an EVM RPC</span>'}</td><td>${e ? addr(e.to) : ''}</td><td class="n">${e ? ignFromWei(e.value) + ' IGN' : ''}</td><td class="n">${t.size ?? ''}</td></tr>`; }).join('')}</tbody></table>` : '<div class="empty" style="margin-top:8px">No EVM transactions in this block.</div>';
|
||||
$('tx-n').textContent = `${b.tx_count ?? 0} carried, ${j.txs.length} executed by the EVM, 1 coinbase`;
|
||||
$('coinbase').innerHTML = cb ? `<dl>${dl([['Coinbase', `<span class="hash">${esc(cb.id)}</span>`], ['Outputs', cb.outputs.map(o => `${o.pool ? '<span class="kv">proving pool (burns on the UTXO side, credited on the EVM side)</span>' : addr(o.address)} <b>${ign(o.value, 8)} IGN</b>`).join('<br>') || 'none'], ['Carries', `${cb.records} proof record${cb.records === 1 ? '' : 's'}${cb.reveal ? ', a key reveal' : ''}${(d.certificates || []).length ? `, certificate ${d.certificates.join(', ')}` : ''}`]])}</dl>` : '<div class="empty">No coinbase decoded.</div>';
|
||||
const carried = d.txs || [];
|
||||
$('txs').innerHTML = j.txs.length ? `<table><thead><tr><th>Transaction</th><th>From</th><th>To</th><th class="n">Value</th><th>Status</th><th class="n">Gas used</th></tr></thead><tbody>${j.txs.map(t => `<tr id="tx-${esc(t.hash.replace(/^0x/, ''))}"><td><a class="hash" href="/tx/${esc(t.hash)}">${esc(shortHash(t.hash, 12, 8))}</a></td><td>${t.from ? `<a class="hash" href="/address/${esc(t.from)}">${esc(shortHash(t.from, 8, 6))}</a>` : ''}</td><td>${t.to ? `<a class="hash" href="/address/${esc(t.to)}">${esc(shortHash(t.to, 8, 6))}</a>` : (t.contract_address ? `<span class="kv">created</span> <a class="hash" href="/address/${esc(t.contract_address)}">${esc(shortHash(t.contract_address, 8, 6))}</a>` : '<span class="kv">none</span>')}</td><td class="n">${ignFromWei(t.value_wei, 6)} IGN</td><td>${t.status === 'success' ? '<span class="chip ok">ok</span>' : t.status === 'failed' ? '<span class="chip" style="border-color:var(--excluded);color:var(--excluded)">failed</span>' : '<span class="kv">no receipt</span>'}</td><td class="n">${int(t.gas_used)}</td></tr>`).join('')}</tbody></table>` :
|
||||
(carried.length ? `<p class="note">This block carries ${carried.length} transaction${carried.length === 1 ? '' : 's'}; ${b.chain ? 'the indexer has not read the block yet, or every one had already been executed in an earlier chain block' : 'they execute in the chain block that merges this one'}.</p>` : '<div class="empty" style="margin-top:8px">No EVM transactions in this block.</div>');
|
||||
if (j.evm && !j.evm.error) $('txs').insertAdjacentHTML('beforeend', `<p class="note">EVM view of this chain block: gas used ${int(j.evm.gas_used)}, state root <span class="hash">${esc(shortHash(j.evm.state_root, 10, 6))}</span>${j.evm.igneum ? `, rewards ${j.evm.igneum.rewards.map(r => ignFromWei(r.wei) + ' IGN to ' + shortHash(r.miner, 6, 4)).join(', ')}, proving pool credit ${ignFromWei(j.evm.igneum.proving_pool_credit)} IGN` : ''}.</p>`);
|
||||
const sh = j.shards;
|
||||
$('proof-eyebrow').textContent = b.chain ? `${sh.length} shard${sh.length === 1 ? '' : 's'} planned for this chain block` : 'not a chain block';
|
||||
$('proofs').innerHTML = `<p style="font-size:14px;color:var(--ink-2)">This block carries <b>${b.proof_records ?? 0}</b> proof record${b.proof_records === 1 ? '' : 's'} for earlier chain blocks (274 bytes each, in the coinbase extra data).</p>` +
|
||||
(sh.length ? `<div class="tbl"><table><thead><tr><th class="n">Shard</th><th>State</th><th>Prover</th><th class="n">pgas</th><th class="n">Proof lag, DAA</th><th>Carried by</th><th class="n">Payout</th></tr></thead><tbody>${sh.map(s => `<tr><td class="n">${s.i} of ${s.n}</td><td><span class="chip ${s.state === 'paid' ? 'ok' : s.state === 'verified' ? 'hot' : ''}">${esc(s.state)}</span></td><td class="id">${esc(s.prover || '')}</td><td class="n">${int(s.pgas)}</td><td class="n">${s.lag === null ? '' : int(s.lag)}</td><td>${s.carried_by ? link(s.carried_by) : ''}</td><td class="n">${s.payout_wei ? ignFromWei(s.payout_wei, 6) + ' IGN' : ''}</td></tr>`).join('')}</tbody></table></div>` : (b.chain ? '<div class="empty">No shard plan recorded (the proving feed was not reading this block).</div>' : ''));
|
||||
$('proofs').innerHTML = `<p style="font-size:14px;color:var(--ink-2)">This block carries <b>${b.proof_records ?? 0}</b> proof record${b.proof_records === 1 ? '' : 's'} for earlier chain blocks (274 bytes each, in the coinbase extra data).${b.chain ? ` Its own execution is split into <b>${sum.total}</b> shard${sum.total === 1 ? '' : 's'}: ${sum.paid} paid, ${sum.verified} verified, ${sum.proving} proving, ${sum.planned} planned.` : ''}</p>` +
|
||||
(sh.length ? `<div class="tbl"><table><thead><tr><th class="n">Shard</th><th>State</th><th>Prover</th><th class="n">pgas</th><th class="n">Proof lag, DAA</th><th>Carried by</th><th class="n">Payout</th><th>Node verdict</th></tr></thead><tbody>${sh.map(s => `<tr><td class="n">${s.i} of ${s.n}</td><td><span class="chip ${s.state === 'paid' ? 'ok' : s.state === 'verified' || s.state === 'proving' ? 'hot' : ''}">${esc(s.state)}</span></td><td class="id">${esc(s.prover || '')}</td><td class="n">${int(s.pgas)}</td><td class="n">${s.lag === null ? '' : int(s.lag)}</td><td>${s.carried_by ? link(s.carried_by) : ''}</td><td class="n">${s.payout_wei ? ignFromWei(s.payout_wei, 6) + ' IGN' : ''}</td><td>${s.node_verified === true ? 'proof verified by the node' : s.node_verified === false ? 'not verified' : '<span class="kv">no record yet</span>'}</td></tr>`).join('')}</tbody></table></div><p class="note">State follows the record: planned when the node published the shard plan, proving when a prover's record is in the pool, verified when the node's SP1 verifier accepted the proof, paid when a later coinbase carried and paid it. The explorer does not re-run the STARK itself; the node's verdict is shown as the node's. Every state, number and record on this page is read from the observer node, the chain the finality certificates follow.</p>` : (b.chain ? '<div class="empty">No shard plan recorded (the proving feed has not read this block).</div>' : ''));
|
||||
const cp = j.checkpoint, certs = j.certificates || [];
|
||||
$('fin-eyebrow').textContent = cp ? `checkpoint ${cp.index}` : (certs.length ? 'carries a certificate' : 'not a checkpoint');
|
||||
$('finality').innerHTML = (cp ? `<dl>${dl([['State', `<span class="chip ${cp.state === 'locked' ? 'ok' : ''}">${esc(cp.state)}</span>`], ['Signed weight', `${int(cp.signed)} of ${int(cp.total)} (${(cp.fraction_total * 100).toFixed(1)}% of all weight, ${(cp.fraction_active * 100).toFixed(1)}% of active)`], ['Votes', `${int(cp.votes)} of ${int(cp.voters)} voters`], cp.locked_at ? ['Locked', utc(new Date(cp.locked_at).getTime())] : null])}</dl>` : '') +
|
||||
certs.map(c => `<dl style="margin-top:14px">${dl([[c.role === 'checkpoint' ? 'Certificate' : 'Carries certificate', `index ${c.index}, ${c.voter_count} voters, aggregator <span class="id">${esc(shortHash(c.aggregator, 8, 0))}</span>, ${c.role === 'checkpoint' ? 'carried by ' + link(c.carrier) : 'for checkpoint ' + link(c.checkpoint)}`], ['Weight', `${int(c.total_weight)} total, ${int(c.active_weight)} active at the lock`], c.previous ? ['Previous lock', `index ${c.previous.index}, ${link(c.previous.hash)}${c.headers_complete ? ', header chain stored' : ''}`] : null, ['Verify', `<a href="/api/checkpoint">/api/checkpoint</a> serves the newest certificate for the in-browser verifier`]])}</dl>`).join('') +
|
||||
(!cp && !certs.length ? '<div class="empty">This block is neither a checkpoint nor a certificate carrier. Checkpoints are every 30 blue score; a lock needs two thirds of all 30-day weight.</div>' : '');
|
||||
certs.map(c => `<dl style="margin-top:14px">${dl([[c.role === 'checkpoint' ? 'Certificate' : 'Carries certificate', `index ${c.index}, ${c.voter_count} voters, aggregator <span class="id">${esc(shortHash(c.aggregator, 8, 0))}</span>, ${c.role === 'checkpoint' ? 'carried by ' + link(c.carrier) : 'for checkpoint ' + link(c.checkpoint)}`], ['Weight', `${int(c.total_weight)} total, ${int(c.active_weight)} active at the lock`], c.previous ? ['Previous lock', `index ${c.previous.index}, ${link(c.previous.hash)}${c.headers_complete ? ', header chain stored' : ''}`] : null, ['Data', `<a href="/api/checkpoint?index=${c.index}">/api/checkpoint?index=${c.index}</a> serves this certificate for the in-browser verifier`]])}</dl>`).join('') +
|
||||
(!cp && !certs.length ? `<div class="empty">This block is neither a checkpoint nor a certificate carrier. Checkpoints are every 30 blue score; a lock needs two thirds of all 30-day weight.${b.lock && b.lock.final ? ` This block is under lock ${int(b.lock.index)}.` : ''}</div>` : '');
|
||||
$('body').hidden = false;
|
||||
const ownCert = certs.find(c => c.role === 'checkpoint');
|
||||
if (ownCert) recheck(ownCert.index, b.hash, true);
|
||||
else if (b.lock && b.lock.final && b.lock.index !== undefined) recheck(b.lock.index, b.hash, false);
|
||||
}
|
||||
load().catch(e => { $('msg').textContent = 'The API did not answer: ' + e.message; });
|
||||
</script>
|
||||
|
|
|
|||
365
site/build.html
Normal file
365
site/build.html
Normal file
|
|
@ -0,0 +1,365 @@
|
|||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
|
||||
<title>Build on Igneum: chain ids, RPC, a contract in five minutes</title>
|
||||
<meta name="description" content="The developer entry page for Igneum: what is different, the chain ids and RPC endpoints, the wallet, the explorer, the faucet, a five-minute contract deploy and a block you verify in your browser.">
|
||||
<link rel="canonical" href="https://igneum.network/build">
|
||||
<meta name="theme-color" content="#0C0C0E">
|
||||
<meta property="og:type" content="website">
|
||||
<meta property="og:site_name" content="Igneum">
|
||||
<meta property="og:title" content="Build on Igneum: chain ids, RPC, a contract in five minutes">
|
||||
<meta property="og:description" content="The developer entry page for Igneum: what is different, the chain ids and RPC endpoints, the wallet, the explorer, the faucet, a five-minute contract deploy and a block you verify in your browser.">
|
||||
<meta property="og:url" content="https://igneum.network/build">
|
||||
<meta property="og:image" content="https://igneum.network/og.png?v=3">
|
||||
<meta property="og:image:width" content="1200">
|
||||
<meta property="og:image:height" content="630">
|
||||
<meta property="og:image:alt" content="Igneum. Mined by GPUs. Proven by fire.">
|
||||
<meta name="twitter:card" content="summary_large_image">
|
||||
<meta name="twitter:title" content="Build on Igneum: chain ids, RPC, a contract in five minutes">
|
||||
<meta name="twitter:description" content="The developer entry page for Igneum: what is different, the chain ids and RPC endpoints, the wallet, the explorer, the faucet, a five-minute contract deploy and a block you verify in your browser.">
|
||||
<meta name="twitter:image" content="https://igneum.network/og.png?v=3">
|
||||
<meta name="twitter:image:alt" content="Igneum. Mined by GPUs. Proven by fire.">
|
||||
<link rel="icon" href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1024 1024'%3E%3Crect width='1024' height='1024' fill='%230C0C0E'/%3E%3Cg transform='translate(166.95 166.95) scale(6.901)'%3E%3Cpolygon points='50,4 74,34 67,58 80,54 61,96 39,96 20,54 33,58 26,34' fill='%23F2541B'/%3E%3Cpolygon points='50,42 59,58 50,82 41,58' fill='%230C0C0E'/%3E%3C/g%3E%3C/svg%3E" type="image/svg+xml">
|
||||
<link rel="icon" href="/favicon.ico" sizes="48x48">
|
||||
<link rel="icon" href="/favicon-32.png" type="image/png" sizes="32x32">
|
||||
<link rel="icon" href="/icon-192.png" type="image/png" sizes="192x192">
|
||||
<link rel="icon" href="/icon-512.png" type="image/png" sizes="512x512">
|
||||
<link rel="apple-touch-icon" href="/apple-touch-icon.png" sizes="180x180">
|
||||
<link rel="manifest" href="/site.webmanifest">
|
||||
<!-- head:start -->
|
||||
<link rel="preload" href="/fonts/unbounded-900.woff2" as="font" type="font/woff2" crossorigin>
|
||||
<link rel="preload" href="/fonts/plex-sans-400.woff2" as="font" type="font/woff2" crossorigin>
|
||||
<meta name="color-scheme" content="dark light">
|
||||
<link rel="stylesheet" href="/site.css">
|
||||
<style>
|
||||
/* Shared by every page: the head partial, injected by the build between the head markers. Edit the partial, not the page. */
|
||||
/* Fonts, self-hosted (latin subsets, OFL): Unbounded 500/700/900, IBM Plex Sans 400/500/600, IBM Plex Mono 400/500. Fallbacks carry size and ascent overrides so the swap does not move the layout. The tokens, type and components are in /site.css (docs/plans/site-ui-3.md). */
|
||||
@font-face{font-family:'Unbounded';font-style:normal;font-weight:500;font-display:swap;src:url(/fonts/unbounded-500.woff2) format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
|
||||
@font-face{font-family:'Unbounded';font-style:normal;font-weight:700;font-display:swap;src:url(/fonts/unbounded-700.woff2) format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
|
||||
@font-face{font-family:'Unbounded';font-style:normal;font-weight:900;font-display:swap;src:url(/fonts/unbounded-900.woff2) format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
|
||||
@font-face{font-family:'IBM Plex Sans';font-style:normal;font-weight:400;font-display:swap;src:url(/fonts/plex-sans-400.woff2) format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
|
||||
@font-face{font-family:'IBM Plex Sans';font-style:normal;font-weight:500;font-display:swap;src:url(/fonts/plex-sans-500.woff2) format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
|
||||
@font-face{font-family:'IBM Plex Sans';font-style:normal;font-weight:600;font-display:swap;src:url(/fonts/plex-sans-600.woff2) format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
|
||||
@font-face{font-family:'IBM Plex Mono';font-style:normal;font-weight:400;font-display:swap;src:url(/fonts/plex-mono-400.woff2) format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
|
||||
@font-face{font-family:'IBM Plex Mono';font-style:normal;font-weight:500;font-display:swap;src:url(/fonts/plex-mono-500.woff2) format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
|
||||
@font-face{font-family:'Unbounded Fallback';src:local('Arial Black'),local('Arial-Black'),local('Impact');size-adjust:114%;ascent-override:87.5%;descent-override:21.5%;line-gap-override:0%}
|
||||
@font-face{font-family:'Plex Sans Fallback';src:local('Arial'),local('Helvetica Neue'),local('Helvetica');size-adjust:100.5%;ascent-override:102%;descent-override:27.4%;line-gap-override:0%}
|
||||
@font-face{font-family:'Plex Mono Fallback';src:local('Courier New'),local('Menlo');size-adjust:100%;ascent-override:102.5%;descent-override:27.5%;line-gap-override:0%}
|
||||
</style>
|
||||
<script>
|
||||
/* theme before first paint: ?theme=light|dark for one view (the capture tool), else the stored choice under igneum-theme, else the system setting; ?motion=off marks the page data-motion=off so every .reveal is drawn at once (a headless render never scrolls) */
|
||||
(function(){var t=null;try{t=new URLSearchParams(location.search).get("theme");}catch(e){}if(t!=="light"&&t!=="dark"){try{t=localStorage.getItem("igneum-theme");}catch(e){t=null;}}if(t!=="light"&&t!=="dark")t=window.matchMedia&&window.matchMedia("(prefers-color-scheme: light)").matches?"light":"dark";document.documentElement.setAttribute("data-theme",t);try{if(new URLSearchParams(location.search).get("motion")==="off")document.documentElement.setAttribute("data-motion","off");}catch(e){}})();
|
||||
</script>
|
||||
<!-- head:end -->
|
||||
<style>
|
||||
/* generated-page block (the engineering log, the bench table, the provenance table): the page hero, the contents rail, the sections; tokens, type and components are in /site.css */
|
||||
[id]{scroll-margin-top:120px}
|
||||
article h1{display:none}
|
||||
article{color:var(--ink-2)}
|
||||
article h2{font-size:var(--t-h3);margin:0 0 12px}
|
||||
article h3{font-size:16px;margin:26px 0 8px}
|
||||
article h4{font:600 15px/1.4 var(--f-sans);margin:20px 0 6px;color:var(--bone)}
|
||||
article p{margin:0 0 14px}article ul,article ol{margin:0 0 14px;padding-left:22px}article li{margin-bottom:6px}
|
||||
article p,article li,article h2,article h3{overflow-wrap:anywhere}
|
||||
article pre{margin:0 0 var(--s-4)}
|
||||
.doc-section:last-child{border-bottom:0}
|
||||
.doc-section[hidden]{display:none}
|
||||
.tbl{margin:var(--s-4) 0 var(--s-5)}
|
||||
table{min-width:560px}
|
||||
.gen{color:var(--ash);font-size:13px;margin:40px 0 0;max-width:72ch}
|
||||
.doc-tools{margin:0 0 var(--s-5)}
|
||||
.doc-tools .searchbar{max-width:560px}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<!-- nav:start -->
|
||||
<a class="skip" href="#main">Skip to content</a>
|
||||
<nav class="nav" aria-label="Main" data-nav-version="5">
|
||||
<div class="container nav-row">
|
||||
<a href="/" class="logo" aria-label="Igneum home">
|
||||
<svg class="brand-mark" viewBox="0 0 1024 1024" aria-hidden="true"><rect width="1024" height="1024" rx="160" fill="#0C0C0E"></rect><g transform="translate(166.95 166.95) scale(6.901)"><polygon points="50,4 74,34 67,58 80,54 61,96 39,96 20,54 33,58 26,34" fill="#F2541B"></polygon><polygon points="50,42 59,58 50,82 41,58" fill="#0C0C0E"></polygon></g></svg>
|
||||
<span class="word">IGNEUM</span>
|
||||
</a>
|
||||
<span class="devnet" id="nav-devnet" title="igneum-devnet-3, chain id 4463. Coins have no value. The chain may reset."><span class="dot off" id="foot-dot"></span><span id="foot-state">devnet</span></span>
|
||||
<div class="nav-groups" id="nav-groups" role="list">
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-mine" data-group="mine" aria-expanded="false" aria-controls="nav-panel-mine" aria-haspopup="true">Mine<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-network" data-group="network" aria-expanded="false" aria-controls="nav-panel-network" aria-haspopup="true">Network<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-learn" data-group="learn" aria-expanded="false" aria-controls="nav-panel-learn" aria-haspopup="true">Learn<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-build" data-group="build" data-active aria-expanded="false" aria-controls="nav-panel-build" aria-haspopup="true">Build<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
</div>
|
||||
<div class="nav-controls">
|
||||
<button class="btn icon-btn" type="button" data-theme-toggle aria-label="Switch to light theme"><svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><circle cx="12" cy="12" r="4"/><path d="M12 2v2m0 16v2M2 12h2m16 0h2M5 5l1 1m12 12 1 1M5 19l1-1M18 6l1-1"/></svg></button>
|
||||
<a href="/download" class="btn primary small cta" data-nav="download">Download</a>
|
||||
<button class="burger" id="nav-burger" type="button" aria-expanded="false" aria-controls="nav-sheet" aria-label="Open the menu" aria-haspopup="true"><svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path class="bars" d="M4 6h16M4 12h16M4 18h16"/><path class="cross" d="m6 6 12 12M6 18 18 6"/></svg></button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="panels" id="nav-panels">
|
||||
<div class="panel-wrap container">
|
||||
<div class="nav-panel" id="nav-panel-mine" data-group="mine" role="region" aria-labelledby="nav-btn-mine" hidden>
|
||||
<div class="panel-list">
|
||||
<a href="/miner" data-nav="miner"><b>Ember, the miner</b><span>One click installs the node, the miner and the prover.</span></a>
|
||||
<a href="/download" data-nav="download"><b>Download</b><span>Windows, macOS, Linux and HiveOS.</span></a>
|
||||
<a href="/app" data-nav="app"><b>The app</b><span>What you see while the card mines.</span></a>
|
||||
<a href="/wallet" data-nav="wallet"><b>The wallet</b><span>Your coins. Final means final.</span></a>
|
||||
<a href="/miners" data-nav="miners"><b>GPU bench table</b><span>Measured rates, card by card.</span></a>
|
||||
<a href="/dev-fee" data-nav="dev-fee"><b>The dev fee</b><span>The optional one, in full view, off with one flag.</span></a>
|
||||
<a href="/metamask" data-nav="metamask"><b>Add to MetaMask</b><span>Igneum as a network in your wallet.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-panel" id="nav-panel-network" data-group="network" role="region" aria-labelledby="nav-btn-network" hidden>
|
||||
<div class="panel-list">
|
||||
<a href="/live" data-nav="live"><b>Live devnet</b><span>The chain as it grows, one lane per miner.</span></a>
|
||||
<a href="/explorer" data-nav="explorer"><b>Explorer</b><span>Look a block or an address up.</span></a>
|
||||
<a href="/journey" data-nav="journey"><b>The journey</b><span>Six phases, four gates, the log behind them.</span></a>
|
||||
<a href="/bench" data-nav="bench"><b>Engineering log</b><span>Every measurement, with the commands that made it.</span></a>
|
||||
<a href="/evidence" data-nav="evidence"><b>Evidence</b><span>Every claim and how far it is tested.</span></a>
|
||||
<a href="/light" data-nav="light"><b>Light wallet</b><span>A balance your browser proves, trusting no node.</span></a>
|
||||
<a href="/receipt" data-nav="receipt"><b>Payment receipt</b><span>A receipt any third party re-verifies offline.</span></a>
|
||||
<a href="/oracle" data-nav="oracle"><b>State oracle on Sepolia</b><span>Devnet 3 balances read from another chain.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-panel" id="nav-panel-learn" data-group="learn" role="region" aria-labelledby="nav-btn-learn" hidden>
|
||||
<div class="panel-list">
|
||||
<a href="/litepaper" data-nav="litepaper"><b>Litepaper</b><span>The design, as published.</span></a>
|
||||
<a href="/income" data-nav="income"><b>Income per tier</b><span>IGN a day per card at three network sizes, and the electricity.</span></a>
|
||||
<a href="/ledger" data-nav="ledger"><b>Ledger</b><span>Every criticism, answered or conceded.</span></a>
|
||||
<a href="/claims" data-nav="claims"><b>What Igneum does not claim</b><span>The limits, stated first.</span></a>
|
||||
<a href="/randomx" data-nav="randomx"><b>Igneum vs RandomX</b><span>What was kept and what was rebuilt for GPUs.</span></a>
|
||||
<a href="/provenance" data-nav="provenance"><b>Built on the shoulders</b><span>Every borrowed part, credited.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-panel" id="nav-panel-build" data-group="build" role="region" aria-labelledby="nav-btn-build" hidden>
|
||||
<div class="panel-list">
|
||||
<a href="/build" data-nav="build" aria-current="page"><b>Build on Igneum</b><span>Chain ids, RPC, a contract in five minutes.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Devnet faucet</b><span>10 IGN of devnet coin, once a day.</span></a>
|
||||
<a href="/swap" data-nav="swap"><b>Swap</b><span>Test tokens on Devnet 3; every swap is a proven block.</span></a>
|
||||
<a href="/grants" data-nav="grants"><b>Grants</b><span>Tooling, apps, infrastructure, research.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-sheet" id="nav-sheet" role="dialog" aria-modal="true" aria-label="Menu" hidden>
|
||||
<div class="sheet-scroll">
|
||||
<div class="sheet-group"><div class="sheet-head">Mine</div>
|
||||
<a href="/miner" data-nav="miner"><b>Ember, the miner</b><span>One click installs the node, the miner and the prover.</span></a>
|
||||
<a href="/download" data-nav="download"><b>Download</b><span>Windows, macOS, Linux and HiveOS.</span></a>
|
||||
<a href="/app" data-nav="app"><b>The app</b><span>What you see while the card mines.</span></a>
|
||||
<a href="/wallet" data-nav="wallet"><b>The wallet</b><span>Your coins. Final means final.</span></a>
|
||||
<a href="/miners" data-nav="miners"><b>GPU bench table</b><span>Measured rates, card by card.</span></a>
|
||||
<a href="/dev-fee" data-nav="dev-fee"><b>The dev fee</b><span>The optional one, in full view, off with one flag.</span></a>
|
||||
<a href="/metamask" data-nav="metamask"><b>Add to MetaMask</b><span>Igneum as a network in your wallet.</span></a>
|
||||
</div>
|
||||
<div class="sheet-group"><div class="sheet-head">Network</div>
|
||||
<a href="/live" data-nav="live"><b>Live devnet</b><span>The chain as it grows, one lane per miner.</span></a>
|
||||
<a href="/explorer" data-nav="explorer"><b>Explorer</b><span>Look a block or an address up.</span></a>
|
||||
<a href="/journey" data-nav="journey"><b>The journey</b><span>Six phases, four gates, the log behind them.</span></a>
|
||||
<a href="/bench" data-nav="bench"><b>Engineering log</b><span>Every measurement, with the commands that made it.</span></a>
|
||||
<a href="/evidence" data-nav="evidence"><b>Evidence</b><span>Every claim and how far it is tested.</span></a>
|
||||
<a href="/light" data-nav="light"><b>Light wallet</b><span>A balance your browser proves, trusting no node.</span></a>
|
||||
<a href="/receipt" data-nav="receipt"><b>Payment receipt</b><span>A receipt any third party re-verifies offline.</span></a>
|
||||
<a href="/oracle" data-nav="oracle"><b>State oracle on Sepolia</b><span>Devnet 3 balances read from another chain.</span></a>
|
||||
</div>
|
||||
<div class="sheet-group"><div class="sheet-head">Learn</div>
|
||||
<a href="/litepaper" data-nav="litepaper"><b>Litepaper</b><span>The design, as published.</span></a>
|
||||
<a href="/income" data-nav="income"><b>Income per tier</b><span>IGN a day per card at three network sizes, and the electricity.</span></a>
|
||||
<a href="/ledger" data-nav="ledger"><b>Ledger</b><span>Every criticism, answered or conceded.</span></a>
|
||||
<a href="/claims" data-nav="claims"><b>What Igneum does not claim</b><span>The limits, stated first.</span></a>
|
||||
<a href="/randomx" data-nav="randomx"><b>Igneum vs RandomX</b><span>What was kept and what was rebuilt for GPUs.</span></a>
|
||||
<a href="/provenance" data-nav="provenance"><b>Built on the shoulders</b><span>Every borrowed part, credited.</span></a>
|
||||
</div>
|
||||
<div class="sheet-group"><div class="sheet-head">Build</div>
|
||||
<a href="/build" data-nav="build" aria-current="page"><b>Build on Igneum</b><span>Chain ids, RPC, a contract in five minutes.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Devnet faucet</b><span>10 IGN of devnet coin, once a day.</span></a>
|
||||
<a href="/swap" data-nav="swap"><b>Swap</b><span>Test tokens on Devnet 3; every swap is a proven block.</span></a>
|
||||
<a href="/grants" data-nav="grants"><b>Grants</b><span>Tooling, apps, infrastructure, research.</span></a>
|
||||
</div>
|
||||
<div class="sheet-foot">
|
||||
<a href="/download" class="btn primary big" data-nav="download">Download</a>
|
||||
<div class="sheet-social"><a href="https://discord.gg/igneum" target="_blank" rel="noopener">Discord</a><a href="https://git.igneum.network/igneum-network/spec" target="_blank" rel="noopener">Source</a><a href="https://www.reddit.com/user/Igneum_network/" target="_blank" rel="noopener">Reddit</a></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
<script>
|
||||
(function(){
|
||||
// the slim bar (site-ui-5, 7 Oct 2026): three group buttons open one panel each; the burger opens the sheet on phones.
|
||||
// Keyboard: Enter or Space opens a group, Escape closes it and returns focus to its button, arrows move between the
|
||||
// group buttons, Tab walks the open panel's links, a click outside closes. The theme toggle flips data-theme and stores it.
|
||||
var n=document.querySelector('.nav');if(!n)return;
|
||||
var btns=[].slice.call(n.querySelectorAll('.group-btn')),panels=[].slice.call(n.querySelectorAll('.nav-panel')),wrap=n.querySelector('.panels');
|
||||
var burger=document.getElementById('nav-burger'),sheet=document.getElementById('nav-sheet');
|
||||
function panelOf(g){return panels.filter(function(p){return p.getAttribute('data-group')===g;})[0];}
|
||||
function closeAll(focusBack){var was=null;btns.forEach(function(b){if(b.getAttribute('aria-expanded')==='true')was=b;b.setAttribute('aria-expanded','false');});panels.forEach(function(p){p.hidden=true;});n.classList.remove('panel-open');if(focusBack&&was)was.focus();}
|
||||
function open(g){closeAll(false);var b=btns.filter(function(x){return x.getAttribute('data-group')===g;})[0],p=panelOf(g);if(!b||!p)return;b.setAttribute('aria-expanded','true');p.hidden=false;n.classList.add('panel-open');anchor(b,p);}
|
||||
// the panel sits under its button; a panel that would run past the container's right edge aligns its right edge to the button's right edge instead (never past the viewport)
|
||||
function anchor(b,p){var pw=n.querySelector('.panel-wrap');if(!pw)return;var cr=pw.getBoundingClientRect(),br=b.getBoundingClientRect(),w=p.offsetWidth,left=br.left-cr.left;if(left+w>cr.width)left=(br.right-cr.left)-w;if(left<0)left=0;p.style.setProperty('--panel-left',Math.round(left)+'px');}
|
||||
window.addEventListener('resize',function(){var o=btns.filter(function(x){return x.getAttribute('aria-expanded')==='true';})[0];if(o)anchor(o,panelOf(o.getAttribute('data-group')));}); btns.forEach(function(b,i){
|
||||
b.addEventListener('click',function(){var on=b.getAttribute('aria-expanded')==='true';if(on)closeAll(false);else open(b.getAttribute('data-group'));});
|
||||
b.addEventListener('keydown',function(e){
|
||||
var k=e.key;
|
||||
if(k==='ArrowRight'||k==='ArrowLeft'){e.preventDefault();var j=(i+(k==='ArrowRight'?1:btns.length-1))%btns.length;btns[j].focus();if(n.classList.contains('panel-open'))open(btns[j].getAttribute('data-group'));}
|
||||
else if(k==='ArrowDown'){e.preventDefault();open(b.getAttribute('data-group'));var f=panelOf(b.getAttribute('data-group')).querySelector('a');if(f)f.focus();}
|
||||
else if(k==='Escape'){closeAll(true);}
|
||||
});
|
||||
});
|
||||
if(wrap)wrap.addEventListener('keydown',function(e){if(e.key==='Escape'){e.stopPropagation();closeAll(true);}});
|
||||
document.addEventListener('click',function(e){if(!n.classList.contains('panel-open'))return;if(e.target.closest('.group-btn')||e.target.closest('.nav-panel'))return;closeAll(false);});
|
||||
document.addEventListener('focusin',function(e){if(!n.classList.contains('panel-open'))return;if(n.contains(e.target))return;closeAll(false);});
|
||||
document.addEventListener('keydown',function(e){if(e.key==='Escape'&&n.classList.contains('panel-open'))closeAll(true);});
|
||||
// the sheet on phones
|
||||
function setSheet(o){if(!burger||!sheet)return;n.classList.toggle('open',o);sheet.hidden=!o;burger.setAttribute('aria-expanded',o?'true':'false');burger.setAttribute('aria-label',o?'Close the menu':'Open the menu');document.documentElement.classList.toggle('nav-locked',o);if(o){var f=sheet.querySelector('a');if(f)f.focus();}}
|
||||
if(burger&&sheet){
|
||||
burger.addEventListener('click',function(){setSheet(!n.classList.contains('open'));});
|
||||
sheet.addEventListener('click',function(e){if(e.target.closest('a'))setSheet(false);});
|
||||
sheet.addEventListener('keydown',function(e){
|
||||
if(e.key==='Escape'){setSheet(false);burger.focus();return;}
|
||||
if(e.key!=='Tab')return;var f=sheet.querySelectorAll('a,button');if(!f.length)return;var first=f[0],last=f[f.length-1];
|
||||
if(e.shiftKey&&document.activeElement===first){e.preventDefault();burger.focus();}else if(!e.shiftKey&&document.activeElement===last){e.preventDefault();burger.focus();}
|
||||
});
|
||||
burger.addEventListener('keydown',function(e){if(e.key==='Tab'&&!e.shiftKey&&n.classList.contains('open')){e.preventDefault();var f=sheet.querySelector('a');if(f)f.focus();}});
|
||||
var mq=window.matchMedia('(min-width:861px)');if(mq.addEventListener)mq.addEventListener('change',function(){setSheet(false);});
|
||||
}
|
||||
// the theme toggle
|
||||
var t=n.querySelector('[data-theme-toggle]');
|
||||
function paintToggle(){var dark=document.documentElement.getAttribute('data-theme')!=='light';t.setAttribute('aria-label',dark?'Switch to light theme':'Switch to dark theme');t.innerHTML=dark?'<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><circle cx="12" cy="12" r="4"/><path d="M12 2v2m0 16v2M2 12h2m16 0h2M5 5l1 1m12 12 1 1M5 19l1-1M18 6l1-1"/></svg>':'<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="M20.7 13.3A8.5 8.5 0 0 1 10.7 3.3 8.5 8.5 0 1 0 20.7 13.3Z"/></svg>';}
|
||||
if(t){t.addEventListener('click',function(){var v=document.documentElement.getAttribute('data-theme')==='light'?'dark':'light';document.documentElement.setAttribute('data-theme',v);try{localStorage.setItem('igneum-theme',v);}catch(e){}document.dispatchEvent(new CustomEvent('igneum-theme'));});paintToggle();document.addEventListener('igneum-theme',paintToggle);}
|
||||
})();
|
||||
</script>
|
||||
<!-- nav:end -->
|
||||
<main id="main">
|
||||
<section class="page-hero">
|
||||
<div class="container">
|
||||
<div class="breadcrumb"><a href="/">Igneum</a><span>/</span><span>Build on Igneum</span></div>
|
||||
<div class="page-heading"><div><div class="eyebrow"><span class="line"></span>Developers</div>
|
||||
<h1>Build on Igneum</h1>
|
||||
<p class="lead">Built to prove every block. A lock in minutes. Nothing to stake. The EVM you already know: Solidity deploys unchanged. Here are the chain ids, the endpoints and a contract in five minutes.</p></div></div>
|
||||
</div>
|
||||
</section>
|
||||
<section class="section compact"><div class="container">
|
||||
|
||||
<div class="docs-layout">
|
||||
<nav class="doc-nav" aria-label="Contents"><div class="eyebrow">Contents</div><a href="#what-is-different">What is different</a><a href="#networks">Networks</a><a href="#endpoints-and-tools">Endpoints and tools</a><a href="#your-first-contract-in-five-minutes">Your first contract in five minutes</a><a href="#the-rpc-the-node-serves">The RPC the node serves</a><a href="#verify-a-block-in-your-browser">Verify a block in your browser</a><a href="#where-to-ask">Where to ask</a></nav>
|
||||
<article class="doc-body" data-filter-list="build"><section class="doc-section"><h1 id="build-on-igneum">Build on Igneum</h1>
|
||||
<p>This file is the source of <a href="https://igneum.network/build" rel="noopener">igneum.network/build</a>. The site build renders it as the page. The other files in this directory are the walkthrough, the RPC list, the faucet, the verifier and the grants.</p>
|
||||
</section>
|
||||
<section class="doc-section"><h2 id="what-is-different">What is different</h2>
|
||||
<p><strong>Every block is built to be proven.</strong> A chain block carries a zero-knowledge proof of its execution. The miners are the provers: the same cards that find blocks prove them, in shards. On Devnet 3 a share of blocks carries a proof today; the live page shows the share and the lag, and the design target at launch is under a minute. Full nodes execute every block themselves, so a bad proof is a light-client problem and never a chain split.</p>
|
||||
<p><strong>A lock in minutes, not an hour of confirmations.</strong> Miners sign a checkpoint every 30 seconds. When two thirds of the mining weight of the last 30 days have signed, the checkpoint is locked. Weight is blocks mined, nothing else. The lock lands in about two minutes. The <a href="/litepaper">litepaper</a> has the rule.</p>
|
||||
<p><strong>Nothing to stake.</strong> No validator set, no delegation, no slashing, no bonded class above the miners. Finality comes from mining weight alone. Nobody holds a key that the chain depends on.</p>
|
||||
<p><strong>The EVM you already know.</strong> Solidity deploys unchanged. Standard JSON-RPC, EIP-1559 transactions, the chain id in the signature, <code>cancun</code> as the EVM version. Gas has two dimensions on Igneum, execution and proving, and the node folds the second into the price it quotes, so <code>eth_estimateGas</code> and <code>eth_gasPrice</code> work as they do on Ethereum.</p>
|
||||
</section>
|
||||
<section class="doc-section"><h2 id="networks">Networks</h2>
|
||||
<div class="tbl"><table><thead><tr><th></th><th>Devnet 3</th><th>Testnet</th><th>Mainnet</th></tr></thead><tbody><tr><td>Chain id</td><td>4463 (<code>0x116f</code>)</td><td>4462 (<code>0x116e</code>)</td><td>4461 (<code>0x116d</code>)</td></tr><tr><td>Network id</td><td><code>igneum-devnet-3</code></td><td><code>igneum-testnet-1</code></td><td>not started</td></tr><tr><td>RPC</td><td><code>https://rpc.devnet.igneum.network</code> (a node you run serves <code>http://127.0.0.1:26790</code>)</td><td><code>https://rpc.testnet.igneum.network</code> (answers; nothing mines there yet, so a transaction waits)</td><td>none</td></tr><tr><td>Coins</td><td>no value, resets without notice</td><td>no value, resets with notice</td><td>not started</td></tr><tr><td>Symbol, decimals</td><td>IGN, 18</td><td>IGN, 18</td><td>IGN, 18</td></tr></tbody></table></div>
|
||||
<p>Devnet 3 is where you build today. It is a developer network: it resets without notice and its coins have no value. Its public RPC takes the read methods, <code>eth_sendRawTransaction</code> and a wRPC websocket at <code>/ws</code>, at 20 requests a second per address. The public testnet exists, its RPC answers, and no blocks are being produced on it until it opens. Mainnet has no date. Devnet 3 answers chain id 4463 until its class v5 floor, then 4464.</p>
|
||||
</section>
|
||||
<section class="doc-section"><h2 id="endpoints-and-tools">Endpoints and tools</h2>
|
||||
<ul><li><strong>Wallet.</strong> Any Ethereum wallet. <a href="/metamask">Add Igneum to MetaMask</a> with one click, or the <a href="/wallet">Igneum wallet</a>.</li><li><strong>Faucet.</strong> <a href="/faucet">10 IGN of Devnet 3 coin</a> per address per day. No account.</li><li><strong>Explorer.</strong> <a href="/explorer">The explorer</a> shows blocks, the DAG, miners and addresses. The EVM views, transactions and contracts, are being built and link from the same page as they land.</li><li><strong>Swap.</strong> <a href="/swap">The swap</a>: test tokens on Devnet 3, every swap in a proven block.</li><li><strong>Source.</strong> <a href="https://git.igneum.network/igneum-network/igneum" rel="noopener">git.igneum.network/igneum-network/igneum</a>: the node, the miner, the site, and these pages under <code>docs/build/</code>.</li></ul>
|
||||
</section>
|
||||
<section class="doc-section"><h2 id="your-first-contract-in-five-minutes">Your first contract in five minutes</h2>
|
||||
<p>With <a href="https://getfoundry.sh" rel="noopener">Foundry</a>. Tested end to end on Devnet 3 on a build box; the full walkthrough with the expected output is <a href="https://git.igneum.network/igneum-network/igneum/src/branch/master/docs/build/first-contract.md" rel="noopener">docs/build/first-contract.md</a>.</p>
|
||||
<pre>curl -L https://foundry.paradigm.xyz | bash && foundryup
|
||||
export RPC=https://rpc.devnet.igneum.network
|
||||
cast wallet new # an address and a private key, for the devnet only</pre>
|
||||
<p>Paste the address into <a href="/faucet">the faucet</a>. Then:</p>
|
||||
<pre>export PK=0x... # the private key cast printed
|
||||
cast balance $(cast wallet address $PK) --rpc-url $RPC --ether
|
||||
forge init counter && cd counter
|
||||
forge create src/Counter.sol:Counter --rpc-url $RPC --private-key $PK --broadcast</pre>
|
||||
<p><code>forge create</code> prints <code>Deployed to: 0x...</code>. Call it:</p>
|
||||
<pre>cast send 0xDEPLOYED "increment()" --rpc-url $RPC --private-key $PK
|
||||
cast call 0xDEPLOYED "number()(uint256)" --rpc-url $RPC</pre>
|
||||
<p>The call answers <code>1</code>. Paste the transaction hash into <a href="/explorer">the explorer</a>. Hardhat, ethers and viem work the same way: chain id 4463, the RPC above.</p>
|
||||
</section>
|
||||
<section class="doc-section"><h2 id="the-rpc-the-node-serves">The RPC the node serves</h2>
|
||||
<p>Read from a Devnet 3 node, not from a spec. <code>web3_clientVersion</code> answers <code>igneumd/2.1.0/execution-layer-v3</code>. The full list, served and not served, with the probe that produced it: <a href="https://git.igneum.network/igneum-network/igneum/src/branch/master/docs/build/rpc.md" rel="noopener">docs/build/rpc.md</a>.</p>
|
||||
<ul><li><strong>Served.</strong> <code>eth_chainId</code>, <code>eth_blockNumber</code>, <code>eth_getBalance</code>, <code>eth_getTransactionCount</code>, <code>eth_getCode</code>, <code>eth_getStorageAt</code>, <code>eth_getBlockByNumber</code>, <code>eth_getBlockByHash</code>, <code>eth_getTransactionByHash</code>, <code>eth_getTransactionReceipt</code>, <code>eth_getBlockReceipts</code>, <code>eth_getLogs</code>, <code>eth_call</code>, <code>eth_estimateGas</code>, <code>eth_gasPrice</code>, <code>eth_maxPriorityFeePerGas</code>, <code>eth_feeHistory</code>, <code>eth_sendRawTransaction</code>, <code>eth_syncing</code>, <code>eth_accounts</code>, <code>net_version</code>, <code>net_peerCount</code>, <code>net_listening</code>, <code>web3_clientVersion</code>.</li><li><strong>Igneum's own.</strong> <code>igneum_getExecStatus</code>, <code>igneum_getProvingStatus</code>, <code>igneum_getShardPlan</code>, <code>igneum_getProofRecords</code>, <code>igneum_getTransactionStatus</code>, <code>igneum_estimateGas</code>, <code>igneum_getBudgets</code> and the segment and proof calls. <code>igneum_estimateGas</code> returns both gas dimensions and whether a call exceeds the proving limit.</li><li><strong>Not served.</strong> Filters and subscriptions (<code>eth_newFilter</code>, <code>eth_subscribe</code>), <code>txpool_*</code>, <code>debug_*</code>, <code>trace_*</code>, <code>eth_sendTransaction</code>, <code>eth_sign</code>, <code>eth_getProof</code>, the uncle calls. Poll <code>eth_blockNumber</code> and <code>eth_getLogs</code>. Sign on your side.</li></ul>
|
||||
</section>
|
||||
<section class="doc-section"><h2 id="verify-a-block-in-your-browser">Verify a block in your browser</h2>
|
||||
<p>The site ships a light client. Your browser fetches the latest certified checkpoint from <code>/api/checkpoint</code> and verifies the BLS aggregate signature, the voter weights and the header chain itself, in the tab. Nothing is trusted from the server but the data. The example, in twelve lines, is <a href="https://git.igneum.network/igneum-network/igneum/src/branch/master/docs/build/verify-a-block.md" rel="noopener">docs/build/verify-a-block.md</a>; the live run is <a href="/verify/test.html">verify/test.html</a>, genuine and tampered cases side by side.</p>
|
||||
<pre>import { fetchCheckpoint, verify } from 'https://igneum.network/verify/verify.js';
|
||||
const data = await fetchCheckpoint('https://igneum.network/api/checkpoint');
|
||||
const r = verify(data);
|
||||
console.log(r.verified, r.signers, 'of', r.voters, 'voters', r.ms, 'ms');</pre>
|
||||
</section>
|
||||
<section class="doc-section"><h2 id="where-to-ask">Where to ask</h2>
|
||||
<ul><li>An issue on <a href="https://git.igneum.network/igneum-network/igneum/issues" rel="noopener">the repository</a>.</li><li><a href="https://discord.gg/igneum" rel="noopener">Discord</a>, the builders channel.</li><li><a href="/grants">Grants</a> for tooling, reference apps, infrastructure and research.</li></ul>
|
||||
<p>Devnet and testnet coins have no value. Nothing on this page is an offer to sell anything.</p></section></article>
|
||||
</div>
|
||||
<p class="gen">Generated from docs/build/build.md in the repository at build time. Times are UTC.</p>
|
||||
</div></section>
|
||||
</main>
|
||||
<!-- footer:start -->
|
||||
<footer class="site-footer">
|
||||
<div class="container">
|
||||
<div class="footer-grid">
|
||||
<div class="footer-brand">
|
||||
<a href="/" class="logo" aria-label="Igneum home"><svg class="brand-mark" viewBox="0 0 1024 1024" aria-hidden="true"><rect width="1024" height="1024" rx="160" fill="#0C0C0E"></rect><g transform="translate(166.95 166.95) scale(6.901)"><polygon points="50,4 74,34 67,58 80,54 61,96 39,96 20,54 33,58 26,34" fill="#F2541B"></polygon><polygon points="50,42 59,58 50,82 41,58" fill="#0C0C0E"></polygon></g></svg><span class="word">IGNEUM</span><span class="stop">.</span></a>
|
||||
<p>Mined by GPUs. Proven by fire.</p>
|
||||
<div class="social" aria-label="Igneum elsewhere">
|
||||
<a href="https://git.igneum.network/igneum-network/spec" target="_blank" rel="noopener" aria-label="Igneum source: the spec, the vectors and the issues"><svg viewBox="0 0 24 24" width="22" height="22" fill="currentColor" aria-hidden="true"><path d="M8.6 17.6 3 12l5.6-5.6 1.4 1.4L5.8 12l4.2 4.2zm6.8 0-1.4-1.4L18.2 12 14 7.8l1.4-1.4L21 12z"></path></svg></a>
|
||||
<a href="https://discord.gg/igneum" target="_blank" rel="noopener" aria-label="The Igneum Discord"><svg viewBox="0 0 24 24" width="22" height="22" fill="currentColor" aria-hidden="true"><path d="M19.6 5.3A17 17 0 0 0 15.4 4l-.2.4a15.6 15.6 0 0 1 3.9 1.9 13.6 13.6 0 0 0-14.2 0A15.6 15.6 0 0 1 8.8 4.4L8.6 4a17 17 0 0 0-4.2 1.3C1.8 9.2 1.1 13 1.4 16.7a17.1 17.1 0 0 0 5.2 2.6l1.1-1.8a10.8 10.8 0 0 1-1.7-.8l.4-.3a12.2 12.2 0 0 0 11.2 0l.4.3-1.7.8 1.1 1.8a17 17 0 0 0 5.2-2.6c.4-4.3-.7-8-3-11.4zM8.7 14.4c-1 0-1.8-.9-1.8-2.1s.8-2.1 1.8-2.1 1.9 1 1.8 2.1c0 1.2-.8 2.1-1.8 2.1zm6.6 0c-1 0-1.8-.9-1.8-2.1s.8-2.1 1.8-2.1 1.9 1 1.8 2.1c0 1.2-.8 2.1-1.8 2.1z"></path></svg></a>
|
||||
<a data-social="reddit" href="https://www.reddit.com/user/Igneum_network/" target="_blank" rel="noopener" aria-label="Igneum on Reddit"><svg viewBox="0 0 24 24" width="22" height="22" fill="currentColor" aria-hidden="true"><path d="M22 12.1a2.2 2.2 0 0 0-3.7-1.6 10.8 10.8 0 0 0-5.8-1.8l1-4.6 3.2.7a1.5 1.5 0 1 0 .2-.9l-3.6-.8a.5.5 0 0 0-.5.4l-1.1 5.2a10.8 10.8 0 0 0-5.9 1.8A2.2 2.2 0 1 0 3.4 14a4.3 4.3 0 0 0 0 .7c0 3.4 3.9 6.1 8.6 6.1s8.6-2.7 8.6-6.1a4.3 4.3 0 0 0 0-.7 2.2 2.2 0 0 0 1.4-1.9zM7 13.6a1.5 1.5 0 1 1 1.5 1.5A1.5 1.5 0 0 1 7 13.6zm8.6 4.1a5.7 5.7 0 0 1-3.6 1.1 5.7 5.7 0 0 1-3.6-1.1.4.4 0 0 1 .6-.6 4.9 4.9 0 0 0 3 .9 4.9 4.9 0 0 0 3-.9.4.4 0 0 1 .6.6zm-.3-2.6a1.5 1.5 0 1 1 1.5-1.5 1.5 1.5 0 0 1-1.5 1.5z"></path></svg></a>
|
||||
</div>
|
||||
<div class="footer-dl" aria-label="Download Ember"><a href="/download#windows"><span class="osmark mini" data-os="windows" title="Windows"><svg viewBox="0 0 24 24" width="22" height="22" aria-hidden="true" focusable="false" fill="currentColor"><path d="M3 5.6l7.3-1v7.1H3zM11.4 4.4L21 3v8.7h-9.6zM3 12.3h7.3v7.1L3 18.4zM11.4 12.3H21V21l-9.6-1.4z"/></svg></span>Windows</a><a href="/download#mac"><span class="osmark mini" data-os="mac" title="macOS"><svg viewBox="0 0 24 24" width="22" height="22" aria-hidden="true" focusable="false" fill="currentColor"><path d="M16.4 12.6c0-2.5 2-3.6 2.1-3.7-1.2-1.7-3-1.9-3.6-2-1.5-.2-3 .9-3.8.9-.8 0-2-.9-3.3-.8-1.7 0-3.2 1-4.1 2.5-1.8 3-.5 7.6 1.3 10.1.9 1.2 1.9 2.6 3.2 2.5 1.3 0 1.8-.8 3.3-.8 1.6 0 2 .8 3.3.8 1.4 0 2.3-1.2 3.1-2.5 1-1.4 1.4-2.8 1.4-2.9 0 0-2.7-1-2.9-4.1zM13.9 5.3c.7-.8 1.2-2 1-3.2-1 0-2.2.7-2.9 1.5-.6.7-1.2 1.9-1 3 1.1.1 2.2-.5 2.9-1.3z"/></svg></span>macOS</a><a href="/download#linux"><span class="osmark mini" data-os="linux" title="Linux"><svg viewBox="0 0 24 24" width="22" height="22" aria-hidden="true" focusable="false" fill="currentColor"><path d="M12 2c-2.4 0-4 1.9-4 4.6 0 1.2.2 2 0 2.8-.6 1.4-2.1 2.9-2.6 4.9-.3 1.1-.1 2 .3 2.6-.6.4-1.3 1-1.1 1.7.3 1 2.1 1.2 3.2 1.8.7.4 1.5.6 2.1.1.6.2 1.3.3 2.1.3s1.5-.1 2.1-.3c.6.5 1.4.3 2.1-.1 1.1-.6 2.9-.8 3.2-1.8.2-.7-.5-1.3-1.1-1.7.4-.6.6-1.5.3-2.6-.5-2-2-3.5-2.6-4.9-.2-.8 0-1.6 0-2.8C16 3.9 14.4 2 12 2zm-1.4 4.2c.5 0 .8.5.8 1.2s-.3 1.2-.8 1.2-.8-.5-.8-1.2.3-1.2.8-1.2zm2.8 0c.5 0 .8.5.8 1.2s-.3 1.2-.8 1.2-.8-.5-.8-1.2.3-1.2.8-1.2zM12 9.3c.9 0 1.9.5 1.9 1s-1 1.2-1.9 1.2-1.9-.7-1.9-1.2 1-1 1.9-1zm0 3.4c2.2 0 3.6 2.6 3.6 4.4 0 1.5-1.6 2.3-3.6 2.3s-3.6-.8-3.6-2.3c0-1.8 1.4-4.4 3.6-4.4z"/></svg></span>Linux</a><a href="/download#hive"><span class="osmark mini" data-os="hive" title="HiveOS"><svg viewBox="0 0 24 24" width="22" height="22" aria-hidden="true" focusable="false" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linejoin="round" stroke-linecap="round"><path d="M12 2.6 20.2 7.3v9.4L12 21.4 3.8 16.7V7.3z"/><path d="M12 7.4 16 9.7v4.6L12 16.6 8 14.3V9.7z"/><path d="M12 7.4V2.6M16 9.7l4.2-2.4M16 14.3l4.2 2.4M12 16.6v4.8M8 14.3l-4.2 2.4M8 9.7 3.8 7.3"/></svg></span>HiveOS</a></div>
|
||||
<a href="https://git.igneum.network/igneum-network/spec" target="_blank" rel="noopener" class="text-link">Specification and test vectors<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="M6 18 18 6M6 6h12v12"/></svg></a>
|
||||
</div>
|
||||
<div class="footer-column"><h4>Run</h4><div>
|
||||
<a href="/download">Download Ember</a>
|
||||
<a href="/miner">The miner</a>
|
||||
<a href="/app">The app</a>
|
||||
<a href="/wallet">The wallet</a>
|
||||
<a href="/miners">GPU bench table</a>
|
||||
<a href="/dev-fee">The dev fee</a>
|
||||
<a href="/faucet">Devnet faucet</a>
|
||||
<a href="/metamask">Add Igneum to MetaMask</a>
|
||||
</div></div>
|
||||
<div class="footer-column"><h4>Read</h4><div>
|
||||
<a href="/litepaper">Litepaper</a>
|
||||
<a href="/evidence">Evidence</a>
|
||||
<a href="/bench">Engineering log</a>
|
||||
<a href="/ledger">Ledger: every criticism</a>
|
||||
<a href="/claims">What Igneum does not claim</a>
|
||||
<a href="/randomx">Igneum vs RandomX</a>
|
||||
<a href="/provenance">Built on the shoulders</a>
|
||||
</div></div>
|
||||
<div class="footer-column"><h4>Explore</h4><div>
|
||||
<a href="/live">Live devnet</a>
|
||||
<a href="/explorer">Explorer</a>
|
||||
<a href="/build">Build on Igneum</a>
|
||||
<a href="/swap">Swap</a>
|
||||
<a href="/grants">Grants</a>
|
||||
<a href="/journey">Journey</a>
|
||||
<a href="/download">Downloads: devnet build</a>
|
||||
<a href="https://discord.gg/igneum" target="_blank" rel="noopener">Community Discord</a>
|
||||
<a href="mailto:hello@igneum.network">hello@igneum.network</a>
|
||||
<a href="https://git.igneum.network/igneum-network/spec/issues" rel="noopener">An issue on the spec</a>
|
||||
</div></div>
|
||||
</div>
|
||||
<div class="footer-bottom">
|
||||
<p>Igneum Labs LTD · Unit IH-00-01-01-OF-01, Level 01, Innovation One, Dubai International Financial Centre. Experimental software. Nothing on this site is an offer to sell anything.<br>Report a flaw by email or by an issue on the spec. Nobody from Igneum will ask for your seed. © 2026 Igneum · not an offer to sell anything</p>
|
||||
<div class="theme-group" role="group" aria-label="Theme"><button type="button" data-theme-set="system" aria-pressed="true">System</button><button type="button" data-theme-set="light" aria-pressed="false">Light</button><button type="button" data-theme-set="dark" aria-pressed="false">Dark</button></div>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
<script>
|
||||
(function(){
|
||||
// theme control: stores light or dark under igneum-theme; system clears it and follows the OS. The head applied the value before paint.
|
||||
var bs=document.querySelectorAll('[data-theme-set]');if(!bs.length)return;
|
||||
var media=window.matchMedia('(prefers-color-scheme: light)');
|
||||
function stored(){try{var t=localStorage.getItem('igneum-theme');return t==='light'||t==='dark'?t:'system';}catch(e){return 'system';}}
|
||||
function apply(){var c=stored();document.documentElement.setAttribute('data-theme',c==='system'?(media.matches?'light':'dark'):c);bs.forEach(function(b){b.setAttribute('aria-pressed',b.getAttribute('data-theme-set')===c?'true':'false');});document.dispatchEvent(new CustomEvent('igneum-theme'));}
|
||||
bs.forEach(function(b){b.addEventListener('click',function(){var v=b.getAttribute('data-theme-set');try{if(v==='system')localStorage.removeItem('igneum-theme');else localStorage.setItem('igneum-theme',v);}catch(e){}apply();});});
|
||||
if(media.addEventListener)media.addEventListener('change',function(){if(stored()==='system')apply();});
|
||||
document.addEventListener('igneum-theme',function(){var c=stored();bs.forEach(function(b){b.setAttribute('aria-pressed',b.getAttribute('data-theme-set')===c?'true':'false');});});
|
||||
bs.forEach(function(b){b.setAttribute('aria-pressed',b.getAttribute('data-theme-set')===stored()?'true':'false');});
|
||||
// the network state word in the status bar: one read of the observer per page view
|
||||
var fs=document.getElementById('foot-state'),fd=document.getElementById('foot-dot');if(fs&&fd){fetch('/api/live?window=30',{cache:'no-store'}).then(function(r){return r.json();}).then(function(d){var on=d&&d.ok&&d.state&&!d.state.stale;fs.textContent=on?'devnet live':'devnet, observer stale';fd.className='dot '+(on?'live':'off');}).catch(function(){fs.textContent='devnet';});}
|
||||
})();
|
||||
</script>
|
||||
<!-- footer:end -->
|
||||
<script src="/ui.js" defer></script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -19,6 +19,7 @@ function inline(s) {
|
|||
s = s.replace(/`([^`]+)`/g, '<code>$1</code>');
|
||||
s = s.replace(/\*\*([^*]+)\*\*/g, '<strong>$1</strong>');
|
||||
s = s.replace(/\[([^\]]+)\]\((https?:[^)]+)\)/g, '<a href="$2" rel="noopener">$1</a>');
|
||||
s = s.replace(/\[([^\]]+)\]\((\/[^)\s]*)\)/g, '<a href="$2">$1</a>'); // a site-relative link (the builder pages, 8 October 2026)
|
||||
return s;
|
||||
}
|
||||
function md(src) {
|
||||
|
|
@ -278,6 +279,21 @@ if (existsSync(join(docs, 'bench-log.md'))) {
|
|||
built.push('journey.json (' + j.log.length + ' entries)');
|
||||
}
|
||||
|
||||
// The builder programme (8 October 2026): /build and /grants are rendered from docs/build/build.md and docs/build/grants.md
|
||||
// through the same generated-page shell as /bench, so the markdown is the source and the served page follows it. The other
|
||||
// files of docs/build/ (the walkthrough, the RPC list, the faucet, the verifier) are linked from /build on the git host.
|
||||
for (const [src, file, title, desc, heading, lead, eyebrow] of [
|
||||
['build.md', 'build.html', 'Build on Igneum: chain ids, RPC, a contract in five minutes', 'The developer entry page for Igneum: what is different, the chain ids and RPC endpoints, the wallet, the explorer, the faucet, a five-minute contract deploy and a block you verify in your browser.', 'Build on Igneum', 'Built to prove every block. A lock in minutes. Nothing to stake. The EVM you already know: Solidity deploys unchanged. Here are the chain ids, the endpoints and a contract in five minutes.', 'Developers'],
|
||||
['grants.md', 'grants.html', 'Igneum grants: tooling, reference apps, infrastructure, research', 'The Igneum grants programme: four tiers, what a grant is, how to apply with an issue on the git host, the weekly review, and the lines that stay honest about value, amounts and dates.', 'Grants', 'Paid in IGN from the dev fee fund, on delivery, on the public testnet first. Four tiers. One issue to apply. A weekly review.', 'The programme'],
|
||||
]) {
|
||||
const mdp = join(docs, 'build', src);
|
||||
if (!existsSync(mdp)) continue; // the gate builds a copy of site/ alone: the committed page stands, as for /bench
|
||||
const { html, toc } = md(readFileSync(mdp, 'utf8'));
|
||||
const path = '/' + file.replace(/\.html$/, '');
|
||||
writeFileSync(join(here, file), page(title, desc, html, toc, lead, { path, heading, crumb: heading, eyebrow, filter: false }).replace('<p class="gen">Generated from the repository at build time. Times are UTC. Machine names are model names.</p>', `<p class="gen">Generated from docs/build/${src} in the repository at build time. Times are UTC.</p>`));
|
||||
built.push(file);
|
||||
}
|
||||
|
||||
// The hand-written pages: shared head, nav (with the active link marked) and footer injected in place; the homepage also
|
||||
// gets journey.json inlined so the phases and the log render without a fetch and without a layout shift.
|
||||
const journey = JSON.parse(readFileSync(join(here, 'journey.json'), 'utf8'));
|
||||
|
|
@ -389,11 +405,14 @@ function renderEvidence(html) {
|
|||
return html;
|
||||
}
|
||||
|
||||
const PAGES = [['index.html', ''], ['download.html', 'download'], ['income.html', 'income'], ['litepaper.html', 'litepaper'], ['live.html', 'live'], ['evidence.html', 'evidence'], ['miner.html', 'miner'], ['app.html', 'app'], ['wallet.html', 'wallet'], ['ledger.html', 'ledger'], ['metamask.html', 'metamask'], ['faucet.html', 'faucet'], ['404.html', ''],
|
||||
// the DAG explorer (5 Oct 2026): /explorer, /block/<hash> and /address/<addr> (vercel.json rewrites the last two)
|
||||
['explorer.html', 'live'], ['block.html', 'live'], ['address.html', 'live'],
|
||||
const PAGES = [['index.html', ''], ['download.html', 'download'], ['income.html', 'income'], ['litepaper.html', 'litepaper'], ['live.html', 'live'], ['evidence.html', 'evidence'], ['miner.html', 'miner'], ['app.html', 'app'], ['wallet.html', 'wallet'], ['ledger.html', 'ledger'], ['metamask.html', 'metamask'], ['faucet.html', 'faucet'], ['swap.html', 'swap'], ['404.html', ''],
|
||||
// the Devnet 3 explorer (5 Oct 2026, extended 8 Oct 2026): /explorer, /block/<hash>, /address/<addr>, /tx/<hash> (vercel.json rewrites
|
||||
// the three) and /proving; the Explorer entry of the Network panel is the current one on all five
|
||||
['explorer.html', 'explorer'], ['block.html', 'explorer'], ['address.html', 'explorer'], ['tx.html', 'explorer'], ['proving.html', 'explorer'],
|
||||
// the scenes lab (6 Oct 2026): three animated views of the live feed, unlinked, noindex
|
||||
['scenes.html', '']];
|
||||
['scenes.html', ''],
|
||||
// the reference apps (8 Oct 2026): the light wallet, the payment receipt, the Sepolia state oracle
|
||||
['light.html', 'light'], ['receipt.html', 'receipt'], ['oracle.html', 'oracle']];
|
||||
for (const [file, active] of PAGES) {
|
||||
const p = join(here, file);
|
||||
if (!existsSync(p)) throw new Error(`missing page ${file}`);
|
||||
|
|
@ -434,6 +453,7 @@ for (const [file, active] of PAGES) {
|
|||
const tunedState = (r) => { const v = r.tuned || 'stock, mining'; if (/Ember Tune|core lock/.test(v)) return ['tuned', 'Tuned']; if (/no lever/.test(v)) return ['nolever', 'No lever']; return ['stock', 'Stock']; };
|
||||
const effCell = (r) => {
|
||||
if (r.mh_per_w == null) return ['not measured', -1];
|
||||
if (r.watts_class === 'v3') return ['<span class="hollow" title="class v3 watts: the fleet\'s bench pack ran the class v3 program; the class v4 watts land with the rerun; not ranked">○ ' + fmt3(r.mh_per_w) + '</span>', -1];
|
||||
if (r.watt_basis === 'chip') return ['<span class="hollow" title="chip watts (GPU plus DRAM), not wall; not ranked">○ ' + fmt3(r.mh_per_w) + '</span>', -1];
|
||||
return [(best && r === best ? '<span class="eff best">' : '<span class="eff">') + fmt3(r.mh_per_w) + '</span>', r.mh_per_w];
|
||||
};
|
||||
|
|
@ -471,7 +491,19 @@ for (const [file, active] of PAGES) {
|
|||
const table = render(cur, 'bench-current');
|
||||
const dcTable = render(dcRows, 'bench-datacentre');
|
||||
const earlierTable = render(earlier, 'bench-earlier');
|
||||
const bestLine = best ? `<p class="lede"><strong>Best desktop card:</strong> ${esc(best.card.replace(/ \(.*$/, ''))}, ${esc(fmt(best.mh_s))} MH/s, ${esc(fmt3(best.mh_per_w))} MH per wall watt tuned (measured, ${esc(best.date)}).</p>` : '';
|
||||
// the lede recomputes from the data (8 October 2026): the best desktop card by rate, then the best stock and the best tuned
|
||||
// MH per wall watt as separate claims, so a rented stock row never reads as a tuned one and a tuned lock never reads as stock
|
||||
// a row whose watts were read under another class (watts_class 'v3': the fleet's bench pack, 7 and 8 October 2026) is ranked by rate,
|
||||
// never by MH per watt; the per-watt claims come from rows whose watts are class v4
|
||||
const ranked = (list) => list.filter(r => r.mh_per_w != null && r.watt_basis !== 'chip' && !r.watts_class).sort((a, b) => b.mh_per_w - a.mh_per_w);
|
||||
const bestStock = ranked(cur.filter(r => tunedState(r)[0] === 'stock'))[0];
|
||||
const bestTuned = ranked(cur.filter(r => tunedState(r)[0] === 'tuned'))[0];
|
||||
const name = (r) => esc(r.card.replace(/ \(.*$/, ''));
|
||||
// the rented model sweep of 8 October 2026 (23 rows on 22 models, every class v5 fingerprint matched): its two page-level findings
|
||||
const sweepLine = `<p class="lede sweep">The rented model sweep of 8 October 2026 (23 rows, 22 models, every row untuned) found the rate cap-proof: a card on a host power cap gives the same MH/s as an uncapped one. Class v5 held the rate on every uncapped card and read 17 to 18 percent under it on the two power-capped hosts (an A4000 at 114 W, a GTX 1080 Ti at 130 W), so a class v5 rate needs the card's power state beside it. The sweep's watts, and the 7 October fleet rows' watts, are class v3 figures: the fleet's bench pack ran the class v3 program, and class v4 draws more for the same rate (a 5070 Ti measured 78.7 MH/s at 141 W on class v3 and 78.8 at 224 W on class v4, 8 October 2026). Those rows are ranked by rate alone; the per-watt claims above come from rows measured under class v4; the class v4 watts rerun lands on each row with its date, the v3 watts kept beside it as the shadow premium per card.</p>`;
|
||||
const bestLine = best ? `<p class="lede"><strong>Best desktop card:</strong> ${name(best)}, ${esc(fmt(best.mh_s))} MH/s (measured, ${esc(best.date)}).`
|
||||
+ (bestStock ? ` <strong>Best stock MH per wall watt:</strong> ${name(bestStock)}, ${esc(fmt3(bestStock.mh_per_w))} at ${esc(fmt(bestStock.watts))} W, untuned (${esc(bestStock.by)}, ${esc(bestStock.date)}).` : '')
|
||||
+ (bestTuned ? ` <strong>Best tuned:</strong> ${name(bestTuned)}, ${esc(fmt3(bestTuned.mh_per_w))} at ${esc(fmt(bestTuned.watts))} W (measured, ${esc(bestTuned.date)}).` : '') + '</p>' : '';
|
||||
const sortScript = `<script>
|
||||
(function(){
|
||||
document.querySelectorAll('table.bench2').forEach(function(t){
|
||||
|
|
@ -545,6 +577,7 @@ table.bench2 tr.detail .d{display:block;margin:0 0 4px}table.bench2 tr.detail b{
|
|||
sortStyle,
|
||||
'<h2 id="table">The table</h2>',
|
||||
bestLine,
|
||||
sweepLine,
|
||||
'<p>One row per card on the current class: the class v4 program (the latency-shadow block over the class v3 hash), or a class v3 row re-measured with its class v4 cost on 6 October 2026 or later. MH per wall watt uses board or wall power; a row whose watts are the chip\'s (Apple silicon: GPU plus DRAM from IOReport) says so and is not ranked on that column. Integrated GPUs are not listed.</p>',
|
||||
'<h3 class="grp" id="buy">Cards you can buy</h3>',
|
||||
table,
|
||||
|
|
|
|||
|
|
@ -86,6 +86,7 @@
|
|||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-mine" data-group="mine" aria-expanded="false" aria-controls="nav-panel-mine" aria-haspopup="true">Mine<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-network" data-group="network" aria-expanded="false" aria-controls="nav-panel-network" aria-haspopup="true">Network<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-learn" data-group="learn" data-active aria-expanded="false" aria-controls="nav-panel-learn" aria-haspopup="true">Learn<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-build" data-group="build" aria-expanded="false" aria-controls="nav-panel-build" aria-haspopup="true">Build<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
</div>
|
||||
<div class="nav-controls">
|
||||
<button class="btn icon-btn" type="button" data-theme-toggle aria-label="Switch to light theme"><svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><circle cx="12" cy="12" r="4"/><path d="M12 2v2m0 16v2M2 12h2m16 0h2M5 5l1 1m12 12 1 1M5 19l1-1M18 6l1-1"/></svg></button>
|
||||
|
|
@ -103,7 +104,6 @@
|
|||
<a href="/wallet" data-nav="wallet"><b>The wallet</b><span>Your coins. Final means final.</span></a>
|
||||
<a href="/miners" data-nav="miners"><b>GPU bench table</b><span>Measured rates, card by card.</span></a>
|
||||
<a href="/dev-fee" data-nav="dev-fee"><b>The dev fee</b><span>The optional one, in full view, off with one flag.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Testnet faucet</b><span>Test coin for an address, once a day.</span></a>
|
||||
<a href="/metamask" data-nav="metamask"><b>Add to MetaMask</b><span>Igneum as a network in your wallet.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -114,6 +114,9 @@
|
|||
<a href="/journey" data-nav="journey"><b>The journey</b><span>Six phases, four gates, the log behind them.</span></a>
|
||||
<a href="/bench" data-nav="bench"><b>Engineering log</b><span>Every measurement, with the commands that made it.</span></a>
|
||||
<a href="/evidence" data-nav="evidence"><b>Evidence</b><span>Every claim and how far it is tested.</span></a>
|
||||
<a href="/light" data-nav="light"><b>Light wallet</b><span>A balance your browser proves, trusting no node.</span></a>
|
||||
<a href="/receipt" data-nav="receipt"><b>Payment receipt</b><span>A receipt any third party re-verifies offline.</span></a>
|
||||
<a href="/oracle" data-nav="oracle"><b>State oracle on Sepolia</b><span>Devnet 3 balances read from another chain.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-panel" id="nav-panel-learn" data-group="learn" role="region" aria-labelledby="nav-btn-learn" hidden>
|
||||
|
|
@ -126,6 +129,14 @@
|
|||
<a href="/provenance" data-nav="provenance"><b>Built on the shoulders</b><span>Every borrowed part, credited.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-panel" id="nav-panel-build" data-group="build" role="region" aria-labelledby="nav-btn-build" hidden>
|
||||
<div class="panel-list">
|
||||
<a href="/build" data-nav="build"><b>Build on Igneum</b><span>Chain ids, RPC, a contract in five minutes.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Devnet faucet</b><span>10 IGN of devnet coin, once a day.</span></a>
|
||||
<a href="/swap" data-nav="swap"><b>Swap</b><span>Test tokens on Devnet 3; every swap is a proven block.</span></a>
|
||||
<a href="/grants" data-nav="grants"><b>Grants</b><span>Tooling, apps, infrastructure, research.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-sheet" id="nav-sheet" role="dialog" aria-modal="true" aria-label="Menu" hidden>
|
||||
|
|
@ -137,7 +148,6 @@
|
|||
<a href="/wallet" data-nav="wallet"><b>The wallet</b><span>Your coins. Final means final.</span></a>
|
||||
<a href="/miners" data-nav="miners"><b>GPU bench table</b><span>Measured rates, card by card.</span></a>
|
||||
<a href="/dev-fee" data-nav="dev-fee"><b>The dev fee</b><span>The optional one, in full view, off with one flag.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Testnet faucet</b><span>Test coin for an address, once a day.</span></a>
|
||||
<a href="/metamask" data-nav="metamask"><b>Add to MetaMask</b><span>Igneum as a network in your wallet.</span></a>
|
||||
</div>
|
||||
<div class="sheet-group"><div class="sheet-head">Network</div>
|
||||
|
|
@ -146,6 +156,9 @@
|
|||
<a href="/journey" data-nav="journey"><b>The journey</b><span>Six phases, four gates, the log behind them.</span></a>
|
||||
<a href="/bench" data-nav="bench"><b>Engineering log</b><span>Every measurement, with the commands that made it.</span></a>
|
||||
<a href="/evidence" data-nav="evidence"><b>Evidence</b><span>Every claim and how far it is tested.</span></a>
|
||||
<a href="/light" data-nav="light"><b>Light wallet</b><span>A balance your browser proves, trusting no node.</span></a>
|
||||
<a href="/receipt" data-nav="receipt"><b>Payment receipt</b><span>A receipt any third party re-verifies offline.</span></a>
|
||||
<a href="/oracle" data-nav="oracle"><b>State oracle on Sepolia</b><span>Devnet 3 balances read from another chain.</span></a>
|
||||
</div>
|
||||
<div class="sheet-group"><div class="sheet-head">Learn</div>
|
||||
<a href="/litepaper" data-nav="litepaper"><b>Litepaper</b><span>The design, as published.</span></a>
|
||||
|
|
@ -155,6 +168,12 @@
|
|||
<a href="/randomx" data-nav="randomx"><b>Igneum vs RandomX</b><span>What was kept and what was rebuilt for GPUs.</span></a>
|
||||
<a href="/provenance" data-nav="provenance"><b>Built on the shoulders</b><span>Every borrowed part, credited.</span></a>
|
||||
</div>
|
||||
<div class="sheet-group"><div class="sheet-head">Build</div>
|
||||
<a href="/build" data-nav="build"><b>Build on Igneum</b><span>Chain ids, RPC, a contract in five minutes.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Devnet faucet</b><span>10 IGN of devnet coin, once a day.</span></a>
|
||||
<a href="/swap" data-nav="swap"><b>Swap</b><span>Test tokens on Devnet 3; every swap is a proven block.</span></a>
|
||||
<a href="/grants" data-nav="grants"><b>Grants</b><span>Tooling, apps, infrastructure, research.</span></a>
|
||||
</div>
|
||||
<div class="sheet-foot">
|
||||
<a href="/download" class="btn primary big" data-nav="download">Download</a>
|
||||
<div class="sheet-social"><a href="https://discord.gg/igneum" target="_blank" rel="noopener">Discord</a><a href="https://git.igneum.network/igneum-network/spec" target="_blank" rel="noopener">Source</a><a href="https://www.reddit.com/user/Igneum_network/" target="_blank" rel="noopener">Reddit</a></div>
|
||||
|
|
@ -222,7 +241,7 @@
|
|||
<div class="derived"><p>Here are the limits, stated before anyone else states them.</p>
|
||||
<ul>
|
||||
<li><strong>A proof in seconds.</strong> Not at launch. Proving a full block today needs a cluster of 100 to 200 consumer GPUs, approximate, so Igneum launches with proofs within about a minute and tightens as hardware improves. Users still see their transaction land in one second.</li>
|
||||
<li><strong>A chip is impossible.</strong> No. A chip wired for one program is a bad bet, because the program moves before it ships. A programmable chip is not stopped by the moving target: everything it needs is public at genesis and every drawn parameter is firmware to it (an address permute, a rotator, an immediate table), so the defence against it is the latency-shadow work (class v4) and the price per joule, not the schedule (the Horizon lane analysis, 6 October 2026, section 5.4; ledger M32). At launch the strongest chip in our public model reaches 2.1x per joule against an RTX 5090 with a core as good as a GPU lane and 3.4x with one three times better, under class v4 from the first block: a memory-controller chip that stores the whole dataset and carries a GPU-class datapath beside its memory for the 100,000 ops per hash in the shadow, the range running from a chip core as costly per operation as a GPU lane (k = 1, modelled on the 5090’s measured watts at its knee, 7 October 2026) to a core three times better per operation (k about 0.33); the withdrawn Antminer X9’s claimed figure is a ratio against a CPU core, not a GPU lane, so it does not stand for a chip core against us; the ladder’s second rung takes that bracket to about 2.8x (modelled, 7 October 2026). Class v5 then makes the dataset the chain’s own state, so a chip that stores it or recomputes it is wrong on every item (designed, 7 October 2026). The baseline the work started from, never the launch state: without class v4 the same stored-dataset chip would reach 1.2x per chip and 5x to 9x per joule in our model (6 October 2026); the Ethash chips of this class reached 2.1x to 4.8x (Linzhi Phoenix 2020, Jasminer X4 2021, Antminer E9 2022). The strongest recompute chip we can price, holding the whole 256 MiB cache on-die, reaches under 1x per chip against an RTX 5090 (the published model, 5 October 2026: 0.92x per unit of silicon with a 3x fixed-function allowance, approximate). Sources: the chip model analysis (6 October 2026); the ASIC history’s Ethash rows; Counter ASIC 3.0 item 8 (the chip’s per-joule edge over the RTX 5090 falls from 5.6x to 2.1x on GDDR7 at k = 1 and to 3.4x at a core three times better, the 5090 at 0.2% less rate; gates G1 to G6 passed, 6 October 2026). No hash has stayed free of chips forever; Igneum does not claim to. Monero’s RandomX has held for about seven years; the one chip announced against it, Bitmain’s Antminer X9, was withdrawn in mid-May 2026 before any unit shipped, its claimed core (k about 0.33) never measured. That record says nothing about the price of a chip with the 256 MB cache on its die; that price is a cost model, not a measurement.</li>
|
||||
<li><strong>A chip is impossible.</strong> No. A chip wired for one program is a bad bet, because the program moves before it ships. A programmable chip is not stopped by the moving target: everything it needs is public at genesis and every drawn parameter is firmware to it (an address permute, a rotator, an immediate table), so the defence against it is the latency-shadow work (class v4) and the price per joule, not the schedule (the Horizon lane analysis, 6 October 2026, section 5.4; ledger M32). At launch the strongest chip in our public model reaches 2.1x per joule against an RTX 5090 with a core as good as a GPU lane and 3.4x with one three times better, under class v4 from the first block: a memory-controller chip that stores the whole dataset and carries a GPU-class datapath beside its memory for the 100,000 ops per hash in the shadow, the range running from a chip core as costly per operation as a GPU lane (k = 1, modelled on the 5090’s measured watts at its knee, 7 October 2026) to a core three times better per operation (k about 0.33); the withdrawn Antminer X9’s claimed figure is a ratio against a CPU core, not a GPU lane, so it does not stand for a chip core against us; the ladder’s second rung takes that bracket to about 2.8x (modelled, 7 October 2026). Class v5 then makes the dataset the chain’s own state, so a chip that stores it or recomputes it is wrong on every item (designed, 7 October 2026). The baseline the work started from, never the launch state: without class v4 the same stored-dataset chip would reach 1.2x per chip and 5x to 9x per joule in our model (6 October 2026); the Ethash chips of this class reached 2.1x to 4.8x (Linzhi Phoenix 2020, Jasminer X4 2021, Antminer E9 2022). The strongest recompute chip we can price, holding the whole 256 MiB cache on-die, reaches under 1x per chip against an RTX 5090 (the published model, 5 October 2026: 0.92x per unit of silicon with a 3x fixed-function allowance, approximate). Sources: the chip model analysis (6 October 2026); the ASIC history’s Ethash rows; Counter ASIC 3.0 item 8 (the chip’s per-joule edge over the RTX 5090 falls from 5.6x to 2.1x on GDDR7 at k = 1 and to 3.4x at a core three times better, the 5090 at 0.2% less rate; gates G1 to G6 passed, 6 October 2026). No hash has stayed free of chips forever; Igneum does not claim to. Monero’s RandomX has held its miners on commodity hardware for about seven years: one chip shipped against it, Bitmain’s Antminer X5 (September 2023), at 1.46x per joule over a desktop CPU; the one announced beyond it, the Antminer X9, was withdrawn in mid-May 2026 before any unit shipped, its claimed core (k about 0.33) never measured; RandomX v2 was released on 25 March 2026 with its activation pending. That record says nothing about the price of a chip with the 256 MB cache on its die; that price is a cost model, not a measurement.</li>
|
||||
<li><strong>A guaranteed income floor.</strong> No. External proving is a small market today. Igneum's miners' electricity cost in it is close to power, but the price they must charge is the subsidy they forgo, which falls as one over network hash: an edge at scale and nothing more.</li>
|
||||
<li><strong>A memory-hard prototype on every vendor.</strong> Not yet. The 256 MB cache closed the shortcut on Apple silicon (computing items runs 4.8x slower than loading them, measured 3 October 2026). The same ratio on NVIDIA and on a discrete AMD card is Open.</li>
|
||||
<li><strong>Finality in the first month.</strong> No. No checkpoint locks until the 30-day window has 30 days of history. The first month of mainnet is proof of work with a 12-hour depth, and the text above says so wherever a day count appears.</li>
|
||||
|
|
@ -262,7 +281,7 @@
|
|||
<a href="/wallet">The wallet</a>
|
||||
<a href="/miners">GPU bench table</a>
|
||||
<a href="/dev-fee">The dev fee</a>
|
||||
<a href="/faucet">Testnet faucet</a>
|
||||
<a href="/faucet">Devnet faucet</a>
|
||||
<a href="/metamask">Add Igneum to MetaMask</a>
|
||||
</div></div>
|
||||
<div class="footer-column"><h4>Read</h4><div>
|
||||
|
|
@ -277,6 +296,9 @@
|
|||
<div class="footer-column"><h4>Explore</h4><div>
|
||||
<a href="/live">Live devnet</a>
|
||||
<a href="/explorer">Explorer</a>
|
||||
<a href="/build">Build on Igneum</a>
|
||||
<a href="/swap">Swap</a>
|
||||
<a href="/grants">Grants</a>
|
||||
<a href="/journey">Journey</a>
|
||||
<a href="/download">Downloads: devnet build</a>
|
||||
<a href="https://discord.gg/igneum" target="_blank" rel="noopener">Community Discord</a>
|
||||
|
|
|
|||
|
|
@ -86,6 +86,7 @@
|
|||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-mine" data-group="mine" data-active aria-expanded="false" aria-controls="nav-panel-mine" aria-haspopup="true">Mine<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-network" data-group="network" aria-expanded="false" aria-controls="nav-panel-network" aria-haspopup="true">Network<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-learn" data-group="learn" aria-expanded="false" aria-controls="nav-panel-learn" aria-haspopup="true">Learn<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-build" data-group="build" aria-expanded="false" aria-controls="nav-panel-build" aria-haspopup="true">Build<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
</div>
|
||||
<div class="nav-controls">
|
||||
<button class="btn icon-btn" type="button" data-theme-toggle aria-label="Switch to light theme"><svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><circle cx="12" cy="12" r="4"/><path d="M12 2v2m0 16v2M2 12h2m16 0h2M5 5l1 1m12 12 1 1M5 19l1-1M18 6l1-1"/></svg></button>
|
||||
|
|
@ -103,7 +104,6 @@
|
|||
<a href="/wallet" data-nav="wallet"><b>The wallet</b><span>Your coins. Final means final.</span></a>
|
||||
<a href="/miners" data-nav="miners"><b>GPU bench table</b><span>Measured rates, card by card.</span></a>
|
||||
<a href="/dev-fee" data-nav="dev-fee" aria-current="page"><b>The dev fee</b><span>The optional one, in full view, off with one flag.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Testnet faucet</b><span>Test coin for an address, once a day.</span></a>
|
||||
<a href="/metamask" data-nav="metamask"><b>Add to MetaMask</b><span>Igneum as a network in your wallet.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -114,6 +114,9 @@
|
|||
<a href="/journey" data-nav="journey"><b>The journey</b><span>Six phases, four gates, the log behind them.</span></a>
|
||||
<a href="/bench" data-nav="bench"><b>Engineering log</b><span>Every measurement, with the commands that made it.</span></a>
|
||||
<a href="/evidence" data-nav="evidence"><b>Evidence</b><span>Every claim and how far it is tested.</span></a>
|
||||
<a href="/light" data-nav="light"><b>Light wallet</b><span>A balance your browser proves, trusting no node.</span></a>
|
||||
<a href="/receipt" data-nav="receipt"><b>Payment receipt</b><span>A receipt any third party re-verifies offline.</span></a>
|
||||
<a href="/oracle" data-nav="oracle"><b>State oracle on Sepolia</b><span>Devnet 3 balances read from another chain.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-panel" id="nav-panel-learn" data-group="learn" role="region" aria-labelledby="nav-btn-learn" hidden>
|
||||
|
|
@ -126,6 +129,14 @@
|
|||
<a href="/provenance" data-nav="provenance"><b>Built on the shoulders</b><span>Every borrowed part, credited.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-panel" id="nav-panel-build" data-group="build" role="region" aria-labelledby="nav-btn-build" hidden>
|
||||
<div class="panel-list">
|
||||
<a href="/build" data-nav="build"><b>Build on Igneum</b><span>Chain ids, RPC, a contract in five minutes.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Devnet faucet</b><span>10 IGN of devnet coin, once a day.</span></a>
|
||||
<a href="/swap" data-nav="swap"><b>Swap</b><span>Test tokens on Devnet 3; every swap is a proven block.</span></a>
|
||||
<a href="/grants" data-nav="grants"><b>Grants</b><span>Tooling, apps, infrastructure, research.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-sheet" id="nav-sheet" role="dialog" aria-modal="true" aria-label="Menu" hidden>
|
||||
|
|
@ -137,7 +148,6 @@
|
|||
<a href="/wallet" data-nav="wallet"><b>The wallet</b><span>Your coins. Final means final.</span></a>
|
||||
<a href="/miners" data-nav="miners"><b>GPU bench table</b><span>Measured rates, card by card.</span></a>
|
||||
<a href="/dev-fee" data-nav="dev-fee" aria-current="page"><b>The dev fee</b><span>The optional one, in full view, off with one flag.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Testnet faucet</b><span>Test coin for an address, once a day.</span></a>
|
||||
<a href="/metamask" data-nav="metamask"><b>Add to MetaMask</b><span>Igneum as a network in your wallet.</span></a>
|
||||
</div>
|
||||
<div class="sheet-group"><div class="sheet-head">Network</div>
|
||||
|
|
@ -146,6 +156,9 @@
|
|||
<a href="/journey" data-nav="journey"><b>The journey</b><span>Six phases, four gates, the log behind them.</span></a>
|
||||
<a href="/bench" data-nav="bench"><b>Engineering log</b><span>Every measurement, with the commands that made it.</span></a>
|
||||
<a href="/evidence" data-nav="evidence"><b>Evidence</b><span>Every claim and how far it is tested.</span></a>
|
||||
<a href="/light" data-nav="light"><b>Light wallet</b><span>A balance your browser proves, trusting no node.</span></a>
|
||||
<a href="/receipt" data-nav="receipt"><b>Payment receipt</b><span>A receipt any third party re-verifies offline.</span></a>
|
||||
<a href="/oracle" data-nav="oracle"><b>State oracle on Sepolia</b><span>Devnet 3 balances read from another chain.</span></a>
|
||||
</div>
|
||||
<div class="sheet-group"><div class="sheet-head">Learn</div>
|
||||
<a href="/litepaper" data-nav="litepaper"><b>Litepaper</b><span>The design, as published.</span></a>
|
||||
|
|
@ -155,6 +168,12 @@
|
|||
<a href="/randomx" data-nav="randomx"><b>Igneum vs RandomX</b><span>What was kept and what was rebuilt for GPUs.</span></a>
|
||||
<a href="/provenance" data-nav="provenance"><b>Built on the shoulders</b><span>Every borrowed part, credited.</span></a>
|
||||
</div>
|
||||
<div class="sheet-group"><div class="sheet-head">Build</div>
|
||||
<a href="/build" data-nav="build"><b>Build on Igneum</b><span>Chain ids, RPC, a contract in five minutes.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Devnet faucet</b><span>10 IGN of devnet coin, once a day.</span></a>
|
||||
<a href="/swap" data-nav="swap"><b>Swap</b><span>Test tokens on Devnet 3; every swap is a proven block.</span></a>
|
||||
<a href="/grants" data-nav="grants"><b>Grants</b><span>Tooling, apps, infrastructure, research.</span></a>
|
||||
</div>
|
||||
<div class="sheet-foot">
|
||||
<a href="/download" class="btn primary big" data-nav="download">Download</a>
|
||||
<div class="sheet-social"><a href="https://discord.gg/igneum" target="_blank" rel="noopener">Discord</a><a href="https://git.igneum.network/igneum-network/spec" target="_blank" rel="noopener">Source</a><a href="https://www.reddit.com/user/Igneum_network/" target="_blank" rel="noopener">Reddit</a></div>
|
||||
|
|
@ -270,7 +289,7 @@
|
|||
<a href="/wallet">The wallet</a>
|
||||
<a href="/miners">GPU bench table</a>
|
||||
<a href="/dev-fee">The dev fee</a>
|
||||
<a href="/faucet">Testnet faucet</a>
|
||||
<a href="/faucet">Devnet faucet</a>
|
||||
<a href="/metamask">Add Igneum to MetaMask</a>
|
||||
</div></div>
|
||||
<div class="footer-column"><h4>Read</h4><div>
|
||||
|
|
@ -285,6 +304,9 @@
|
|||
<div class="footer-column"><h4>Explore</h4><div>
|
||||
<a href="/live">Live devnet</a>
|
||||
<a href="/explorer">Explorer</a>
|
||||
<a href="/build">Build on Igneum</a>
|
||||
<a href="/swap">Swap</a>
|
||||
<a href="/grants">Grants</a>
|
||||
<a href="/journey">Journey</a>
|
||||
<a href="/download">Downloads: devnet build</a>
|
||||
<a href="https://discord.gg/igneum" target="_blank" rel="noopener">Community Discord</a>
|
||||
|
|
|
|||
|
|
@ -76,6 +76,7 @@
|
|||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-mine" data-group="mine" data-active aria-expanded="false" aria-controls="nav-panel-mine" aria-haspopup="true">Mine<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-network" data-group="network" aria-expanded="false" aria-controls="nav-panel-network" aria-haspopup="true">Network<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-learn" data-group="learn" aria-expanded="false" aria-controls="nav-panel-learn" aria-haspopup="true">Learn<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-build" data-group="build" aria-expanded="false" aria-controls="nav-panel-build" aria-haspopup="true">Build<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
</div>
|
||||
<div class="nav-controls">
|
||||
<button class="btn icon-btn" type="button" data-theme-toggle aria-label="Switch to light theme"><svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><circle cx="12" cy="12" r="4"/><path d="M12 2v2m0 16v2M2 12h2m16 0h2M5 5l1 1m12 12 1 1M5 19l1-1M18 6l1-1"/></svg></button>
|
||||
|
|
@ -93,7 +94,6 @@
|
|||
<a href="/wallet" data-nav="wallet"><b>The wallet</b><span>Your coins. Final means final.</span></a>
|
||||
<a href="/miners" data-nav="miners"><b>GPU bench table</b><span>Measured rates, card by card.</span></a>
|
||||
<a href="/dev-fee" data-nav="dev-fee"><b>The dev fee</b><span>The optional one, in full view, off with one flag.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Testnet faucet</b><span>Test coin for an address, once a day.</span></a>
|
||||
<a href="/metamask" data-nav="metamask"><b>Add to MetaMask</b><span>Igneum as a network in your wallet.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -104,6 +104,9 @@
|
|||
<a href="/journey" data-nav="journey"><b>The journey</b><span>Six phases, four gates, the log behind them.</span></a>
|
||||
<a href="/bench" data-nav="bench"><b>Engineering log</b><span>Every measurement, with the commands that made it.</span></a>
|
||||
<a href="/evidence" data-nav="evidence"><b>Evidence</b><span>Every claim and how far it is tested.</span></a>
|
||||
<a href="/light" data-nav="light"><b>Light wallet</b><span>A balance your browser proves, trusting no node.</span></a>
|
||||
<a href="/receipt" data-nav="receipt"><b>Payment receipt</b><span>A receipt any third party re-verifies offline.</span></a>
|
||||
<a href="/oracle" data-nav="oracle"><b>State oracle on Sepolia</b><span>Devnet 3 balances read from another chain.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-panel" id="nav-panel-learn" data-group="learn" role="region" aria-labelledby="nav-btn-learn" hidden>
|
||||
|
|
@ -116,6 +119,14 @@
|
|||
<a href="/provenance" data-nav="provenance"><b>Built on the shoulders</b><span>Every borrowed part, credited.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-panel" id="nav-panel-build" data-group="build" role="region" aria-labelledby="nav-btn-build" hidden>
|
||||
<div class="panel-list">
|
||||
<a href="/build" data-nav="build"><b>Build on Igneum</b><span>Chain ids, RPC, a contract in five minutes.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Devnet faucet</b><span>10 IGN of devnet coin, once a day.</span></a>
|
||||
<a href="/swap" data-nav="swap"><b>Swap</b><span>Test tokens on Devnet 3; every swap is a proven block.</span></a>
|
||||
<a href="/grants" data-nav="grants"><b>Grants</b><span>Tooling, apps, infrastructure, research.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-sheet" id="nav-sheet" role="dialog" aria-modal="true" aria-label="Menu" hidden>
|
||||
|
|
@ -127,7 +138,6 @@
|
|||
<a href="/wallet" data-nav="wallet"><b>The wallet</b><span>Your coins. Final means final.</span></a>
|
||||
<a href="/miners" data-nav="miners"><b>GPU bench table</b><span>Measured rates, card by card.</span></a>
|
||||
<a href="/dev-fee" data-nav="dev-fee"><b>The dev fee</b><span>The optional one, in full view, off with one flag.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Testnet faucet</b><span>Test coin for an address, once a day.</span></a>
|
||||
<a href="/metamask" data-nav="metamask"><b>Add to MetaMask</b><span>Igneum as a network in your wallet.</span></a>
|
||||
</div>
|
||||
<div class="sheet-group"><div class="sheet-head">Network</div>
|
||||
|
|
@ -136,6 +146,9 @@
|
|||
<a href="/journey" data-nav="journey"><b>The journey</b><span>Six phases, four gates, the log behind them.</span></a>
|
||||
<a href="/bench" data-nav="bench"><b>Engineering log</b><span>Every measurement, with the commands that made it.</span></a>
|
||||
<a href="/evidence" data-nav="evidence"><b>Evidence</b><span>Every claim and how far it is tested.</span></a>
|
||||
<a href="/light" data-nav="light"><b>Light wallet</b><span>A balance your browser proves, trusting no node.</span></a>
|
||||
<a href="/receipt" data-nav="receipt"><b>Payment receipt</b><span>A receipt any third party re-verifies offline.</span></a>
|
||||
<a href="/oracle" data-nav="oracle"><b>State oracle on Sepolia</b><span>Devnet 3 balances read from another chain.</span></a>
|
||||
</div>
|
||||
<div class="sheet-group"><div class="sheet-head">Learn</div>
|
||||
<a href="/litepaper" data-nav="litepaper"><b>Litepaper</b><span>The design, as published.</span></a>
|
||||
|
|
@ -145,6 +158,12 @@
|
|||
<a href="/randomx" data-nav="randomx"><b>Igneum vs RandomX</b><span>What was kept and what was rebuilt for GPUs.</span></a>
|
||||
<a href="/provenance" data-nav="provenance"><b>Built on the shoulders</b><span>Every borrowed part, credited.</span></a>
|
||||
</div>
|
||||
<div class="sheet-group"><div class="sheet-head">Build</div>
|
||||
<a href="/build" data-nav="build"><b>Build on Igneum</b><span>Chain ids, RPC, a contract in five minutes.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Devnet faucet</b><span>10 IGN of devnet coin, once a day.</span></a>
|
||||
<a href="/swap" data-nav="swap"><b>Swap</b><span>Test tokens on Devnet 3; every swap is a proven block.</span></a>
|
||||
<a href="/grants" data-nav="grants"><b>Grants</b><span>Tooling, apps, infrastructure, research.</span></a>
|
||||
</div>
|
||||
<div class="sheet-foot">
|
||||
<a href="/download" class="btn primary big" data-nav="download">Download</a>
|
||||
<div class="sheet-social"><a href="https://discord.gg/igneum" target="_blank" rel="noopener">Discord</a><a href="https://git.igneum.network/igneum-network/spec" target="_blank" rel="noopener">Source</a><a href="https://www.reddit.com/user/Igneum_network/" target="_blank" rel="noopener">Reddit</a></div>
|
||||
|
|
@ -235,16 +254,16 @@
|
|||
<div><h3>Ember for Linux</h3><div class="sub">one tarball, the miner and the node inside</div></div>
|
||||
<div class="body">
|
||||
<p>Unpack it, run <code>igneum</code> with your payout address. The same signed manifest as the desktop apps. NVIDIA through CUDA, AMD through OpenCL.</p>
|
||||
<a data-dl="miner-hive" href="https://dl.igneum.network/public/igneum-miner-hive.tar.gz" class="btn primary"><span class="osmark bare" data-os="linux" title="Linux"><svg viewBox="0 0 24 24" width="22" height="22" aria-hidden="true" focusable="false" fill="currentColor"><path d="M12 2c-2.4 0-4 1.9-4 4.6 0 1.2.2 2 0 2.8-.6 1.4-2.1 2.9-2.6 4.9-.3 1.1-.1 2 .3 2.6-.6.4-1.3 1-1.1 1.7.3 1 2.1 1.2 3.2 1.8.7.4 1.5.6 2.1.1.6.2 1.3.3 2.1.3s1.5-.1 2.1-.3c.6.5 1.4.3 2.1-.1 1.1-.6 2.9-.8 3.2-1.8.2-.7-.5-1.3-1.1-1.7.4-.6.6-1.5.3-2.6-.5-2-2-3.5-2.6-4.9-.2-.8 0-1.6 0-2.8C16 3.9 14.4 2 12 2zm-1.4 4.2c.5 0 .8.5.8 1.2s-.3 1.2-.8 1.2-.8-.5-.8-1.2.3-1.2.8-1.2zm2.8 0c.5 0 .8.5.8 1.2s-.3 1.2-.8 1.2-.8-.5-.8-1.2.3-1.2.8-1.2zM12 9.3c.9 0 1.9.5 1.9 1s-1 1.2-1.9 1.2-1.9-.7-1.9-1.2 1-1 1.9-1zm0 3.4c2.2 0 3.6 2.6 3.6 4.4 0 1.5-1.6 2.3-3.6 2.3s-3.6-.8-3.6-2.3c0-1.8 1.4-4.4 3.6-4.4z"/></svg></span>Download the tarball <span class="meta" data-dl-meta="miner-hive">v0.3.23 · 28.8 MB</span></a>
|
||||
<div class="sha"><b>sha256</b> <span data-dl-sha="miner-hive">0d716ed92560b6b2eccb63ca1bd7a4d9eb64c9b334e8370e1263f0344cee294e</span></div>
|
||||
<a data-dl="miner-hive" href="https://dl.igneum.network/public/igneum-miner-hive.tar.gz" class="btn primary"><span class="osmark bare" data-os="linux" title="Linux"><svg viewBox="0 0 24 24" width="22" height="22" aria-hidden="true" focusable="false" fill="currentColor"><path d="M12 2c-2.4 0-4 1.9-4 4.6 0 1.2.2 2 0 2.8-.6 1.4-2.1 2.9-2.6 4.9-.3 1.1-.1 2 .3 2.6-.6.4-1.3 1-1.1 1.7.3 1 2.1 1.2 3.2 1.8.7.4 1.5.6 2.1.1.6.2 1.3.3 2.1.3s1.5-.1 2.1-.3c.6.5 1.4.3 2.1-.1 1.1-.6 2.9-.8 3.2-1.8.2-.7-.5-1.3-1.1-1.7.4-.6.6-1.5.3-2.6-.5-2-2-3.5-2.6-4.9-.2-.8 0-1.6 0-2.8C16 3.9 14.4 2 12 2zm-1.4 4.2c.5 0 .8.5.8 1.2s-.3 1.2-.8 1.2-.8-.5-.8-1.2.3-1.2.8-1.2zm2.8 0c.5 0 .8.5.8 1.2s-.3 1.2-.8 1.2-.8-.5-.8-1.2.3-1.2.8-1.2zM12 9.3c.9 0 1.9.5 1.9 1s-1 1.2-1.9 1.2-1.9-.7-1.9-1.2 1-1 1.9-1zm0 3.4c2.2 0 3.6 2.6 3.6 4.4 0 1.5-1.6 2.3-3.6 2.3s-3.6-.8-3.6-2.3c0-1.8 1.4-4.4 3.6-4.4z"/></svg></span>Download the tarball <span class="meta" data-dl-meta="miner-hive">v0.3.22 · 28.8 MB</span></a>
|
||||
<div class="sha"><b>sha256</b> <span data-dl-sha="miner-hive">8ad6dcef9edc57dcd33e8d5a97cbef5cdda0e384a6e56d3f62f8903029c4c764</span></div>
|
||||
</div>
|
||||
</article>
|
||||
<article class="dl-card" id="hive">
|
||||
<span class="osmark" data-os="hive" title="HiveOS"><svg viewBox="0 0 24 24" width="22" height="22" aria-hidden="true" focusable="false" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linejoin="round" stroke-linecap="round"><path d="M12 2.6 20.2 7.3v9.4L12 21.4 3.8 16.7V7.3z"/><path d="M12 7.4 16 9.7v4.6L12 16.6 8 14.3V9.7z"/><path d="M12 7.4V2.6M16 9.7l4.2-2.4M16 14.3l4.2 2.4M12 16.6v4.8M8 14.3l-4.2 2.4M8 9.7 3.8 7.3"/></svg></span>
|
||||
<div><h3>Ember on HiveOS</h3><div class="sub">for the rig people, the same tarball</div></div>
|
||||
<div class="body">
|
||||
<div class="hive-sheet"><b>Flight Sheet.</b> Miner: <b>Custom</b>. Installation URL: <code data-dl-url="miner-hive">https://dl.igneum.network/dl/public/igneum-hive-0.3.23.tar.gz</code>. Miner name <code>igneum</code>, wallet and worker <code>0x<your 40-hex payout address>.%WORKER_NAME%</code>. Hive itself is untested on our side: tell us what breaks.</div>
|
||||
<a data-dl="miner-hive" href="https://dl.igneum.network/public/igneum-miner-hive.tar.gz" class="btn"><span class="osmark bare" data-os="hive" title="HiveOS"><svg viewBox="0 0 24 24" width="22" height="22" aria-hidden="true" focusable="false" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linejoin="round" stroke-linecap="round"><path d="M12 2.6 20.2 7.3v9.4L12 21.4 3.8 16.7V7.3z"/><path d="M12 7.4 16 9.7v4.6L12 16.6 8 14.3V9.7z"/><path d="M12 7.4V2.6M16 9.7l4.2-2.4M16 14.3l4.2 2.4M12 16.6v4.8M8 14.3l-4.2 2.4M8 9.7 3.8 7.3"/></svg></span>Download the tarball <span class="meta" data-dl-meta="miner-hive">v0.3.23 · 28.8 MB</span></a>
|
||||
<div class="hive-sheet"><b>Flight Sheet.</b> Miner: <b>Custom</b>. Installation URL: <code data-dl-url="miner-hive">https://dl.igneum.network/dl/public/igneum-hive-0.3.22.tar.gz</code>. Miner name <code>igneum</code>, wallet and worker <code>0x<your 40-hex payout address>.%WORKER_NAME%</code>. Hive itself is untested on our side: tell us what breaks.</div>
|
||||
<a data-dl="miner-hive" href="https://dl.igneum.network/public/igneum-miner-hive.tar.gz" class="btn"><span class="osmark bare" data-os="hive" title="HiveOS"><svg viewBox="0 0 24 24" width="22" height="22" aria-hidden="true" focusable="false" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linejoin="round" stroke-linecap="round"><path d="M12 2.6 20.2 7.3v9.4L12 21.4 3.8 16.7V7.3z"/><path d="M12 7.4 16 9.7v4.6L12 16.6 8 14.3V9.7z"/><path d="M12 7.4V2.6M16 9.7l4.2-2.4M16 14.3l4.2 2.4M12 16.6v4.8M8 14.3l-4.2 2.4M8 9.7 3.8 7.3"/></svg></span>Download the tarball <span class="meta" data-dl-meta="miner-hive">v0.3.22 · 28.8 MB</span></a>
|
||||
</div>
|
||||
</article>
|
||||
</div>
|
||||
|
|
@ -308,7 +327,7 @@
|
|||
<a href="/wallet">The wallet</a>
|
||||
<a href="/miners">GPU bench table</a>
|
||||
<a href="/dev-fee">The dev fee</a>
|
||||
<a href="/faucet">Testnet faucet</a>
|
||||
<a href="/faucet">Devnet faucet</a>
|
||||
<a href="/metamask">Add Igneum to MetaMask</a>
|
||||
</div></div>
|
||||
<div class="footer-column"><h4>Read</h4><div>
|
||||
|
|
@ -323,6 +342,9 @@
|
|||
<div class="footer-column"><h4>Explore</h4><div>
|
||||
<a href="/live">Live devnet</a>
|
||||
<a href="/explorer">Explorer</a>
|
||||
<a href="/build">Build on Igneum</a>
|
||||
<a href="/swap">Swap</a>
|
||||
<a href="/grants">Grants</a>
|
||||
<a href="/journey">Journey</a>
|
||||
<a href="/download">Downloads: devnet build</a>
|
||||
<a href="https://discord.gg/igneum" target="_blank" rel="noopener">Community Discord</a>
|
||||
|
|
|
|||
|
|
@ -97,6 +97,7 @@ td.mono{font-family:var(--f-mono);font-size:12.5px;min-width:180px}td.iv{color:v
|
|||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-mine" data-group="mine" aria-expanded="false" aria-controls="nav-panel-mine" aria-haspopup="true">Mine<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-network" data-group="network" data-active aria-expanded="false" aria-controls="nav-panel-network" aria-haspopup="true">Network<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-learn" data-group="learn" aria-expanded="false" aria-controls="nav-panel-learn" aria-haspopup="true">Learn<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-build" data-group="build" aria-expanded="false" aria-controls="nav-panel-build" aria-haspopup="true">Build<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
</div>
|
||||
<div class="nav-controls">
|
||||
<button class="btn icon-btn" type="button" data-theme-toggle aria-label="Switch to light theme"><svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><circle cx="12" cy="12" r="4"/><path d="M12 2v2m0 16v2M2 12h2m16 0h2M5 5l1 1m12 12 1 1M5 19l1-1M18 6l1-1"/></svg></button>
|
||||
|
|
@ -114,7 +115,6 @@ td.mono{font-family:var(--f-mono);font-size:12.5px;min-width:180px}td.iv{color:v
|
|||
<a href="/wallet" data-nav="wallet"><b>The wallet</b><span>Your coins. Final means final.</span></a>
|
||||
<a href="/miners" data-nav="miners"><b>GPU bench table</b><span>Measured rates, card by card.</span></a>
|
||||
<a href="/dev-fee" data-nav="dev-fee"><b>The dev fee</b><span>The optional one, in full view, off with one flag.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Testnet faucet</b><span>Test coin for an address, once a day.</span></a>
|
||||
<a href="/metamask" data-nav="metamask"><b>Add to MetaMask</b><span>Igneum as a network in your wallet.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -125,6 +125,9 @@ td.mono{font-family:var(--f-mono);font-size:12.5px;min-width:180px}td.iv{color:v
|
|||
<a href="/journey" data-nav="journey"><b>The journey</b><span>Six phases, four gates, the log behind them.</span></a>
|
||||
<a href="/bench" data-nav="bench"><b>Engineering log</b><span>Every measurement, with the commands that made it.</span></a>
|
||||
<a href="/evidence" data-nav="evidence" aria-current="page"><b>Evidence</b><span>Every claim and how far it is tested.</span></a>
|
||||
<a href="/light" data-nav="light"><b>Light wallet</b><span>A balance your browser proves, trusting no node.</span></a>
|
||||
<a href="/receipt" data-nav="receipt"><b>Payment receipt</b><span>A receipt any third party re-verifies offline.</span></a>
|
||||
<a href="/oracle" data-nav="oracle"><b>State oracle on Sepolia</b><span>Devnet 3 balances read from another chain.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-panel" id="nav-panel-learn" data-group="learn" role="region" aria-labelledby="nav-btn-learn" hidden>
|
||||
|
|
@ -137,6 +140,14 @@ td.mono{font-family:var(--f-mono);font-size:12.5px;min-width:180px}td.iv{color:v
|
|||
<a href="/provenance" data-nav="provenance"><b>Built on the shoulders</b><span>Every borrowed part, credited.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-panel" id="nav-panel-build" data-group="build" role="region" aria-labelledby="nav-btn-build" hidden>
|
||||
<div class="panel-list">
|
||||
<a href="/build" data-nav="build"><b>Build on Igneum</b><span>Chain ids, RPC, a contract in five minutes.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Devnet faucet</b><span>10 IGN of devnet coin, once a day.</span></a>
|
||||
<a href="/swap" data-nav="swap"><b>Swap</b><span>Test tokens on Devnet 3; every swap is a proven block.</span></a>
|
||||
<a href="/grants" data-nav="grants"><b>Grants</b><span>Tooling, apps, infrastructure, research.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-sheet" id="nav-sheet" role="dialog" aria-modal="true" aria-label="Menu" hidden>
|
||||
|
|
@ -148,7 +159,6 @@ td.mono{font-family:var(--f-mono);font-size:12.5px;min-width:180px}td.iv{color:v
|
|||
<a href="/wallet" data-nav="wallet"><b>The wallet</b><span>Your coins. Final means final.</span></a>
|
||||
<a href="/miners" data-nav="miners"><b>GPU bench table</b><span>Measured rates, card by card.</span></a>
|
||||
<a href="/dev-fee" data-nav="dev-fee"><b>The dev fee</b><span>The optional one, in full view, off with one flag.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Testnet faucet</b><span>Test coin for an address, once a day.</span></a>
|
||||
<a href="/metamask" data-nav="metamask"><b>Add to MetaMask</b><span>Igneum as a network in your wallet.</span></a>
|
||||
</div>
|
||||
<div class="sheet-group"><div class="sheet-head">Network</div>
|
||||
|
|
@ -157,6 +167,9 @@ td.mono{font-family:var(--f-mono);font-size:12.5px;min-width:180px}td.iv{color:v
|
|||
<a href="/journey" data-nav="journey"><b>The journey</b><span>Six phases, four gates, the log behind them.</span></a>
|
||||
<a href="/bench" data-nav="bench"><b>Engineering log</b><span>Every measurement, with the commands that made it.</span></a>
|
||||
<a href="/evidence" data-nav="evidence" aria-current="page"><b>Evidence</b><span>Every claim and how far it is tested.</span></a>
|
||||
<a href="/light" data-nav="light"><b>Light wallet</b><span>A balance your browser proves, trusting no node.</span></a>
|
||||
<a href="/receipt" data-nav="receipt"><b>Payment receipt</b><span>A receipt any third party re-verifies offline.</span></a>
|
||||
<a href="/oracle" data-nav="oracle"><b>State oracle on Sepolia</b><span>Devnet 3 balances read from another chain.</span></a>
|
||||
</div>
|
||||
<div class="sheet-group"><div class="sheet-head">Learn</div>
|
||||
<a href="/litepaper" data-nav="litepaper"><b>Litepaper</b><span>The design, as published.</span></a>
|
||||
|
|
@ -166,6 +179,12 @@ td.mono{font-family:var(--f-mono);font-size:12.5px;min-width:180px}td.iv{color:v
|
|||
<a href="/randomx" data-nav="randomx"><b>Igneum vs RandomX</b><span>What was kept and what was rebuilt for GPUs.</span></a>
|
||||
<a href="/provenance" data-nav="provenance"><b>Built on the shoulders</b><span>Every borrowed part, credited.</span></a>
|
||||
</div>
|
||||
<div class="sheet-group"><div class="sheet-head">Build</div>
|
||||
<a href="/build" data-nav="build"><b>Build on Igneum</b><span>Chain ids, RPC, a contract in five minutes.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Devnet faucet</b><span>10 IGN of devnet coin, once a day.</span></a>
|
||||
<a href="/swap" data-nav="swap"><b>Swap</b><span>Test tokens on Devnet 3; every swap is a proven block.</span></a>
|
||||
<a href="/grants" data-nav="grants"><b>Grants</b><span>Tooling, apps, infrastructure, research.</span></a>
|
||||
</div>
|
||||
<div class="sheet-foot">
|
||||
<a href="/download" class="btn primary big" data-nav="download">Download</a>
|
||||
<div class="sheet-social"><a href="https://discord.gg/igneum" target="_blank" rel="noopener">Discord</a><a href="https://git.igneum.network/igneum-network/spec" target="_blank" rel="noopener">Source</a><a href="https://www.reddit.com/user/Igneum_network/" target="_blank" rel="noopener">Reddit</a></div>
|
||||
|
|
@ -254,8 +273,8 @@ td.mono{font-family:var(--f-mono);font-size:12.5px;min-width:180px}td.iv{color:v
|
|||
<tr data-status="tested by the team"><td class="n">14</td><td class="claim">Ethereum bytecode runs unchanged, with the documented differences of spec 7.1<div class="where">Homepage Build card; litepaper Building</div></td><td><span class="st st-2">tested by the team</span></td><td class="mono">as row 13; fixes <code>F-exec-A</code>, <code>F-exec-B</code> (spec 7.5)</td><td><code>tools/evm-smoke/smoke.mjs</code>: deploy via viem, <code>increment</code>, <code>hashLoop</code>, <code>eth_estimateGas</code>, <code>eth_getLogs</code>; <code>tools/exec-attacks</code> scenarios 1 and 3; bench-log "execution layer attack fixes"</td><td>Deployment, calls, reverts, logs and gas estimates behave as viem expects; chain id 4463; the prototype pgas table gives 0.0095 to 0.028 pgas per gas, below the design's band before calibration, 3 October 2026. 4 October 2026: a transaction that would cross the block's proving budget is refused by the mempool and, if forced in, aborted and charged with its nonce advanced (25 of 25 checks; 30 of 30 malformed cases). Apple M5 Max. The <code>Prover</code> precompile, proof records and the shard planner are not in the node</td><td class="iv">none yet</td></tr>
|
||||
<tr data-status="implemented"><td class="n">15</td><td class="claim">Every block is proven, with the proof landing within about a minute at launch<div class="where">Homepage stats ("~60 s to a proof"); litepaper Proving; roadmap phase 3 gate</div></td><td><span class="st st-1">implemented</span></td><td class="mono">repo <code>d7e1f89</code> (GPU proof), <code>e01a3cc</code>, <code>292e800</code>, <code>eedd136</code> (<code>proving/igneum-prove</code>: shard cutter, MPT witnesses, shard and aggregator guests); SP1 6.8.1; spec 7.2, 7.6</td><td><code>proving/windows-wsl2</code> (SETUP-PROVER, PROVE-BLOCK) on the RTX 5090; <code>igneum-prove-host --mode block</code> on <code>proving/fixtures/</code>; bench-log "proving v0 on the RTX 5090" and "proving: devnet v4 shards"</td><td>First GPU proof of an Igneum block, 4 October 2026, RTX 5090 (WSL2, SP1 cuda, mining paused): fixture <code>block-78-increment</code> (2 transactions), core proof 1.4 s (7.3 MB, verify 0.221 s), compressed proof 2.7 s (1.27 MB, verify 0.038 s), post-state and receipts roots identical to the node's; 15.7x and 20.6x faster than a loaded M5 Max CPU. The same day on that CPU (load 38 to 47): a three-shard block proved shard by shard and aggregated by recursion, 19 min (1,139 s) end to end, 245 to 337 s per compressed shard proof, every proof verified. What is not there: no proof is produced, carried or checked on the chain (the devnet prover is a stub that signs claims), the proving pool pays nobody (row 21), the block proven is far below one shard, and the 60-second figure remains a design target; the pass mark is the standard in <code>docs/benchmarks/proving-e2e.md</code>. Second RTX 5090 run, 4 October 2026 evening (job run-20261004-173115): a full shard at the provisional S_p (6.75 M pgas, 60.8 M cycles) executed in 1.63 s, core proof 8.3 s (18.1 MB), compressed proof 10.9 s (1.27 MB, verify 0.040 s); a two-shard block (13.5 M pgas) proved shard by shard (11.7 s and 10.0 s) and aggregated in 2.2 s, 24 s of GPU stages end to end, every proof verified, six tampered witnesses rejected. The two host defects (an abort after the upload, an idle wait that turned out to be an unbuffered 18 MB proof save through the WSL2 file bridge, 24 minutes) are fixed (ledger P20) 5 October 2026, live devnet with real transactions (bench-log "real transactions, the first non-empty shard proven and paid"): block 72704 shard 0, 29 transfers, 5,800 pgas, proven on the RTX 5090 Windows rig in 34 s, verified on the Apple M5 Max in 0.297 s and paid 1.7623 IGN, 53 s after the chain block executed; of about 1,400 blocks in the 20-minute window 36 were proven (the one prover takes the newest shard assigned to it), so "every block" is not yet true; a second content shard (72803, all copies skipped) failed the native-execution veto on the exporter's block structure, fixed with fixtures the same day, the node side pending the 0.3.9 rollout 5 October 2026, evening (bench-log "proving v1"): the aggregated segment record, the chain rule and the unproven rule are implemented behind <code>proving_v1_activation_daa</code> (branch proving-v1, not on the devnet before 0.3.11); on the RTX 5090 a chain of 8 consecutive live blocks proved and aggregated by recursion in 135.6 s with the miner on the card (17 s a block, one proof of 1,272,909 bytes attesting all 8, verified in 0.04 s); the 3-node fast-time harness paid a segment record 1.0 s after submission and refused a late one after its deadline (21 checks); the devnet itself, with one prover, carried proofs for 2.4% of blocks over 30 minutes at a block-to-record latency p50 44 s, p99 52 s. The "within about a minute" holds per proven block; "every block" needs 18 mining 5090s or 6 proving-only cards at empty blocks on the measured rates, and the mandatory rule stays off until the share is one</td><td class="iv">none yet</td></tr>
|
||||
<tr data-status="designed"><td class="n">16</td><td class="claim">A 12 GB card proves one shard in about 20 s (WITHDRAWN 5 October 2026: a 24 GB card proves a full shard at the adopted size in 4.3 s; 32 GB mines and proves)<div class="where">Litepaper Proving ("The proving budget"); roadmap gate 2</div></td><td><span class="st st-0">designed</span></td><td class="mono">spec 5.1 (Target), 7.6 (<code>S_p</code> provisional, 7,500,000 pgas = <code>B_p</code> / 4)</td><td><code>PROVE-SHARD.bat</code> on the RTX 5090 (pending); the end-to-end standard in <code>docs/benchmarks/proving-e2e.md</code>; bench-log "proving: devnet v4 shards"</td><td>Measured on a 32 GB card, not yet on a 12 GB card. A shard at the provisional <code>S_p</code> is 60.8 M SP1 cycles on the prototype pgas table (9 cycles per pgas, 44 per EVM gas; the modexp entry about 100x its SP1 cost); on an RTX 5090 (4 October 2026 evening, job run-20261004-173115) it executed in 1.63 s and its compressed proof took 10.9 s, verified in 0.040 s, so the 32 GB card is inside the 20 s target with margin. Whether a 12 GB card proves it at all, and in what time, is the next measurement (an RTX 3060 and an RTX 5060 Ti 16 GB are on order). A per-shard time can be met by shrinking the shard, so the project does not use it as a pass mark 5 October 2026, evening (bench-log "proving v1", the S_p curve): measured on the RTX 5090 with SP1 6.8.1's GPU prover, the card to itself, 1-s nvidia-smi samples: an empty shard 13,874 MiB and 2.2 s; a full shard at the ADOPTED v1 budget (30,000 pgas, 4.7 M cycles) 20,434 MiB and 4.3 s; the full prototype shard (6.75 M pgas, 60 M cycles) 28,307 MiB and 10.8 s; beside the miner 15,670 and 30,039 MiB. No environment knob of SP1 moves the 13.9 GB floor and the GPU server has no options of its own, so on this build a 12 GB card proves nothing, a 16 GB card only empty shards, a 24 GB card the adopted full shard alone and beside the miner (22,210 MiB and 13.2 s, measured on the 32 GB card: the 5090's allocation pattern, not yet a run on a 24 GB card) and a 32 GB card the prototype shard beside the miner with 2.5 GB spare. The litepaper line now says so; the 12 GB gate returns when a prover build with a smaller floor is measured on a 12 GB card</td><td class="iv">none yet</td></tr>
|
||||
<tr data-status="designed"><td class="n">17</td><td class="claim">The chip resistance claim: at launch the strongest chip in the public model reaches 2.1x (a core as good as a GPU lane, k = 1) to 3.4x (a core three times better, k about 0.33) per joule against an RTX 5090 under class v4, live from genesis on the testnet and the mainnet; the ladder's second rung brings it to about 2.8x; class v5 makes the dataset the chain's state so a stateless or stale chip is wrong on every item; the hot-set cache is bounded at 1.067x at the ceiling and the weak-day FPGA at 12 percent on 15 days a century, both routed to the next class; datacentre silicon does not change the question; a stored-dataset chip pays for itself only at about USD 100 M of market cap in two years; without class v4 the same chip would reach 5x to 9x (the class v3 baseline, the devnet's starting state, never the launch state)<div class="where">the home page's chip line, the litepaper's chip section (/litepaper#chip-model), the miner page's line</div></td><td><span class="st st-0">tested by the team (every card, the verifier, the two attack-pass bounds, the H100), the chip itself modelled, class v5 and the ladder designed, the X9 figure claimed against a CPU core and never measured</span></td><td class="mono"><code>docs/analysis/chip-model-v3.md</code> 5 and 6; <code>docs/analysis/latency-shadow-2026-10-06.md</code>; <code>docs/plans/counter-asic-3-status.md</code>; <code>docs/analysis/attack-pass/f8-uniform.md</code>, <code>f4-weakday.md</code>, <code>docs/analysis/ca3-v4-uniform.md</code>; <code>docs/design/class-v5-stored-state.md</code>; the H100 and market-cap rows of 7 October; <code>docs/plans/cryptanalysis/in-house-pass.md</code> (the internal adversarial pass)</td><td>the chip model's arithmetic in its file; the card rows by the benchmark package; the attack-pass harnesses <code>tools/attack/f8-uniform</code> and the F4 census; the verifier by <code>igneum-pow bench</code></td><td>136 MH/s at 350 W (5090, bench) and 290 W (app); the class v4 efficiency passes (bench log "7 to 8 October 2026, the class v4 efficiency passes: the core clock lock on the RTX 5090 and the RTX 5080", measured): the 5090 at 136.84 MH/s and 475.5 W unlocked, 134.98 at 316.3 W at a 1,400 MHz core lock, the best points class v4 at 1,200 MHz (133.80 MH/s, 305.1 W, 0.439 MH/W) and class v3 at 1,300 MHz (134.62, 223.3 W, 0.603), the premium 145 W unlocked and 82 W at the best points, the knee 1,300 MHz; the RTX 5080 (8 October 2026, the dock card of the three-card Windows rig) at 71.41 MH/s and 253.1 W unlocked under class v4 against 71.28 at 169.7 W under class v3, the best points class v4 at 1,100 MHz (71.20 MH/s, 146.6 W, 0.486 MH/W) and class v3 at 1,000 MHz (71.11, 103.7 W, 0.686), the premium 83.4 W unlocked and 41 W at the best points, the knee between 1,000 and 900 MHz; per tier: a 5080 owner on class v4 locked near 1,100 MHz pays 147 W instead of 253 for 0.3 percent less rate, MH per watt up 72 percent, the lever Ember Tune's core-clock knob in 0.3.24; 27 MH/s at 21 W (M5 Max); 249 MH/s (H100 SXM) at 98 percent of its read ceiling, 1.78x hash, 1.15x MH/W, a third per rented dollar; 2.33 ms per warp; 2.1x, 3.4x, 2.8x at launch; the shadow's premium on a 5090 81.8 W at its knee (class v4 at the 1,200 MHz lock 133.80 MH/s at 305.1 W; class v3 at 1,300 MHz 134.62 at 223.3 W; 7 October 2026); 1.067x at the ceiling; 12 percent on 15 days a century; 10.85 ms at rung 3; USD 100 M; 5.1x to 9.2x the class v3 baseline; 6 and 7 October 2026, the M5 Max, the RTX 5090 Windows rig's RTX 5090, the three-card Windows rig's RX 9070 XT and RTX 4070, a rented H100 SXM, igneum-build-1 The k about 0.33 bound is the implied core of Bitmain's Antminer X9 (RandomX; 1,000 KH/s, 2,472 W, 2.47 J per KH, USD 5,600; pre-orders 26 December 2025), withdrawn in mid-May 2026 with buyers refunded before any unit shipped, no independent benchmark, commodity Sophgo SG2044 server SoCs with an AES accelerator, no tapeout: a claimed, unmeasured figure carried as the pessimistic bound, not a calibration point (attack pass AP-F5-1, 7 October 2026).</td><td class="iv">none yet; the next test is the internal adversarial pass (three lanes new to the hash code, outsider inputs only, reports published whole), and no outside review has run yet</td></tr>
|
||||
<tr data-status="tested by the team"><td class="n">18</td><td class="claim">The chip resistance measurements: the program is latency-bound (random reads), not bandwidth-bound, on every card we own, and sits beyond a card's on-chip cache<div class="where">Litepaper Mining ("waits on memory latency, not on maths or bandwidth"), vs RandomX; the numbers page</div></td><td><span class="st st-2">tested by the team</span></td><td class="mono">readwidth e752fc7 (<code>docs/plans/read-width.md</code>), ca2-era 78c0ee4, ca2-cache 2de19e5 (<code>docs/plans/hot-table.md</code>)</td><td>The dependent-read probes at 32 to 1,024 MiB and the hash rate per class on the three cards; the latency-bound share = rate over the probe ceiling per load</td><td>Latency-bound share at the 1 GiB dataset: RTX 5090 0.96 (v2) and 1.01 (v3), RX 9070 XT 0.87 and 0.95, M5 Max 1.01 and 1.06; wider reads do not close the AMD gap (the 9070 XT does 2.4 G dependent reads per second at every width; the 5090 goes bandwidth-bound at 64 B, share 0.58); a 32 to 96 MiB hot table is not kept resident by any card while the dataset streams (g 0.80 to 0.87 in the added form). 5 October 2026</td><td class="iv">none yet</td></tr>
|
||||
<tr data-status="designed"><td class="n">17</td><td class="claim">The chip resistance claim: at launch the strongest chip in the public model reaches 2.1x (a core as good as a GPU lane, k = 1) to 3.4x (a core three times better, k about 0.33) per joule against an RTX 5090 under class v4, live from genesis on the testnet and the mainnet; the ladder's second rung brings it to about 2.8x; class v5 makes the dataset the chain's state so a stateless or stale chip is wrong on every item; the hot-set cache is bounded at 1.067x at the ceiling and the weak-day FPGA at 12 percent on 15 days a century, both routed to the next class; datacentre silicon does not change the question; a stored-dataset chip pays for itself only at about USD 100 M of market cap in two years; without class v4 the same chip would reach 5x to 9x (the class v3 baseline, the devnet's starting state, never the launch state)<div class="where">the home page's chip line, the litepaper's chip section (/litepaper#chip-model), the miner page's line</div></td><td><span class="st st-0">tested by the team (every card, the verifier, the two attack-pass bounds, the H100), the chip itself modelled, class v5 and the ladder designed, the X9 figure claimed against a CPU core and never measured</span></td><td class="mono"><code>docs/analysis/chip-model-v3.md</code> 5 and 6; <code>docs/analysis/latency-shadow-2026-10-06.md</code>; <code>docs/plans/counter-asic-3-status.md</code>; <code>docs/analysis/attack-pass/f8-uniform.md</code>, <code>f4-weakday.md</code>, <code>docs/analysis/ca3-v4-uniform.md</code>; <code>docs/design/class-v5-stored-state.md</code>; the H100 and market-cap rows of 7 October; <code>docs/plans/cryptanalysis/in-house-pass.md</code> (the internal adversarial pass)</td><td>the chip model's arithmetic in its file; the card rows by the benchmark package; the attack-pass harnesses <code>tools/attack/f8-uniform</code> and the F4 census; the verifier by <code>igneum-pow bench</code></td><td>136 MH/s at 350 W (5090, bench) and 290 W (app); the class v4 efficiency passes (bench log "7 to 8 October 2026, the class v4 efficiency passes: the core clock lock on the RTX 5090 and the RTX 5080", measured): the 5090 at 136.84 MH/s and 475.5 W unlocked, 134.98 at 316.3 W at a 1,400 MHz core lock, the best points class v4 at 1,200 MHz (133.80 MH/s, 305.1 W, 0.439 MH/W) and class v3 at 1,300 MHz (134.62, 223.3 W, 0.603), the premium 145 W unlocked and 82 W at the best points, the knee 1,300 MHz; the RTX 5080 (8 October 2026, the dock card of the three-card Windows rig) at 71.41 MH/s and 253.1 W unlocked under class v4 against 71.28 at 169.7 W under class v3, the best points class v4 at 1,100 MHz (71.20 MH/s, 146.6 W, 0.486 MH/W) and class v3 at 1,000 MHz (71.11, 103.7 W, 0.686), the premium 83.4 W unlocked and 41 W at the best points, the knee between 1,000 and 900 MHz; per tier: a 5080 owner on class v4 locked near 1,100 MHz pays 147 W instead of 253 for 0.3 percent less rate, MH per watt up 72 percent, the lever Ember Tune's core-clock knob in 0.3.24; 27 MH/s at 21 W (M5 Max); 249 MH/s (H100 SXM) at 98 percent of its read ceiling, 1.78x hash, 1.15x MH/W, a third per rented dollar; 2.33 ms per warp; 2.1x, 3.4x, 2.8x at launch; the shadow's premium on a 5090 81.8 W at its knee (class v4 at the 1,200 MHz lock 133.80 MH/s at 305.1 W; class v3 at 1,300 MHz 134.62 at 223.3 W; 7 October 2026); 1.067x at the ceiling; 12 percent on 15 days a century; 10.85 ms at rung 3; USD 100 M; 5.1x to 9.2x the class v3 baseline; 6 and 7 October 2026, the M5 Max, the RTX 5090 Windows rig's RTX 5090, the three-card Windows rig's RX 9070 XT and RTX 4070, a rented H100 SXM, igneum-build-1 The k about 0.33 bound is the implied core of Bitmain's Antminer X9 (RandomX; 1,000 KH/s, 2,472 W, 2.47 J per KH, USD 5,600; pre-orders 26 December 2025), withdrawn in mid-May 2026 with buyers refunded before any unit shipped, no independent benchmark, commodity Sophgo SG2044 server SoCs with an AES accelerator, no tapeout: a claimed, unmeasured figure carried as the pessimistic bound, not a calibration point (attack pass AP-F5-1, 7 October 2026).</td><td class="iv">none yet; the next test is the internal adversarial pass (three lanes new to the hash code, outsider inputs only, reports published whole), whose floor reading is in (measured, 8 October 2026; ledger AP-F8-1 and AP-F8-6): nine of nine hot sets refused; the diffuse era-stride excess, bounded under 0.1 percent of a hash's reads per site, is not caught by the floor and is the next class's test, and no outside review has run yet</td></tr>
|
||||
<tr data-status="tested by the team"><td class="n">18</td><td class="claim">The chip resistance measurements: the program is latency-bound (dependent reads spread over the whole dataset), not bandwidth-bound, on every card we own, and sits beyond a card's on-chip cache; measured 8 October 2026: the distinct-index floor holds at 0.995 on every accepted program, about half of epochs carry one load site with a biased address bit at the era's stride rotation, priced at about 1.6 percent of a hash's reads to a chip storing half the dataset and nothing to one storing all of it (<code>docs/analysis/class-v6/family-gate.md</code>, lane D; adv-cache-2's <code>report-chained-cache-2.md</code> section 2.3 on its branch; ledger AP-F8-7)<div class="where">Litepaper Mining ("waits on memory latency, not on maths or bandwidth"), vs RandomX; the numbers page</div></td><td><span class="st st-2">tested by the team</span></td><td class="mono">readwidth e752fc7 (<code>docs/plans/read-width.md</code>), ca2-era 78c0ee4, ca2-cache 2de19e5 (<code>docs/plans/hot-table.md</code>)</td><td>The dependent-read probes at 32 to 1,024 MiB and the hash rate per class on the three cards; the latency-bound share = rate over the probe ceiling per load</td><td>Latency-bound share at the 1 GiB dataset: RTX 5090 0.96 (v2) and 1.01 (v3), RX 9070 XT 0.87 and 0.95, M5 Max 1.01 and 1.06; wider reads do not close the AMD gap (the 9070 XT does 2.4 G dependent reads per second at every width; the 5090 goes bandwidth-bound at 64 B, share 0.58); a 32 to 96 MiB hot table is not kept resident by any card while the dataset streams (g 0.80 to 0.87 in the added form). 5 October 2026</td><td class="iv">none yet</td></tr>
|
||||
<tr data-status="tested by the team"><td class="n">19</td><td class="claim">The lottery hash is sound as a hash: uniform output, deterministic, no out-of-bounds read, fuzzed; class v3 bit-exact on the three vendors<div class="where">Litepaper vs RandomX ("Every number above is measured and logged"), the numbers page</div></td><td><span class="st st-2">tested by the team</span></td><td class="mono">ca2-mixer 1ab8b21 (<code>tests/mixer.rs</code>, <code>tests/scratch.rs</code>), ca2-era 78c0ee4, ca2-soundness a465881 (<code>docs/analysis/scratch-soundness.md</code>), <code>igneum-pow/tests/packs.rs</code></td><td>The crate suite (53 + 4 + 19 + 7), the Metal fuzz, edge, stats and determinism runs on the v3 construction, the pack vectors and 2^24 fingerprints on Metal, Apple OpenCL, the RTX 5090 and the RX 9070 XT, the 1,024-hash CPU re-check per card</td><td>Class v3 (mixer x8 + era): 200-program fuzz 200 of 200 on Metal, every tenth on Apple OpenCL; the pinned v3 packs 3/3 + 3/3 and 96 of 96 lanes on Metal and Apple OpenCL; the six era packs' fingerprints equal on the three vendors (the three-card Windows rig (RTX 5090, RTX 4070, RX 9070 XT) job run-ca2-era-pc1-20261005, 5 October 2026); the v2 exports byte-identical on the v3 crate; the final-class PC rows and the G2 re-check: job run-ca2-era-pc1b-20261005 (pending at the time of writing)</td><td class="iv">none yet</td></tr>
|
||||
<tr data-status="implemented"><td class="n">20</td><td class="claim">No premine, no pre-sale, no allocation: every coin is minted by the schedule and every coin goes to the block producer (80%) and the proving pool (20%)<div class="where">Homepage stats and Economics tiles; litepaper Supply, Economics</div></td><td><span class="st st-1">implemented</span></td><td class="mono">repo <code>6ac80a3</code>; fork "igneum-node devnet v0"; <code>consensus/core/src/igneum.rs</code>, <code>coinbase.rs</code></td><td><code>cargo test -p kaspa-consensus-core igneum</code> (8 pass: subsidy table, ramp, split, cap) and <code>cargo test -p kaspa-consensus coinbase</code> (8 pass); <code>igneum-miner inspect 40</code>; bench-log "igneum-node devnet v0"</td><td>Coinbases on the devnet: 80/20 exact on 39 of 39 single-payee blocks, the 20% to the <code>igneum-proving-pool-v0</code> output; the per-second schedule sums to under the 4,000,000,000 cap by less than 100 coins; 3,168,808,781 units per DAA second in years 0 to 2, halving at 63,115,200 DAA s. 3 October 2026, Apple M5 Max. The devnet genesis carries no allocation; the mainnet genesis does not exist yet, so the claim is about the code and the stated rule, not a launch that has happened</td><td class="iv">none yet</td></tr>
|
||||
<tr data-status="tested by the team"><td class="n">21</td><td class="claim">The proving pool's 20% reaches shard provers and aggregators<div class="where">Litepaper Economics; homepage "20% provers"</div></td><td><span class="st st-2">tested by the team</span></td><td class="mono">spec 5.3; <code>proving/igneum-prove</code> carries the prover's payout address in every shard proof (ledger P12)</td><td>None. The pool output exists (row 20); the payout from it against proof records is unwritten. Since 5 October 2026: the payout rule is live on the devnet (<code>proving.rs shard_payouts</code>, the carrying segment pays the first valid record per shard its part of the segment's pool credit)</td><td>The escrow accumulated on the simnet (92.55 IGN at the end of the v3 run) and nothing can draw it. Rule decided: per block, divided among shards by consensus proving cost, sortition to 8 provers for 10 s then open (spec 7.2). The economy model of 4 October 2026 (<code>sim/economy</code>, 1,000 operators, 30 days) kept every block proven within 60 s under six stress scenarios; a model, not hardware Live devnet, 5 October 2026: 388 shards paid by 16:02 UTC, 446.13 IGN from the pool to the RTX 5090 Windows rig's payout address, 0.8813 IGN per mergeset block of the proven segment (bench-log entries of 5 October: "the first shards proven, verified and paid" and "real transactions, the first non-empty shard proven and paid")</td><td class="iv">none yet</td></tr>
|
||||
|
|
@ -303,7 +322,7 @@ td.mono{font-family:var(--f-mono);font-size:12.5px;min-width:180px}td.iv{color:v
|
|||
<a href="/wallet">The wallet</a>
|
||||
<a href="/miners">GPU bench table</a>
|
||||
<a href="/dev-fee">The dev fee</a>
|
||||
<a href="/faucet">Testnet faucet</a>
|
||||
<a href="/faucet">Devnet faucet</a>
|
||||
<a href="/metamask">Add Igneum to MetaMask</a>
|
||||
</div></div>
|
||||
<div class="footer-column"><h4>Read</h4><div>
|
||||
|
|
@ -318,6 +337,9 @@ td.mono{font-family:var(--f-mono);font-size:12.5px;min-width:180px}td.iv{color:v
|
|||
<div class="footer-column"><h4>Explore</h4><div>
|
||||
<a href="/live">Live devnet</a>
|
||||
<a href="/explorer">Explorer</a>
|
||||
<a href="/build">Build on Igneum</a>
|
||||
<a href="/swap">Swap</a>
|
||||
<a href="/grants">Grants</a>
|
||||
<a href="/journey">Journey</a>
|
||||
<a href="/download">Downloads: devnet build</a>
|
||||
<a href="https://discord.gg/igneum" target="_blank" rel="noopener">Community Discord</a>
|
||||
|
|
|
|||
|
|
@ -3,22 +3,22 @@
|
|||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
|
||||
<title>Igneum explorer</title>
|
||||
<meta name="description" content="The Igneum block DAG, block by block: hash, DAA score, blue score, miner, transactions and proof records, with the network numbers and the supply.">
|
||||
<title>Igneum Devnet 3 explorer</title>
|
||||
<meta name="description" content="Devnet 3, block by block: the DAG, every transaction, every account, the shard plan and proof of each block, the finality lock that covers it. A test network: coins have no value.">
|
||||
<link rel="canonical" href="https://igneum.network/explorer">
|
||||
<meta name="theme-color" content="#0C0C0E">
|
||||
<meta property="og:type" content="website">
|
||||
<meta property="og:site_name" content="Igneum">
|
||||
<meta property="og:title" content="Igneum explorer">
|
||||
<meta property="og:description" content="The Igneum block DAG, block by block: hash, DAA score, blue score, miner, transactions and proof records, with the network numbers and the supply.">
|
||||
<meta property="og:title" content="Igneum Devnet 3 explorer">
|
||||
<meta property="og:description" content="Devnet 3, block by block: the DAG, every transaction, every account, the shard plan and proof of each block, the finality lock that covers it. A test network: coins have no value.">
|
||||
<meta property="og:url" content="https://igneum.network/explorer">
|
||||
<meta property="og:image" content="https://igneum.network/og-small.png?v=3">
|
||||
<meta property="og:image:width" content="256">
|
||||
<meta property="og:image:height" content="256">
|
||||
<meta property="og:image:alt" content="Igneum. Mined by GPUs. Proven by fire.">
|
||||
<meta name="twitter:card" content="summary">
|
||||
<meta name="twitter:title" content="Igneum explorer">
|
||||
<meta name="twitter:description" content="The Igneum block DAG, block by block, with the network numbers and the supply.">
|
||||
<meta name="twitter:title" content="Igneum Devnet 3 explorer">
|
||||
<meta name="twitter:description" content="Devnet 3, block by block: the DAG, transactions, accounts, proofs and finality. A test network.">
|
||||
<meta name="twitter:image" content="https://igneum.network/og-small.png?v=3">
|
||||
<meta name="twitter:image:alt" content="Igneum. Mined by GPUs. Proven by fire.">
|
||||
<link rel="icon" href="/favicon.ico" sizes="48x48">
|
||||
|
|
@ -91,6 +91,12 @@ dd{margin:0;overflow-wrap:anywhere;font-variant-numeric:tabular-nums}
|
|||
@media (min-width:900px){.two{grid-template-columns:1fr 1fr}.two .card{margin-top:0}}
|
||||
.two-wrap{margin-top:var(--gap)}
|
||||
main{padding-bottom:100px}.card{background:var(--row);border:1px solid var(--line);border-radius:16px;padding:25px;margin-top:24px}.card .viz-head h2{font-size:19px}.card .viz-head .eyebrow{margin:0}
|
||||
.badge{display:inline-flex;align-items:center;gap:6px;font-family:var(--f-mono);font-size:11px;letter-spacing:.06em;text-transform:uppercase;padding:4px 9px;border-radius:999px;border:1px solid var(--line-2);color:var(--ink-2);margin:0 6px 6px 0}
|
||||
.badge.ok{border-color:var(--green,#5CC48A);color:var(--green,#5CC48A)}.badge.hot{border-color:var(--molten);color:var(--molten)}.badge.bad{border-color:var(--excluded);color:var(--excluded)}.badge.wait{color:var(--ash)}
|
||||
.bar{display:inline-block;width:72px;height:7px;border-radius:4px;background:var(--line);vertical-align:middle;margin-right:7px;overflow:hidden}.bar i{display:block;height:100%;background:var(--green,#5CC48A)}.bar i.part{background:var(--molten)}
|
||||
.dagbox{position:relative;width:100%;height:320px;border:1px solid var(--line);border-radius:12px;background:var(--obsidian);overflow:hidden}.dagbox canvas{width:100%;height:100%;display:block;cursor:pointer}
|
||||
.dagtip{position:absolute;pointer-events:none;font:11px/1.5 var(--mono);color:var(--bone);background:var(--graphite);border:1px solid var(--line-2);border-radius:8px;padding:8px 10px;max-width:300px;display:none}
|
||||
.kv{color:var(--ash)}
|
||||
</style>
|
||||
</head>
|
||||
<body class="off">
|
||||
|
|
@ -107,6 +113,7 @@ main{padding-bottom:100px}.card{background:var(--row);border:1px solid var(--lin
|
|||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-mine" data-group="mine" aria-expanded="false" aria-controls="nav-panel-mine" aria-haspopup="true">Mine<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-network" data-group="network" data-active aria-expanded="false" aria-controls="nav-panel-network" aria-haspopup="true">Network<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-learn" data-group="learn" aria-expanded="false" aria-controls="nav-panel-learn" aria-haspopup="true">Learn<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-build" data-group="build" aria-expanded="false" aria-controls="nav-panel-build" aria-haspopup="true">Build<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
</div>
|
||||
<div class="nav-controls">
|
||||
<button class="btn icon-btn" type="button" data-theme-toggle aria-label="Switch to light theme"><svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><circle cx="12" cy="12" r="4"/><path d="M12 2v2m0 16v2M2 12h2m16 0h2M5 5l1 1m12 12 1 1M5 19l1-1M18 6l1-1"/></svg></button>
|
||||
|
|
@ -124,17 +131,19 @@ main{padding-bottom:100px}.card{background:var(--row);border:1px solid var(--lin
|
|||
<a href="/wallet" data-nav="wallet"><b>The wallet</b><span>Your coins. Final means final.</span></a>
|
||||
<a href="/miners" data-nav="miners"><b>GPU bench table</b><span>Measured rates, card by card.</span></a>
|
||||
<a href="/dev-fee" data-nav="dev-fee"><b>The dev fee</b><span>The optional one, in full view, off with one flag.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Testnet faucet</b><span>Test coin for an address, once a day.</span></a>
|
||||
<a href="/metamask" data-nav="metamask"><b>Add to MetaMask</b><span>Igneum as a network in your wallet.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-panel" id="nav-panel-network" data-group="network" role="region" aria-labelledby="nav-btn-network" hidden>
|
||||
<div class="panel-list">
|
||||
<a href="/live" data-nav="live" aria-current="page"><b>Live devnet</b><span>The chain as it grows, one lane per miner.</span></a>
|
||||
<a href="/explorer" data-nav="explorer"><b>Explorer</b><span>Look a block or an address up.</span></a>
|
||||
<a href="/live" data-nav="live"><b>Live devnet</b><span>The chain as it grows, one lane per miner.</span></a>
|
||||
<a href="/explorer" data-nav="explorer" aria-current="page"><b>Explorer</b><span>Look a block or an address up.</span></a>
|
||||
<a href="/journey" data-nav="journey"><b>The journey</b><span>Six phases, four gates, the log behind them.</span></a>
|
||||
<a href="/bench" data-nav="bench"><b>Engineering log</b><span>Every measurement, with the commands that made it.</span></a>
|
||||
<a href="/evidence" data-nav="evidence"><b>Evidence</b><span>Every claim and how far it is tested.</span></a>
|
||||
<a href="/light" data-nav="light"><b>Light wallet</b><span>A balance your browser proves, trusting no node.</span></a>
|
||||
<a href="/receipt" data-nav="receipt"><b>Payment receipt</b><span>A receipt any third party re-verifies offline.</span></a>
|
||||
<a href="/oracle" data-nav="oracle"><b>State oracle on Sepolia</b><span>Devnet 3 balances read from another chain.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-panel" id="nav-panel-learn" data-group="learn" role="region" aria-labelledby="nav-btn-learn" hidden>
|
||||
|
|
@ -147,6 +156,14 @@ main{padding-bottom:100px}.card{background:var(--row);border:1px solid var(--lin
|
|||
<a href="/provenance" data-nav="provenance"><b>Built on the shoulders</b><span>Every borrowed part, credited.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-panel" id="nav-panel-build" data-group="build" role="region" aria-labelledby="nav-btn-build" hidden>
|
||||
<div class="panel-list">
|
||||
<a href="/build" data-nav="build"><b>Build on Igneum</b><span>Chain ids, RPC, a contract in five minutes.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Devnet faucet</b><span>10 IGN of devnet coin, once a day.</span></a>
|
||||
<a href="/swap" data-nav="swap"><b>Swap</b><span>Test tokens on Devnet 3; every swap is a proven block.</span></a>
|
||||
<a href="/grants" data-nav="grants"><b>Grants</b><span>Tooling, apps, infrastructure, research.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-sheet" id="nav-sheet" role="dialog" aria-modal="true" aria-label="Menu" hidden>
|
||||
|
|
@ -158,15 +175,17 @@ main{padding-bottom:100px}.card{background:var(--row);border:1px solid var(--lin
|
|||
<a href="/wallet" data-nav="wallet"><b>The wallet</b><span>Your coins. Final means final.</span></a>
|
||||
<a href="/miners" data-nav="miners"><b>GPU bench table</b><span>Measured rates, card by card.</span></a>
|
||||
<a href="/dev-fee" data-nav="dev-fee"><b>The dev fee</b><span>The optional one, in full view, off with one flag.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Testnet faucet</b><span>Test coin for an address, once a day.</span></a>
|
||||
<a href="/metamask" data-nav="metamask"><b>Add to MetaMask</b><span>Igneum as a network in your wallet.</span></a>
|
||||
</div>
|
||||
<div class="sheet-group"><div class="sheet-head">Network</div>
|
||||
<a href="/live" data-nav="live" aria-current="page"><b>Live devnet</b><span>The chain as it grows, one lane per miner.</span></a>
|
||||
<a href="/explorer" data-nav="explorer"><b>Explorer</b><span>Look a block or an address up.</span></a>
|
||||
<a href="/live" data-nav="live"><b>Live devnet</b><span>The chain as it grows, one lane per miner.</span></a>
|
||||
<a href="/explorer" data-nav="explorer" aria-current="page"><b>Explorer</b><span>Look a block or an address up.</span></a>
|
||||
<a href="/journey" data-nav="journey"><b>The journey</b><span>Six phases, four gates, the log behind them.</span></a>
|
||||
<a href="/bench" data-nav="bench"><b>Engineering log</b><span>Every measurement, with the commands that made it.</span></a>
|
||||
<a href="/evidence" data-nav="evidence"><b>Evidence</b><span>Every claim and how far it is tested.</span></a>
|
||||
<a href="/light" data-nav="light"><b>Light wallet</b><span>A balance your browser proves, trusting no node.</span></a>
|
||||
<a href="/receipt" data-nav="receipt"><b>Payment receipt</b><span>A receipt any third party re-verifies offline.</span></a>
|
||||
<a href="/oracle" data-nav="oracle"><b>State oracle on Sepolia</b><span>Devnet 3 balances read from another chain.</span></a>
|
||||
</div>
|
||||
<div class="sheet-group"><div class="sheet-head">Learn</div>
|
||||
<a href="/litepaper" data-nav="litepaper"><b>Litepaper</b><span>The design, as published.</span></a>
|
||||
|
|
@ -176,6 +195,12 @@ main{padding-bottom:100px}.card{background:var(--row);border:1px solid var(--lin
|
|||
<a href="/randomx" data-nav="randomx"><b>Igneum vs RandomX</b><span>What was kept and what was rebuilt for GPUs.</span></a>
|
||||
<a href="/provenance" data-nav="provenance"><b>Built on the shoulders</b><span>Every borrowed part, credited.</span></a>
|
||||
</div>
|
||||
<div class="sheet-group"><div class="sheet-head">Build</div>
|
||||
<a href="/build" data-nav="build"><b>Build on Igneum</b><span>Chain ids, RPC, a contract in five minutes.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Devnet faucet</b><span>10 IGN of devnet coin, once a day.</span></a>
|
||||
<a href="/swap" data-nav="swap"><b>Swap</b><span>Test tokens on Devnet 3; every swap is a proven block.</span></a>
|
||||
<a href="/grants" data-nav="grants"><b>Grants</b><span>Tooling, apps, infrastructure, research.</span></a>
|
||||
</div>
|
||||
<div class="sheet-foot">
|
||||
<a href="/download" class="btn primary big" data-nav="download">Download</a>
|
||||
<div class="sheet-social"><a href="https://discord.gg/igneum" target="_blank" rel="noopener">Discord</a><a href="https://git.igneum.network/igneum-network/spec" target="_blank" rel="noopener">Source</a><a href="https://www.reddit.com/user/Igneum_network/" target="_blank" rel="noopener">Reddit</a></div>
|
||||
|
|
@ -232,11 +257,11 @@ main{padding-bottom:100px}.card{background:var(--row);border:1px solid var(--lin
|
|||
<main id="main" class="wrap">
|
||||
<div class="head">
|
||||
<div class="breadcrumb"><a href="/">Igneum</a><span>/</span><span>Explorer</span></div>
|
||||
<div class="eyebrow"><span class="line"></span>devnet, last 24 hours</div>
|
||||
<h1>Explorer<span class="accent">.</span></h1>
|
||||
<p>Every block the devnet made in the last day, read from a node by the observer. Paste a block hash, a transaction hash, a chain block number or an address, or click any row.</p>
|
||||
<div class="eyebrow"><span class="line"></span>Devnet 3, chain id 4463</div>
|
||||
<h1>Devnet 3 explorer<span class="accent">.</span></h1>
|
||||
<p>Every block Devnet 3 made in the last day and every transaction of the last seven days, read from a node by the observer and the indexer. Paste a block hash, a transaction hash, a chain block number or an address, or click any row. Devnet 3 is a test network: its coins have no value and the chain may reset. Every number here comes from one node, the observer node on the build box, the chain the finality certificates follow; the indexer reads that node's execution RPC and nothing else.</p>
|
||||
<form class="search" id="search" role="search">
|
||||
<input id="q" type="search" autocomplete="off" spellcheck="false" placeholder="block hash, transaction hash, chain block number, 0x address or igneumdev:… address" aria-label="Search the explorer">
|
||||
<input id="q" type="search" autocomplete="off" spellcheck="false" placeholder="block hash, transaction hash, chain block number, 0x address or igneumdev:… address" aria-label="Search the Devnet 3 explorer">
|
||||
<button class="btn primary" type="submit">Search</button>
|
||||
</form>
|
||||
<div class="msg" id="msg" aria-live="polite"></div>
|
||||
|
|
@ -245,32 +270,53 @@ main{padding-bottom:100px}.card{background:var(--row);border:1px solid var(--lin
|
|||
<div class="cell status"><div class="k">Status</div><div class="v"><span class="dot"></span><span id="st-status">OFFLINE</span></div><div class="s" id="st-age">no observer update yet</div></div>
|
||||
<div class="cell"><div class="k">Height</div><div class="v" id="st-height">0</div><div class="s" id="st-count">chain block number, 0 blocks in the DAG</div></div>
|
||||
<div class="cell"><div class="k">DAA score</div><div class="v" id="st-daa">0</div><div class="s" id="st-blue">blue score 0</div></div>
|
||||
<div class="cell"><div class="k">Difficulty</div><div class="v" id="st-diff">0</div><div class="s" id="st-bt">target per block</div></div>
|
||||
<div class="cell"><div class="k">Hash rate</div><div class="v" id="st-hps">0</div><div class="s">network estimate</div></div>
|
||||
<div class="cell"><div class="k">Block reward</div><div class="v" id="st-reward">0<small>IGN</small></div><div class="s" id="st-split">80% miner, 20% proving pool</div></div>
|
||||
<div class="cell"><div class="k">Circulating</div><div class="v" id="st-supply">0<small>IGN</small></div><div class="s" id="st-cap">of 4,000,000,000 by the rule</div></div>
|
||||
<div class="cell"><div class="k">Next halving</div><div class="v" id="st-halving">0<small>d</small></div><div class="s" id="st-ramp">ramp</div></div>
|
||||
<div class="cell"><div class="k">Hash rate</div><div class="v" id="st-hps">0</div><div class="s" id="st-diff">difficulty 0</div></div>
|
||||
<div class="cell"><div class="k">Chain rate, 10 min</div><div class="v" id="st-rate">0<small>blocks/s</small></div><div class="s" id="st-rate-s">DAG blocks per second; chain blocks per second</div></div>
|
||||
<div class="cell"><div class="k">Finality</div><div class="v" id="st-fin">n/a</div><div class="s" id="st-fin-s">voters and weight</div></div>
|
||||
<div class="cell"><div class="k">Program class</div><div class="v" id="st-class">v4</div><div class="s" id="st-class-s">the hash program family at the tip</div></div>
|
||||
<div class="cell"><div class="k">Proving</div><div class="v" id="st-prov">0<small>paid</small></div><div class="s" id="st-prov-s">shards paid in 10 min</div></div>
|
||||
</div>
|
||||
<div class="card" aria-label="The DAG">
|
||||
<div class="viz-head"><h2>The DAG</h2><div class="eyebrow" id="dag-eyebrow">the newest 150 blocks, one lane per miner</div></div>
|
||||
<div class="dagbox"><canvas id="dag" aria-label="The last 150 blocks of Devnet 3 as a graph: time left to right, one lane per miner, lines to parents"></canvas><div class="dagtip" id="dag-tip"></div></div>
|
||||
<div class="legend" style="margin-top:12px"><span><i class="sw chain"></i>chain block</span><span><i class="sw blue"></i>blue, merged</span><span><i class="sw red"></i>red, excluded</span><span><i class="sw"></i>pending</span><span>◆ under a lock</span><span>● every shard paid</span></div>
|
||||
<p class="note">Left to right is arrival order at the observer; a line joins a block to each parent in the picture. Blue blocks are merged and paid; red blocks are excluded from the order. A diamond outline marks a block under a finality lock, a filled dot a block whose every planned shard has been paid. Click a block for its page.</p>
|
||||
</div>
|
||||
<div class="card" aria-label="Latest blocks">
|
||||
<div class="viz-head"><h2>Latest blocks</h2><div class="eyebrow" id="blk-eyebrow">newest first, every 5 s</div></div>
|
||||
<div class="tbl">
|
||||
<table>
|
||||
<thead><tr><th>Block</th><th class="n">Number</th><th class="n">DAA</th><th class="n">Blue score</th><th>Miner</th><th class="n">Txs</th><th class="n">Proof records</th><th>Time</th></tr></thead>
|
||||
<tbody id="blocks"><tr><td colspan="8" class="empty">Loading.</td></tr></tbody>
|
||||
<thead><tr><th>Block</th><th class="n">Number</th><th class="n">DAA</th><th class="n">Blue score</th><th>Class</th><th>Miner</th><th class="n">Txs</th><th>Shards paid</th><th>Final</th><th>Time</th></tr></thead>
|
||||
<tbody id="blocks"><tr><td colspan="10" class="empty">Loading.</td></tr></tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="legend"><span><i class="sw chain"></i>chain block</span><span><i class="sw blue"></i>blue, merged and paid</span><span><i class="sw red"></i>red, excluded</span><span><i class="sw"></i>pending, not merged yet</span><span>★ locked checkpoint</span></div>
|
||||
<p class="note">Number is the chain block number, the same number the EVM reports; a block off the selected chain has none. Miner is the payout address the coinbase names. Proof records is how many shard proofs the block carries for earlier blocks. Click a row for the block.</p>
|
||||
<p class="note">Number is the chain block number, the same number the EVM reports; a block off the selected chain has none. Class is the hash program family the block was mined under. Txs is what the block carries; the EVM executes each transaction once, in the first chain block that includes it. Shards paid counts the block's proof shards a later coinbase has paid. Final means a finality lock covers the block.</p>
|
||||
<button class="btn" id="more" type="button" style="margin-top:14px">Older blocks</button>
|
||||
</div>
|
||||
<div class="card" aria-label="Public API">
|
||||
<div class="viz-head"><h2>Public API</h2><div class="eyebrow">JSON, cached 10 s</div></div>
|
||||
<dl>
|
||||
<dt>/api/stats</dt><dd><a href="/api/stats" class="hash">network hash rate, difficulty, block time, block reward now, blocks per day, DAA, blue score, height, last block, chain id, version</a></dd>
|
||||
<dt>/api/supply</dt><dd><a href="/api/supply" class="hash">circulating by the emission rule, the 4,000,000,000 cap, the halving table, the 30-day ramp, the observer's coinbase check</a></dd>
|
||||
<dt>/api/explorer</dt><dd><a href="/api/explorer?blocks=20" class="hash">?blocks=N, ?block=hash, ?height=N, ?address=addr, ?search=q</a></dd>
|
||||
</dl>
|
||||
<p class="note">Reward and supply come from the emission rule of the specification (section 2.5) at the node's DAA score; the observer checks the chain's coinbase sums against it every hour and the result is in /api/supply under check.</p>
|
||||
<div class="card" aria-label="Latest transactions">
|
||||
<div class="viz-head"><h2>Latest transactions</h2><div class="eyebrow" id="tx-eyebrow">newest first, every 5 s</div></div>
|
||||
<div class="tbl">
|
||||
<table>
|
||||
<thead><tr><th>Transaction</th><th class="n">Block</th><th>From</th><th>To</th><th class="n">Value</th><th>Status</th><th>Time</th></tr></thead>
|
||||
<tbody id="txs"><tr><td colspan="7" class="empty">Loading.</td></tr></tbody>
|
||||
</table>
|
||||
</div>
|
||||
<p class="note">EVM transactions as the indexer read them from the node's receipts: seven days are kept. Value is in IGN (18 decimals on the EVM side).</p>
|
||||
<button class="btn" id="more-tx" type="button" style="margin-top:14px">Older transactions</button>
|
||||
</div>
|
||||
<div class="two two-wrap">
|
||||
<div class="card" aria-label="Proving"><div class="viz-head"><h2>Proving</h2><div class="eyebrow" id="pv-eyebrow">shards, provers, latency</div></div><dl id="pv"></dl><p class="note"><a href="/proving">The proving view</a>: every chain block's shard plan, who proved what, and the block-to-paid latency.</p></div>
|
||||
<div class="card" aria-label="Public API"><div class="viz-head"><h2>Public API</h2><div class="eyebrow">JSON, cached 5 to 10 s</div></div>
|
||||
<dl>
|
||||
<dt>/api/stats</dt><dd><a href="/api/stats" class="hash">hash rate, difficulty, block time, reward, DAA, blue score, height</a></dd>
|
||||
<dt>/api/supply</dt><dd><a href="/api/supply" class="hash">circulating by the emission rule, the cap, the halving table</a></dd>
|
||||
<dt>/api/explorer</dt><dd><a href="/api/explorer?blocks=20" class="hash">?blocks=N, ?block=hash, ?height=N, ?tx=hash, ?txs=N, ?address=addr, ?proving=1, ?stats=1, ?dag=N, ?search=q</a></dd>
|
||||
<dt>/api/checkpoint</dt><dd><a href="/api/checkpoint" class="hash">the newest certified checkpoint with its voter table and headers; ?index=N for one</a></dd>
|
||||
<dt>/api/live</dt><dd><a href="/api/live" class="hash">the observer's feed: blocks of the last 90 s, miners, events, finality, proving</a></dd>
|
||||
</dl>
|
||||
<p class="note">Every answer names the network (Devnet 3, chain id 4463). The RPC itself is at rpc.devnet.igneum.network (read methods and eth_sendRawTransaction, 20 requests per second per address).</p>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
<!-- footer:start -->
|
||||
|
|
@ -295,7 +341,7 @@ main{padding-bottom:100px}.card{background:var(--row);border:1px solid var(--lin
|
|||
<a href="/wallet">The wallet</a>
|
||||
<a href="/miners">GPU bench table</a>
|
||||
<a href="/dev-fee">The dev fee</a>
|
||||
<a href="/faucet">Testnet faucet</a>
|
||||
<a href="/faucet">Devnet faucet</a>
|
||||
<a href="/metamask">Add Igneum to MetaMask</a>
|
||||
</div></div>
|
||||
<div class="footer-column"><h4>Read</h4><div>
|
||||
|
|
@ -310,6 +356,9 @@ main{padding-bottom:100px}.card{background:var(--row);border:1px solid var(--lin
|
|||
<div class="footer-column"><h4>Explore</h4><div>
|
||||
<a href="/live">Live devnet</a>
|
||||
<a href="/explorer">Explorer</a>
|
||||
<a href="/build">Build on Igneum</a>
|
||||
<a href="/swap">Swap</a>
|
||||
<a href="/grants">Grants</a>
|
||||
<a href="/journey">Journey</a>
|
||||
<a href="/download">Downloads: devnet build</a>
|
||||
<a href="https://discord.gg/igneum" target="_blank" rel="noopener">Community Discord</a>
|
||||
|
|
@ -341,11 +390,12 @@ main{padding-bottom:100px}.card{background:var(--row);border:1px solid var(--lin
|
|||
</script>
|
||||
<!-- footer:end -->
|
||||
<script type="module">
|
||||
import { classify, hrefFor, ign, shortHash, hashrate, rel, int } from '/lib/explorer.mjs';
|
||||
import { classify, hrefFor, ign, ignFromWei, shortHash, hashrate, rel, int } from '/lib/explorer.mjs';
|
||||
const $ = id => document.getElementById(id);
|
||||
const esc = s => String(s).replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>');
|
||||
let oldest = 0, serverNow = 0, serverAt = 0;
|
||||
const esc = s => String(s ?? '').replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>');
|
||||
let oldest = 0, oldestTx = 0, serverNow = 0, serverAt = 0;
|
||||
const vnow = () => serverNow + (performance.now() - serverAt);
|
||||
const stamp = iso => iso ? new Date(iso).toISOString().slice(11, 19) + ' UTC' : '';
|
||||
$('search').addEventListener('submit', async e => {
|
||||
e.preventDefault();
|
||||
const c = classify($('q').value);
|
||||
|
|
@ -358,46 +408,109 @@ $('search').addEventListener('submit', async e => {
|
|||
if (j.ok && j.href) location.href = j.href; else $('msg').textContent = j.error || 'Not found.';
|
||||
} catch { $('msg').textContent = 'The API did not answer.'; }
|
||||
});
|
||||
const minerCell = b => (b.evm_miner ? `<a class="hash" href="/address/${b.evm_miner}" title="${esc(b.evm_miner)}">${esc(shortHash(b.evm_miner, 6, 4))}</a>` : (b.miner ? `<a class="hash" href="/address/${esc(b.miner)}">${esc(shortHash(b.miner, 14, 4))}</a>` : '<span class="id">' + esc(b.miner_id || '?') + '</span>')) + `<span class="id" style="margin-left:8px;font-size:12px">${esc(b.miner_id || '')}</span>`;
|
||||
function shardsCell(b) {
|
||||
const s = b.shards; if (!s || !s.total) return b.chain ? '<span class="kv">no plan yet</span>' : '<span class="kv">not a chain block</span>';
|
||||
const pct = Math.round(s.paid / s.total * 100);
|
||||
return `<span class="bar" title="${s.paid} paid, ${s.verified} verified, ${s.proving} proving, ${s.planned} planned"><i class="${s.paid === s.total ? '' : 'part'}" style="width:${pct}%"></i></span>${s.paid} of ${s.total}`;
|
||||
}
|
||||
function rowHtml(b) {
|
||||
const sw = b.chain ? 'chain' : b.color;
|
||||
const miner = b.evm_miner ? `<a class="hash" href="/address/${b.evm_miner}" title="${esc(b.evm_miner)}">${esc(shortHash(b.evm_miner, 6, 4))}</a>` : (b.miner ? `<a class="hash" href="/address/${esc(b.miner)}">${esc(shortHash(b.miner, 14, 4))}</a>` : '<span class="id">' + esc(b.miner_id || '?') + '</span>');
|
||||
return `<tr data-href="/block/${b.hash}"><td><i class="sw ${sw}" title="${b.chain ? 'chain block' : b.color}"></i><a class="hash" href="/block/${b.hash}">${esc(shortHash(b.hash, 10, 6))}</a>${b.locked ? ' ★' : ''}</td><td class="n">${b.number === null ? '<span style="color:var(--ash)">off chain</span>' : int(b.number)}</td><td class="n">${int(b.daa)}</td><td class="n">${int(b.blue_score)}</td><td>${miner}<span class="id" style="margin-left:8px;font-size:12px">${esc(b.miner_id || '')}</span></td><td class="n">${b.tx_count === null ? 'n/a' : b.tx_count}</td><td class="n">${b.proof_records === null ? 'n/a' : b.proof_records}</td><td title="${new Date(b.ts).toISOString()}">${rel(vnow() - b.ts)}</td></tr>`;
|
||||
const replaced = b.chain && b.chain_now === false, sw = replaced ? '' : (b.chain ? 'chain' : b.color);
|
||||
return `<tr data-href="/block/${b.hash}"><td><i class="sw ${sw}" title="${replaced ? 'was the chain block of its number, replaced by a tip reorg' : (b.chain ? 'chain block' : b.color)}"></i><a class="hash" href="/block/${b.hash}">${esc(shortHash(b.hash, 10, 6))}</a>${b.locked ? ' ★' : ''}</td><td class="n">${b.number === null ? '<span class="kv">off chain</span>' : (replaced ? `<span class="kv" title="a tip reorg gave this number to another block">${int(b.number)}, replaced</span>` : int(b.number))}</td><td class="n">${int(b.daa)}</td><td class="n">${int(b.blue_score)}</td><td><span class="chip">${esc(b.class || 'v4')}</span></td><td>${minerCell(b)}</td><td class="n">${b.tx_count === null ? 'n/a' : b.tx_count}</td><td>${shardsCell(b)}</td><td>${b.final ? '<span class="chip ok">final</span>' : '<span class="kv">not yet</span>'}</td><td title="${new Date(b.ts).toISOString()}">${rel(vnow() - b.ts)}</td></tr>`;
|
||||
}
|
||||
async function loadBlocks(before) {
|
||||
const r = await fetch('/api/explorer?blocks=50' + (before ? '&before=' + before : ''));
|
||||
const j = await r.json(); if (!j.ok) throw new Error(j.error);
|
||||
serverNow = new Date(j.now).getTime(); serverAt = performance.now();
|
||||
const html = j.blocks.map(rowHtml).join('');
|
||||
if (before) $('blocks').insertAdjacentHTML('beforeend', html); else $('blocks').innerHTML = html || '<tr><td colspan="8" class="empty">No blocks in the last 24 hours.</td></tr>';
|
||||
if (before) $('blocks').insertAdjacentHTML('beforeend', html); else $('blocks').innerHTML = html || '<tr><td colspan="10" class="empty">No blocks in the last 24 hours.</td></tr>';
|
||||
if (j.blocks.length) oldest = j.blocks[j.blocks.length - 1].rx;
|
||||
$('blk-eyebrow').textContent = (j.stale ? 'observer offline, last known' : 'newest first, every 5 s') + (j.network ? ', ' + j.network : '');
|
||||
$('blk-eyebrow').textContent = (j.stale ? 'observer offline, last known' : 'newest first, every 5 s') + (j.lock ? `, lock ${int(j.lock.index)} at blue score ${int(j.lock.blue_score)}` : ', no lock yet');
|
||||
}
|
||||
$('blocks').addEventListener('click', e => { const tr = e.target.closest('tr[data-href]'); if (tr && !e.target.closest('a')) location.href = tr.dataset.href; });
|
||||
function txHtml(t) {
|
||||
return `<tr data-href="/tx/${t.hash}"><td><a class="hash" href="/tx/${t.hash}">${esc(shortHash(t.hash, 10, 6))}</a></td><td class="n"><a href="/block/${t.block_hash}">${int(t.number)}</a></td><td><a class="hash" href="/address/${t.from}" title="${esc(t.from)}">${esc(shortHash(t.from, 6, 4))}</a></td><td>${t.to ? `<a class="hash" href="/address/${t.to}" title="${esc(t.to)}">${esc(shortHash(t.to, 6, 4))}</a>` : (t.contract_address ? `<span class="kv">created </span><a class="hash" href="/address/${t.contract_address}">${esc(shortHash(t.contract_address, 6, 4))}</a>` : '<span class="kv">none</span>')}</td><td class="n">${ignFromWei(t.value_wei, 4)} IGN</td><td>${t.status === 'success' ? '<span class="chip ok">ok</span>' : t.status === 'failed' ? '<span class="chip" style="border-color:var(--excluded);color:var(--excluded)">failed</span>' : '<span class="kv">no receipt</span>'}</td><td title="${t.ts ? new Date(t.ts).toISOString() : ''}">${t.ts ? rel(vnow() - t.ts) : 'n/a'}</td></tr>`;
|
||||
}
|
||||
async function loadTxs(before) {
|
||||
const r = await fetch('/api/explorer?txs=30' + (before ? '&before=' + before : ''));
|
||||
const j = await r.json(); if (!j.ok) throw new Error(j.error);
|
||||
const html = j.txs.map(txHtml).join('');
|
||||
if (before) $('txs').insertAdjacentHTML('beforeend', html); else $('txs').innerHTML = html || '<tr><td colspan="7" class="empty">No transactions indexed yet.</td></tr>';
|
||||
if (j.txs.length) oldestTx = j.txs[j.txs.length - 1].number;
|
||||
const ix = j.indexer || {};
|
||||
$('tx-eyebrow').textContent = ix.stale ? 'indexer stale, last known' : `newest first, every 5 s; ${int(ix.txs_total)} transactions and ${int(ix.accounts_total)} accounts in seven days, indexed to chain block ${int(ix.indexed_number)}`;
|
||||
}
|
||||
for (const [tb] of [['blocks'], ['txs']]) $(tb).addEventListener('click', e => { const tr = e.target.closest('tr[data-href]'); if (tr && !e.target.closest('a')) location.href = tr.dataset.href; });
|
||||
$('more').addEventListener('click', () => { $('more').disabled = true; loadBlocks(oldest).catch(() => {}).finally(() => { $('more').disabled = false; clearInterval(timer); }); });
|
||||
$('more-tx').addEventListener('click', () => { $('more-tx').disabled = true; loadTxs(oldestTx).catch(() => {}).finally(() => { $('more-tx').disabled = false; clearInterval(timerTx); }); });
|
||||
async function loadStats() {
|
||||
const [s, p] = await Promise.all([fetch('/api/stats').then(r => r.json()), fetch('/api/supply').then(r => r.json())]);
|
||||
const s = await fetch('/api/explorer?stats=1').then(r => r.json()); if (!s.ok) throw new Error(s.error);
|
||||
document.body.classList.toggle('on', !s.stale); document.body.classList.toggle('off', !!s.stale);
|
||||
$('st-status').textContent = s.stale ? 'OFFLINE' : 'LIVE';
|
||||
$('st-age').textContent = s.age_s === null ? 'no observer update yet' : (s.stale ? `last update ${rel(s.age_s * 1000)}` : `${s.network || ''}, node ${s.node_version || '?'}`);
|
||||
$('st-age').textContent = s.stale ? 'observer stale' : `${s.network || 'Devnet 3'}, node ${s.node_version || '?'}, read ${stamp(s.now)}`;
|
||||
$('st-height').textContent = s.height === null ? 'n/a' : int(s.height);
|
||||
$('st-count').textContent = `chain block number, ${int(s.block_count)} blocks in the DAG`;
|
||||
$('st-daa').textContent = int(s.daa); $('st-blue').textContent = 'blue score ' + int(s.blue_score);
|
||||
$('st-diff').textContent = s.difficulty === null ? 'n/a' : (s.difficulty >= 1e6 ? (s.difficulty / 1e6).toFixed(2) + ' M' : int(s.difficulty));
|
||||
$('st-bt').textContent = s.block_time_measured_s === null ? 'target 1 s per block' : `${s.block_time_measured_s} s per block over 60 s, target 1 s`;
|
||||
$('st-hps').textContent = hashrate(s.hashrate);
|
||||
if (s.block_reward) { $('st-reward').innerHTML = esc(Number(s.block_reward.ign).toFixed(4)) + '<small>IGN</small>'; $('st-split').textContent = `${Number(s.block_reward.miner_ign).toFixed(4)} miner, ${Number(s.block_reward.proving_pool_ign).toFixed(4)} proving pool`; }
|
||||
if (p.ok) {
|
||||
$('st-supply').innerHTML = esc(int(Number(p.circulating_ign))) + '<small>IGN</small>';
|
||||
$('st-cap').textContent = `of ${int(Number(p.max_supply_ign))}, ${(Number(p.circulating_ign) / Number(p.max_supply_ign) * 100).toFixed(3)}% by the rule`;
|
||||
const d = p.halving.next_halving_in_s / 86400;
|
||||
$('st-halving').innerHTML = esc(d >= 1 ? Math.floor(d).toLocaleString('en-GB') : (p.halving.next_halving_in_s / 3600).toFixed(1)) + '<small>' + (d >= 1 ? 'days' : 'h') + '</small>';
|
||||
$('st-ramp').textContent = p.ramp.complete ? 'launch ramp complete' : `launch ramp at ${(p.ramp.factor_now * 100).toFixed(1)}%, full at DAA ${int(p.ramp.length_daa_s)}`;
|
||||
}
|
||||
$('st-hps').textContent = hashrate(s.hashrate); $('st-diff').textContent = 'difficulty ' + (s.difficulty === null ? 'n/a' : (s.difficulty >= 1e6 ? (s.difficulty / 1e6).toFixed(2) + ' M' : int(s.difficulty)));
|
||||
$('st-rate').innerHTML = esc(s.blocks_per_s_10m === null ? 'n/a' : s.blocks_per_s_10m.toFixed(2)) + '<small>blocks/s</small>';
|
||||
$('st-rate-s').textContent = `${s.chain_blocks_per_s_10m === null ? 'n/a' : s.chain_blocks_per_s_10m.toFixed(2)} chain blocks per second, ${int(s.miners_10m)} miners in 10 min`;
|
||||
const f = s.finality;
|
||||
if (f) { $('st-fin').innerHTML = f.latest_locked_index === null ? 'no lock' : `lock ${int(f.latest_locked_index)}`; $('st-fin-s').textContent = `${int(f.voters)} voters, ${int(f.total_weight)} blocks of weight${s.lock ? `, ${(s.lock.fraction_total * 100).toFixed(1)}% signed the newest lock` : ''}${f.active ? '' : ', finality paused'}`; }
|
||||
$('st-class').textContent = s.class ? s.class.class : 'v4';
|
||||
const next = s.class && s.class.floors ? s.class.floors.find(x => x.daa > (s.daa || 0)) : null;
|
||||
$('st-class-s').textContent = next ? `${next.class} from DAA ${int(next.daa)}` : (s.class && s.class.floors && s.class.floors.length ? `since DAA ${int(s.class.floors[s.class.floors.length - 1].daa)}` : 'the hash program family at the tip');
|
||||
const p = s.proving || {};
|
||||
$('st-prov').innerHTML = esc(int(p.shards_paid_10m ?? 0)) + '<small>paid</small>';
|
||||
$('st-prov-s').textContent = p.supported === false ? 'the node reports no proving layer' : `shards paid in 10 min, ${int(p.provers_10m ?? 0)} provers, ${int(p.open_blocks ?? 0)} open blocks`;
|
||||
}
|
||||
async function loadProving() {
|
||||
const j = await fetch('/api/explorer?proving=1').then(r => r.json()); if (!j.ok) throw new Error(j.error);
|
||||
const p = j.proving || {}, l = j.latency_1h || {}, t = j.totals_24h || {};
|
||||
const dl = pairs => pairs.map(([k, v]) => `<dt>${esc(k)}</dt><dd>${v}</dd>`).join('');
|
||||
$('pv-eyebrow').textContent = `read ${stamp(j.now)}`;
|
||||
$('pv').innerHTML = dl([
|
||||
['Paid, 24 h', `${int(t.paid ? t.paid.shards : 0)} shards, ${ignFromWei(t.paid ? t.paid.payout_wei : '0', 2)} IGN to provers`],
|
||||
['Open now', `${int(t.planned ? t.planned.shards : 0)} planned, ${int(t.proving ? t.proving.shards : 0)} proving, ${int(t.verified ? t.verified.shards : 0)} verified and unpaid`],
|
||||
['Provers, 24 h', `${int(j.provers.length)} keys paid`],
|
||||
['Latency, 1 h', l.paid ? `${int(l.paid)} paid; p50 ${int(l.p50_daa)} DAA, p90 ${int(l.p90_daa)} DAA from the block to its payer` : 'no shard paid in the last hour'],
|
||||
['Verifier', p.verifier ? 'the observer node checks every record it sees' : 'n/a'],
|
||||
]);
|
||||
}
|
||||
// the DAG picture: arrival order left to right, one lane per miner, links to parents in the picture
|
||||
const dagTip = $('dag-tip'); let dagBlocks = [], dagPos = new Map();
|
||||
function drawDag() {
|
||||
const cv = $('dag'); if (!cv || !dagBlocks.length) return;
|
||||
const dpr = Math.min(devicePixelRatio || 1, 2), W = cv.clientWidth, H = cv.clientHeight; cv.width = W * dpr; cv.height = H * dpr;
|
||||
const ctx = cv.getContext('2d'); ctx.setTransform(dpr, 0, 0, dpr, 0, 0); ctx.clearRect(0, 0, W, H);
|
||||
const cs = getComputedStyle(document.documentElement), col = k => cs.getPropertyValue(k).trim();
|
||||
const lanes = []; const laneOf = new Map();
|
||||
for (const b of dagBlocks) { const m = b.miner_id || '?'; if (!laneOf.has(m)) { laneOf.set(m, lanes.length); lanes.push(m); } }
|
||||
const n = dagBlocks.length, padX = 18, padY = 16, lh = Math.max(14, (H - 2 * padY) / Math.max(1, lanes.length)), xs = (W - 2 * padX) / Math.max(1, n - 1);
|
||||
dagPos = new Map(); dagBlocks.forEach((b, i) => dagPos.set(b.hash, { x: padX + i * xs, y: padY + laneOf.get(b.miner_id || '?') * lh + lh / 2, b }));
|
||||
ctx.lineWidth = 1;
|
||||
for (const b of dagBlocks) { const p = dagPos.get(b.hash); for (const ph of b.parent_hashes || []) { const q = dagPos.get(ph); if (!q) continue; ctx.strokeStyle = b.chain && ph === b.selected_parent ? col('--ember') : 'rgba(154,154,158,.35)'; ctx.beginPath(); ctx.moveTo(p.x, p.y); ctx.lineTo(q.x, q.y); ctx.stroke(); } }
|
||||
for (const b of dagBlocks) {
|
||||
const p = dagPos.get(b.hash), r = b.chain ? 5 : 3.5;
|
||||
ctx.fillStyle = b.chain && b.chain_now !== false ? col('--ember') : b.color === 'blue' ? col('--included') : b.color === 'red' ? col('--excluded') : col('--ash');
|
||||
ctx.beginPath(); ctx.arc(p.x, p.y, r, 0, Math.PI * 2); ctx.fill();
|
||||
if (b.final) { ctx.strokeStyle = col('--molten'); ctx.beginPath(); ctx.moveTo(p.x, p.y - r - 4); ctx.lineTo(p.x + r + 4, p.y); ctx.lineTo(p.x, p.y + r + 4); ctx.lineTo(p.x - r - 4, p.y); ctx.closePath(); ctx.stroke(); }
|
||||
if (b.shards && b.shards.total && b.shards.paid === b.shards.total) { ctx.fillStyle = col('--bone'); ctx.beginPath(); ctx.arc(p.x, p.y, 1.6, 0, Math.PI * 2); ctx.fill(); }
|
||||
}
|
||||
ctx.font = '10px ' + (col('--mono') || 'monospace'); ctx.fillStyle = col('--ash');
|
||||
lanes.forEach((m, i) => ctx.fillText(m, 4, padY + i * lh + lh / 2 - 7));
|
||||
}
|
||||
function nearest(ev) { const cv = $('dag'), r = cv.getBoundingClientRect(), x = ev.clientX - r.left, y = ev.clientY - r.top; let best = null, bd = 144; for (const p of dagPos.values()) { const d = (p.x - x) ** 2 + (p.y - y) ** 2; if (d < bd) { bd = d; best = p; } } return best; }
|
||||
$('dag').addEventListener('mousemove', ev => { const p = nearest(ev); if (!p) { dagTip.style.display = 'none'; return; } const b = p.b, s = b.shards; dagTip.style.display = 'block'; dagTip.style.left = Math.min(p.x + 12, $('dag').clientWidth - 310) + 'px'; dagTip.style.top = (p.y + 12) + 'px'; dagTip.innerHTML = `${esc(shortHash(b.hash, 10, 6))}<br>${b.chain ? (b.chain_now === false ? 'replaced chain block ' + int(b.number) : 'chain block ' + int(b.number)) : esc(b.color)}, blue score ${int(b.blue_score)}, DAA ${int(b.daa)}<br>miner ${esc(b.miner_id || '?')}, class ${esc(b.class || 'v4')}, ${b.parents} parent${b.parents === 1 ? '' : 's'}<br>${s && s.total ? `${s.paid} of ${s.total} shards paid` : (b.chain ? 'plan not read yet' : 'no shards (not a chain block)')}${b.final ? ', under a lock' : ''}`; });
|
||||
$('dag').addEventListener('mouseleave', () => { dagTip.style.display = 'none'; });
|
||||
$('dag').addEventListener('click', ev => { const p = nearest(ev); if (p) location.href = '/block/' + p.b.hash; });
|
||||
async function loadDag() { const j = await fetch('/api/explorer?dag=150').then(r => r.json()); if (!j.ok) throw new Error(j.error); dagBlocks = j.blocks; $('dag-eyebrow').textContent = `the newest ${j.blocks.length} blocks, one lane per miner, read ${stamp(j.now)}`; drawDag(); }
|
||||
window.addEventListener('resize', drawDag); document.addEventListener('igneum-theme', drawDag);
|
||||
const timer = setInterval(() => { loadBlocks().catch(() => {}); }, 5000);
|
||||
setInterval(() => { loadStats().catch(() => {}); }, 10000);
|
||||
loadBlocks().catch(e => { $('blocks').innerHTML = `<tr><td colspan="8" class="empty">${esc(e.message)}</td></tr>`; });
|
||||
loadStats().catch(() => {});
|
||||
const timerTx = setInterval(() => { loadTxs().catch(() => {}); }, 5000);
|
||||
setInterval(() => { loadStats().catch(() => {}); loadProving().catch(() => {}); }, 10000);
|
||||
setInterval(() => { loadDag().catch(() => {}); }, 4000);
|
||||
loadBlocks().catch(e => { $('blocks').innerHTML = `<tr><td colspan="10" class="empty">${esc(e.message)}</td></tr>`; });
|
||||
loadTxs().catch(e => { $('txs').innerHTML = `<tr><td colspan="7" class="empty">${esc(e.message)}</td></tr>`; });
|
||||
loadStats().catch(() => {}); loadProving().catch(() => {}); loadDag().catch(() => {});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
|||
|
|
@ -3,22 +3,22 @@
|
|||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
|
||||
<title>Igneum testnet faucet. 10 IGN a day for testing</title>
|
||||
<meta name="description" content="Testnet IGN for developers and miners: 10 IGN per address per day, no value, no account. Paste an address, get a transaction hash.">
|
||||
<title>Igneum Devnet 3 faucet. 10 IGN a day for building</title>
|
||||
<meta name="description" content="Devnet 3 IGN for developers: 10 IGN per address per day, no value, no account. Paste an address, get a transaction hash.">
|
||||
<link rel="canonical" href="https://igneum.network/faucet">
|
||||
<meta name="theme-color" content="#0C0C0E">
|
||||
<meta property="og:type" content="website">
|
||||
<meta property="og:site_name" content="Igneum">
|
||||
<meta property="og:title" content="Igneum testnet faucet">
|
||||
<meta property="og:description" content="Testnet IGN for developers and miners: 10 IGN per address per day, no value, no account.">
|
||||
<meta property="og:title" content="Igneum Devnet 3 faucet">
|
||||
<meta property="og:description" content="Devnet 3 IGN for developers: 10 IGN per address per day, no value, no account.">
|
||||
<meta property="og:url" content="https://igneum.network/faucet">
|
||||
<meta property="og:image" content="https://igneum.network/og.png?v=3">
|
||||
<meta property="og:image:width" content="1200">
|
||||
<meta property="og:image:height" content="630">
|
||||
<meta property="og:image:alt" content="Igneum. Mined by GPUs. Proven by fire.">
|
||||
<meta name="twitter:card" content="summary_large_image">
|
||||
<meta name="twitter:title" content="Igneum testnet faucet">
|
||||
<meta name="twitter:description" content="Testnet IGN for developers and miners: 10 IGN per address per day, no value, no account.">
|
||||
<meta name="twitter:title" content="Igneum Devnet 3 faucet">
|
||||
<meta name="twitter:description" content="Devnet 3 IGN for developers: 10 IGN per address per day, no value, no account.">
|
||||
<meta name="twitter:image" content="https://igneum.network/og.png?v=3">
|
||||
<link rel="icon" href="/favicon.ico" sizes="48x48">
|
||||
<link rel="icon" href="/favicon-32.png" type="image/png" sizes="32x32">
|
||||
|
|
@ -86,9 +86,10 @@ dt{color:var(--ash)}dd{margin:0;font-family:var(--f-mono);font-size:14px;overflo
|
|||
</a>
|
||||
<span class="devnet" id="nav-devnet" title="igneum-devnet-3, chain id 4463. Coins have no value. The chain may reset."><span class="dot off" id="foot-dot"></span><span id="foot-state">devnet</span></span>
|
||||
<div class="nav-groups" id="nav-groups" role="list">
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-mine" data-group="mine" data-active aria-expanded="false" aria-controls="nav-panel-mine" aria-haspopup="true">Mine<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-mine" data-group="mine" aria-expanded="false" aria-controls="nav-panel-mine" aria-haspopup="true">Mine<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-network" data-group="network" aria-expanded="false" aria-controls="nav-panel-network" aria-haspopup="true">Network<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-learn" data-group="learn" aria-expanded="false" aria-controls="nav-panel-learn" aria-haspopup="true">Learn<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-build" data-group="build" data-active aria-expanded="false" aria-controls="nav-panel-build" aria-haspopup="true">Build<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
</div>
|
||||
<div class="nav-controls">
|
||||
<button class="btn icon-btn" type="button" data-theme-toggle aria-label="Switch to light theme"><svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><circle cx="12" cy="12" r="4"/><path d="M12 2v2m0 16v2M2 12h2m16 0h2M5 5l1 1m12 12 1 1M5 19l1-1M18 6l1-1"/></svg></button>
|
||||
|
|
@ -106,7 +107,6 @@ dt{color:var(--ash)}dd{margin:0;font-family:var(--f-mono);font-size:14px;overflo
|
|||
<a href="/wallet" data-nav="wallet"><b>The wallet</b><span>Your coins. Final means final.</span></a>
|
||||
<a href="/miners" data-nav="miners"><b>GPU bench table</b><span>Measured rates, card by card.</span></a>
|
||||
<a href="/dev-fee" data-nav="dev-fee"><b>The dev fee</b><span>The optional one, in full view, off with one flag.</span></a>
|
||||
<a href="/faucet" data-nav="faucet" aria-current="page"><b>Testnet faucet</b><span>Test coin for an address, once a day.</span></a>
|
||||
<a href="/metamask" data-nav="metamask"><b>Add to MetaMask</b><span>Igneum as a network in your wallet.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -117,6 +117,9 @@ dt{color:var(--ash)}dd{margin:0;font-family:var(--f-mono);font-size:14px;overflo
|
|||
<a href="/journey" data-nav="journey"><b>The journey</b><span>Six phases, four gates, the log behind them.</span></a>
|
||||
<a href="/bench" data-nav="bench"><b>Engineering log</b><span>Every measurement, with the commands that made it.</span></a>
|
||||
<a href="/evidence" data-nav="evidence"><b>Evidence</b><span>Every claim and how far it is tested.</span></a>
|
||||
<a href="/light" data-nav="light"><b>Light wallet</b><span>A balance your browser proves, trusting no node.</span></a>
|
||||
<a href="/receipt" data-nav="receipt"><b>Payment receipt</b><span>A receipt any third party re-verifies offline.</span></a>
|
||||
<a href="/oracle" data-nav="oracle"><b>State oracle on Sepolia</b><span>Devnet 3 balances read from another chain.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-panel" id="nav-panel-learn" data-group="learn" role="region" aria-labelledby="nav-btn-learn" hidden>
|
||||
|
|
@ -129,6 +132,14 @@ dt{color:var(--ash)}dd{margin:0;font-family:var(--f-mono);font-size:14px;overflo
|
|||
<a href="/provenance" data-nav="provenance"><b>Built on the shoulders</b><span>Every borrowed part, credited.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-panel" id="nav-panel-build" data-group="build" role="region" aria-labelledby="nav-btn-build" hidden>
|
||||
<div class="panel-list">
|
||||
<a href="/build" data-nav="build"><b>Build on Igneum</b><span>Chain ids, RPC, a contract in five minutes.</span></a>
|
||||
<a href="/faucet" data-nav="faucet" aria-current="page"><b>Devnet faucet</b><span>10 IGN of devnet coin, once a day.</span></a>
|
||||
<a href="/swap" data-nav="swap"><b>Swap</b><span>Test tokens on Devnet 3; every swap is a proven block.</span></a>
|
||||
<a href="/grants" data-nav="grants"><b>Grants</b><span>Tooling, apps, infrastructure, research.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-sheet" id="nav-sheet" role="dialog" aria-modal="true" aria-label="Menu" hidden>
|
||||
|
|
@ -140,7 +151,6 @@ dt{color:var(--ash)}dd{margin:0;font-family:var(--f-mono);font-size:14px;overflo
|
|||
<a href="/wallet" data-nav="wallet"><b>The wallet</b><span>Your coins. Final means final.</span></a>
|
||||
<a href="/miners" data-nav="miners"><b>GPU bench table</b><span>Measured rates, card by card.</span></a>
|
||||
<a href="/dev-fee" data-nav="dev-fee"><b>The dev fee</b><span>The optional one, in full view, off with one flag.</span></a>
|
||||
<a href="/faucet" data-nav="faucet" aria-current="page"><b>Testnet faucet</b><span>Test coin for an address, once a day.</span></a>
|
||||
<a href="/metamask" data-nav="metamask"><b>Add to MetaMask</b><span>Igneum as a network in your wallet.</span></a>
|
||||
</div>
|
||||
<div class="sheet-group"><div class="sheet-head">Network</div>
|
||||
|
|
@ -149,6 +159,9 @@ dt{color:var(--ash)}dd{margin:0;font-family:var(--f-mono);font-size:14px;overflo
|
|||
<a href="/journey" data-nav="journey"><b>The journey</b><span>Six phases, four gates, the log behind them.</span></a>
|
||||
<a href="/bench" data-nav="bench"><b>Engineering log</b><span>Every measurement, with the commands that made it.</span></a>
|
||||
<a href="/evidence" data-nav="evidence"><b>Evidence</b><span>Every claim and how far it is tested.</span></a>
|
||||
<a href="/light" data-nav="light"><b>Light wallet</b><span>A balance your browser proves, trusting no node.</span></a>
|
||||
<a href="/receipt" data-nav="receipt"><b>Payment receipt</b><span>A receipt any third party re-verifies offline.</span></a>
|
||||
<a href="/oracle" data-nav="oracle"><b>State oracle on Sepolia</b><span>Devnet 3 balances read from another chain.</span></a>
|
||||
</div>
|
||||
<div class="sheet-group"><div class="sheet-head">Learn</div>
|
||||
<a href="/litepaper" data-nav="litepaper"><b>Litepaper</b><span>The design, as published.</span></a>
|
||||
|
|
@ -158,6 +171,12 @@ dt{color:var(--ash)}dd{margin:0;font-family:var(--f-mono);font-size:14px;overflo
|
|||
<a href="/randomx" data-nav="randomx"><b>Igneum vs RandomX</b><span>What was kept and what was rebuilt for GPUs.</span></a>
|
||||
<a href="/provenance" data-nav="provenance"><b>Built on the shoulders</b><span>Every borrowed part, credited.</span></a>
|
||||
</div>
|
||||
<div class="sheet-group"><div class="sheet-head">Build</div>
|
||||
<a href="/build" data-nav="build"><b>Build on Igneum</b><span>Chain ids, RPC, a contract in five minutes.</span></a>
|
||||
<a href="/faucet" data-nav="faucet" aria-current="page"><b>Devnet faucet</b><span>10 IGN of devnet coin, once a day.</span></a>
|
||||
<a href="/swap" data-nav="swap"><b>Swap</b><span>Test tokens on Devnet 3; every swap is a proven block.</span></a>
|
||||
<a href="/grants" data-nav="grants"><b>Grants</b><span>Tooling, apps, infrastructure, research.</span></a>
|
||||
</div>
|
||||
<div class="sheet-foot">
|
||||
<a href="/download" class="btn primary big" data-nav="download">Download</a>
|
||||
<div class="sheet-social"><a href="https://discord.gg/igneum" target="_blank" rel="noopener">Discord</a><a href="https://git.igneum.network/igneum-network/spec" target="_blank" rel="noopener">Source</a><a href="https://www.reddit.com/user/Igneum_network/" target="_blank" rel="noopener">Reddit</a></div>
|
||||
|
|
@ -213,16 +232,16 @@ dt{color:var(--ash)}dd{margin:0;font-family:var(--f-mono);font-size:14px;overflo
|
|||
<!-- nav:end -->
|
||||
<main id="main" class="wrap">
|
||||
<div class="head">
|
||||
<div class="breadcrumb"><a href="/">Igneum</a><span>/</span><span>Testnet faucet</span></div>
|
||||
<div class="eyebrow"><span class="line"></span>Testnet faucet</div>
|
||||
<h1>10 IGN a day, <span class="accent">for testing.</span></h1>
|
||||
<p>Paste an address. The faucet sends 10 testnet IGN and shows you the transaction hash. Once per address per day, once per connection per day. No account, no sign-in, nothing to install.</p>
|
||||
<p data-testnet-notice class="notice">Public testnet: not yet open. The faucet is prepared on the devnet and answers "not open yet" until the testnet starts.</p>
|
||||
<div class="breadcrumb"><a href="/">Igneum</a><span>/</span><span>Devnet 3 faucet</span></div>
|
||||
<div class="eyebrow"><span class="line"></span>Devnet 3 faucet</div>
|
||||
<h1>10 IGN a day, <span class="accent">for building.</span></h1>
|
||||
<p>Paste an address. The faucet sends 10 IGN of Devnet 3 coin and shows you the transaction hash. Once per address per day, once per connection per day. No account, no sign-in, nothing to install.</p>
|
||||
<p class="notice" id="faucet-state">Devnet 3, chain id 4463. The coins have no value and the chain resets without notice. <span id="faucet-balance"></span></p>
|
||||
</div>
|
||||
<div class="grid">
|
||||
<section class="card" aria-labelledby="ask">
|
||||
<h2 id="ask">Ask for 10 IGN</h2>
|
||||
<p>An Ethereum-style address: 0x and 40 hex characters. The one the miner made for you, or any wallet you have pointed at the Igneum testnet.</p>
|
||||
<p>An Ethereum-style address: 0x and 40 hex characters. The one <code>cast wallet new</code> printed, the one the miner made for you, or any wallet you have pointed at Devnet 3.</p>
|
||||
<form id="faucet-form" novalidate>
|
||||
<label for="address">Address</label>
|
||||
<input id="address" name="address" inputmode="text" autocomplete="off" spellcheck="false" placeholder="0x…" required pattern="^0x[0-9a-fA-F]{40}$" aria-describedby="status">
|
||||
|
|
@ -233,15 +252,17 @@ dt{color:var(--ash)}dd{margin:0;font-family:var(--f-mono);font-size:14px;overflo
|
|||
<aside class="card" aria-labelledby="rules">
|
||||
<h2 id="rules">The rules</h2>
|
||||
<div class="rules">
|
||||
<div class="rule"><span class="num">01</span><div><b>No value</b><span>Testnet IGN cannot be sold, bought or redeemed, now or at mainnet. Mainnet starts from an empty genesis.</span></div></div>
|
||||
<div class="rule"><span class="num">02</span><div><b>10 IGN per address per day</b><span>And 10 per connection per day. The limit resets 24 hours after the last grant.</span></div></div>
|
||||
<div class="rule"><span class="num">03</span><div><b>Resets</b><span>The chain restarts from a fresh genesis when a consensus rule changes. Balances do not carry over.</span></div></div>
|
||||
<div class="rule"><span class="num">04</span><div><b>What is stored</b><span>The address, the connection's IP, the transaction hash and the time, for 24 hours of rate limiting. Nothing else.</span></div></div>
|
||||
<div class="rule"><span class="num">01</span><div><b>No value</b><span>Devnet IGN cannot be sold, bought or redeemed, now or at mainnet. Mainnet starts from an empty genesis.</span></div></div>
|
||||
<div class="rule"><span class="num">02</span><div><b>10 IGN per address per day</b><span>And 10 per connection per day, 500 sends a day in all. The limit resets 24 hours after the last send.</span></div></div>
|
||||
<div class="rule"><span class="num">03</span><div><b>Resets</b><span>Devnet 3 is a developer network. It restarts from a fresh genesis without notice. Balances do not carry over.</span></div></div>
|
||||
<div class="rule"><span class="num">04</span><div><b>What is stored</b><span>The address, the connection's IP, the transaction hash and the time, on the box that runs the faucet, for 24 hours of rate limiting. Nothing else.</span></div></div>
|
||||
</div>
|
||||
<dl>
|
||||
<dt>Chain id</dt><dd>4462 (testnet), 4463 (devnet)</dd>
|
||||
<dt>Chain id</dt><dd>4463 (Devnet 3)</dd>
|
||||
<dt>RPC</dt><dd>https://rpc.devnet.igneum.network</dd>
|
||||
<dt>Wallet set-up</dt><dd><a href="/metamask">MetaMask: chain id, RPC, one click</a></dd>
|
||||
<dt>Mine instead</dt><dd><a href="/miner#get">Get the miner</a></dd>
|
||||
<dt>Then</dt><dd><a href="/build">Deploy a contract in five minutes</a></dd>
|
||||
<dt>Testnet</dt><dd>its faucet opens with the public testnet</dd>
|
||||
</dl>
|
||||
</aside>
|
||||
</div>
|
||||
|
|
@ -268,7 +289,7 @@ dt{color:var(--ash)}dd{margin:0;font-family:var(--f-mono);font-size:14px;overflo
|
|||
<a href="/wallet">The wallet</a>
|
||||
<a href="/miners">GPU bench table</a>
|
||||
<a href="/dev-fee">The dev fee</a>
|
||||
<a href="/faucet">Testnet faucet</a>
|
||||
<a href="/faucet">Devnet faucet</a>
|
||||
<a href="/metamask">Add Igneum to MetaMask</a>
|
||||
</div></div>
|
||||
<div class="footer-column"><h4>Read</h4><div>
|
||||
|
|
@ -283,6 +304,9 @@ dt{color:var(--ash)}dd{margin:0;font-family:var(--f-mono);font-size:14px;overflo
|
|||
<div class="footer-column"><h4>Explore</h4><div>
|
||||
<a href="/live">Live devnet</a>
|
||||
<a href="/explorer">Explorer</a>
|
||||
<a href="/build">Build on Igneum</a>
|
||||
<a href="/swap">Swap</a>
|
||||
<a href="/grants">Grants</a>
|
||||
<a href="/journey">Journey</a>
|
||||
<a href="/download">Downloads: devnet build</a>
|
||||
<a href="https://discord.gg/igneum" target="_blank" rel="noopener">Community Discord</a>
|
||||
|
|
@ -315,17 +339,20 @@ dt{color:var(--ash)}dd{margin:0;font-family:var(--f-mono);font-size:14px;overflo
|
|||
<!-- footer:end -->
|
||||
<script>
|
||||
(function(){
|
||||
var form=document.getElementById('faucet-form'),input=document.getElementById('address'),btn=document.getElementById('send'),out=document.getElementById('status');
|
||||
// the faucet service runs on a build box behind Caddy (infra/build-server/faucet), not on the site's host
|
||||
var FAUCET='https://faucet.igneum.network/api/faucet';
|
||||
var form=document.getElementById('faucet-form'),input=document.getElementById('address'),btn=document.getElementById('send'),out=document.getElementById('status'),bal=document.getElementById('faucet-balance');
|
||||
fetch(FAUCET,{cache:'no-store'}).then(function(r){return r.json();}).then(function(d){if(!d||!d.ok)return;if(d.balance_ign!==null&&d.balance_ign!==undefined){bal.textContent=d.funded?('The faucet holds '+Math.floor(Number(d.balance_ign)).toLocaleString('en-GB')+' IGN; '+d.sends_24h+' sends in the last 24 hours.'):'The faucet is being refilled; try again in an hour.';}}).catch(function(){});
|
||||
function say(text,state,html){out.setAttribute('data-state',state||'');if(html){out.innerHTML=html;}else{out.textContent=text;}}
|
||||
form.addEventListener('submit',function(e){
|
||||
e.preventDefault();
|
||||
var a=input.value.trim();
|
||||
if(!/^0x[0-9a-fA-F]{40}$/.test(a)){say('That is not an address. It is 0x followed by 40 hex characters.','bad');input.focus();return;}
|
||||
btn.disabled=true;say('Sending…','');
|
||||
fetch('/api/faucet',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({address:a})})
|
||||
fetch(FAUCET,{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({address:a})})
|
||||
.then(function(r){return r.json().then(function(j){return {status:r.status,body:j};});})
|
||||
.then(function(r){
|
||||
if(r.body&&r.body.ok){var h=String(r.body.tx||'');say('',"ok",'Sent 10 IGN. Transaction <code>'+h.replace(/[^0-9a-fx]/gi,'')+'</code>. It is in a block within a few seconds.');}
|
||||
if(r.body&&r.body.ok){var h=String(r.body.tx||'').replace(/[^0-9a-fx]/gi,'');say('',"ok",'Sent 10 IGN. Transaction <code>'+h+'</code>. It is in a block within a few seconds. <a href="/explorer">Paste it into the explorer</a>.');}
|
||||
else{say((r.body&&r.body.error)||('The faucet answered '+r.status+'.'),'bad');}
|
||||
})
|
||||
.catch(function(){say('The faucet did not answer. Try again in a minute.','bad');})
|
||||
|
|
|
|||
342
site/grants.html
Normal file
342
site/grants.html
Normal file
|
|
@ -0,0 +1,342 @@
|
|||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
|
||||
<title>Igneum grants: tooling, reference apps, infrastructure, research</title>
|
||||
<meta name="description" content="The Igneum grants programme: four tiers, what a grant is, how to apply with an issue on the git host, the weekly review, and the lines that stay honest about value, amounts and dates.">
|
||||
<link rel="canonical" href="https://igneum.network/grants">
|
||||
<meta name="theme-color" content="#0C0C0E">
|
||||
<meta property="og:type" content="website">
|
||||
<meta property="og:site_name" content="Igneum">
|
||||
<meta property="og:title" content="Igneum grants: tooling, reference apps, infrastructure, research">
|
||||
<meta property="og:description" content="The Igneum grants programme: four tiers, what a grant is, how to apply with an issue on the git host, the weekly review, and the lines that stay honest about value, amounts and dates.">
|
||||
<meta property="og:url" content="https://igneum.network/grants">
|
||||
<meta property="og:image" content="https://igneum.network/og.png?v=3">
|
||||
<meta property="og:image:width" content="1200">
|
||||
<meta property="og:image:height" content="630">
|
||||
<meta property="og:image:alt" content="Igneum. Mined by GPUs. Proven by fire.">
|
||||
<meta name="twitter:card" content="summary_large_image">
|
||||
<meta name="twitter:title" content="Igneum grants: tooling, reference apps, infrastructure, research">
|
||||
<meta name="twitter:description" content="The Igneum grants programme: four tiers, what a grant is, how to apply with an issue on the git host, the weekly review, and the lines that stay honest about value, amounts and dates.">
|
||||
<meta name="twitter:image" content="https://igneum.network/og.png?v=3">
|
||||
<meta name="twitter:image:alt" content="Igneum. Mined by GPUs. Proven by fire.">
|
||||
<link rel="icon" href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1024 1024'%3E%3Crect width='1024' height='1024' fill='%230C0C0E'/%3E%3Cg transform='translate(166.95 166.95) scale(6.901)'%3E%3Cpolygon points='50,4 74,34 67,58 80,54 61,96 39,96 20,54 33,58 26,34' fill='%23F2541B'/%3E%3Cpolygon points='50,42 59,58 50,82 41,58' fill='%230C0C0E'/%3E%3C/g%3E%3C/svg%3E" type="image/svg+xml">
|
||||
<link rel="icon" href="/favicon.ico" sizes="48x48">
|
||||
<link rel="icon" href="/favicon-32.png" type="image/png" sizes="32x32">
|
||||
<link rel="icon" href="/icon-192.png" type="image/png" sizes="192x192">
|
||||
<link rel="icon" href="/icon-512.png" type="image/png" sizes="512x512">
|
||||
<link rel="apple-touch-icon" href="/apple-touch-icon.png" sizes="180x180">
|
||||
<link rel="manifest" href="/site.webmanifest">
|
||||
<!-- head:start -->
|
||||
<link rel="preload" href="/fonts/unbounded-900.woff2" as="font" type="font/woff2" crossorigin>
|
||||
<link rel="preload" href="/fonts/plex-sans-400.woff2" as="font" type="font/woff2" crossorigin>
|
||||
<meta name="color-scheme" content="dark light">
|
||||
<link rel="stylesheet" href="/site.css">
|
||||
<style>
|
||||
/* Shared by every page: the head partial, injected by the build between the head markers. Edit the partial, not the page. */
|
||||
/* Fonts, self-hosted (latin subsets, OFL): Unbounded 500/700/900, IBM Plex Sans 400/500/600, IBM Plex Mono 400/500. Fallbacks carry size and ascent overrides so the swap does not move the layout. The tokens, type and components are in /site.css (docs/plans/site-ui-3.md). */
|
||||
@font-face{font-family:'Unbounded';font-style:normal;font-weight:500;font-display:swap;src:url(/fonts/unbounded-500.woff2) format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
|
||||
@font-face{font-family:'Unbounded';font-style:normal;font-weight:700;font-display:swap;src:url(/fonts/unbounded-700.woff2) format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
|
||||
@font-face{font-family:'Unbounded';font-style:normal;font-weight:900;font-display:swap;src:url(/fonts/unbounded-900.woff2) format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
|
||||
@font-face{font-family:'IBM Plex Sans';font-style:normal;font-weight:400;font-display:swap;src:url(/fonts/plex-sans-400.woff2) format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
|
||||
@font-face{font-family:'IBM Plex Sans';font-style:normal;font-weight:500;font-display:swap;src:url(/fonts/plex-sans-500.woff2) format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
|
||||
@font-face{font-family:'IBM Plex Sans';font-style:normal;font-weight:600;font-display:swap;src:url(/fonts/plex-sans-600.woff2) format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
|
||||
@font-face{font-family:'IBM Plex Mono';font-style:normal;font-weight:400;font-display:swap;src:url(/fonts/plex-mono-400.woff2) format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
|
||||
@font-face{font-family:'IBM Plex Mono';font-style:normal;font-weight:500;font-display:swap;src:url(/fonts/plex-mono-500.woff2) format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
|
||||
@font-face{font-family:'Unbounded Fallback';src:local('Arial Black'),local('Arial-Black'),local('Impact');size-adjust:114%;ascent-override:87.5%;descent-override:21.5%;line-gap-override:0%}
|
||||
@font-face{font-family:'Plex Sans Fallback';src:local('Arial'),local('Helvetica Neue'),local('Helvetica');size-adjust:100.5%;ascent-override:102%;descent-override:27.4%;line-gap-override:0%}
|
||||
@font-face{font-family:'Plex Mono Fallback';src:local('Courier New'),local('Menlo');size-adjust:100%;ascent-override:102.5%;descent-override:27.5%;line-gap-override:0%}
|
||||
</style>
|
||||
<script>
|
||||
/* theme before first paint: ?theme=light|dark for one view (the capture tool), else the stored choice under igneum-theme, else the system setting; ?motion=off marks the page data-motion=off so every .reveal is drawn at once (a headless render never scrolls) */
|
||||
(function(){var t=null;try{t=new URLSearchParams(location.search).get("theme");}catch(e){}if(t!=="light"&&t!=="dark"){try{t=localStorage.getItem("igneum-theme");}catch(e){t=null;}}if(t!=="light"&&t!=="dark")t=window.matchMedia&&window.matchMedia("(prefers-color-scheme: light)").matches?"light":"dark";document.documentElement.setAttribute("data-theme",t);try{if(new URLSearchParams(location.search).get("motion")==="off")document.documentElement.setAttribute("data-motion","off");}catch(e){}})();
|
||||
</script>
|
||||
<!-- head:end -->
|
||||
<style>
|
||||
/* generated-page block (the engineering log, the bench table, the provenance table): the page hero, the contents rail, the sections; tokens, type and components are in /site.css */
|
||||
[id]{scroll-margin-top:120px}
|
||||
article h1{display:none}
|
||||
article{color:var(--ink-2)}
|
||||
article h2{font-size:var(--t-h3);margin:0 0 12px}
|
||||
article h3{font-size:16px;margin:26px 0 8px}
|
||||
article h4{font:600 15px/1.4 var(--f-sans);margin:20px 0 6px;color:var(--bone)}
|
||||
article p{margin:0 0 14px}article ul,article ol{margin:0 0 14px;padding-left:22px}article li{margin-bottom:6px}
|
||||
article p,article li,article h2,article h3{overflow-wrap:anywhere}
|
||||
article pre{margin:0 0 var(--s-4)}
|
||||
.doc-section:last-child{border-bottom:0}
|
||||
.doc-section[hidden]{display:none}
|
||||
.tbl{margin:var(--s-4) 0 var(--s-5)}
|
||||
table{min-width:560px}
|
||||
.gen{color:var(--ash);font-size:13px;margin:40px 0 0;max-width:72ch}
|
||||
.doc-tools{margin:0 0 var(--s-5)}
|
||||
.doc-tools .searchbar{max-width:560px}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<!-- nav:start -->
|
||||
<a class="skip" href="#main">Skip to content</a>
|
||||
<nav class="nav" aria-label="Main" data-nav-version="5">
|
||||
<div class="container nav-row">
|
||||
<a href="/" class="logo" aria-label="Igneum home">
|
||||
<svg class="brand-mark" viewBox="0 0 1024 1024" aria-hidden="true"><rect width="1024" height="1024" rx="160" fill="#0C0C0E"></rect><g transform="translate(166.95 166.95) scale(6.901)"><polygon points="50,4 74,34 67,58 80,54 61,96 39,96 20,54 33,58 26,34" fill="#F2541B"></polygon><polygon points="50,42 59,58 50,82 41,58" fill="#0C0C0E"></polygon></g></svg>
|
||||
<span class="word">IGNEUM</span>
|
||||
</a>
|
||||
<span class="devnet" id="nav-devnet" title="igneum-devnet-3, chain id 4463. Coins have no value. The chain may reset."><span class="dot off" id="foot-dot"></span><span id="foot-state">devnet</span></span>
|
||||
<div class="nav-groups" id="nav-groups" role="list">
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-mine" data-group="mine" aria-expanded="false" aria-controls="nav-panel-mine" aria-haspopup="true">Mine<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-network" data-group="network" aria-expanded="false" aria-controls="nav-panel-network" aria-haspopup="true">Network<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-learn" data-group="learn" aria-expanded="false" aria-controls="nav-panel-learn" aria-haspopup="true">Learn<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-build" data-group="build" data-active aria-expanded="false" aria-controls="nav-panel-build" aria-haspopup="true">Build<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
</div>
|
||||
<div class="nav-controls">
|
||||
<button class="btn icon-btn" type="button" data-theme-toggle aria-label="Switch to light theme"><svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><circle cx="12" cy="12" r="4"/><path d="M12 2v2m0 16v2M2 12h2m16 0h2M5 5l1 1m12 12 1 1M5 19l1-1M18 6l1-1"/></svg></button>
|
||||
<a href="/download" class="btn primary small cta" data-nav="download">Download</a>
|
||||
<button class="burger" id="nav-burger" type="button" aria-expanded="false" aria-controls="nav-sheet" aria-label="Open the menu" aria-haspopup="true"><svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path class="bars" d="M4 6h16M4 12h16M4 18h16"/><path class="cross" d="m6 6 12 12M6 18 18 6"/></svg></button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="panels" id="nav-panels">
|
||||
<div class="panel-wrap container">
|
||||
<div class="nav-panel" id="nav-panel-mine" data-group="mine" role="region" aria-labelledby="nav-btn-mine" hidden>
|
||||
<div class="panel-list">
|
||||
<a href="/miner" data-nav="miner"><b>Ember, the miner</b><span>One click installs the node, the miner and the prover.</span></a>
|
||||
<a href="/download" data-nav="download"><b>Download</b><span>Windows, macOS, Linux and HiveOS.</span></a>
|
||||
<a href="/app" data-nav="app"><b>The app</b><span>What you see while the card mines.</span></a>
|
||||
<a href="/wallet" data-nav="wallet"><b>The wallet</b><span>Your coins. Final means final.</span></a>
|
||||
<a href="/miners" data-nav="miners"><b>GPU bench table</b><span>Measured rates, card by card.</span></a>
|
||||
<a href="/dev-fee" data-nav="dev-fee"><b>The dev fee</b><span>The optional one, in full view, off with one flag.</span></a>
|
||||
<a href="/metamask" data-nav="metamask"><b>Add to MetaMask</b><span>Igneum as a network in your wallet.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-panel" id="nav-panel-network" data-group="network" role="region" aria-labelledby="nav-btn-network" hidden>
|
||||
<div class="panel-list">
|
||||
<a href="/live" data-nav="live"><b>Live devnet</b><span>The chain as it grows, one lane per miner.</span></a>
|
||||
<a href="/explorer" data-nav="explorer"><b>Explorer</b><span>Look a block or an address up.</span></a>
|
||||
<a href="/journey" data-nav="journey"><b>The journey</b><span>Six phases, four gates, the log behind them.</span></a>
|
||||
<a href="/bench" data-nav="bench"><b>Engineering log</b><span>Every measurement, with the commands that made it.</span></a>
|
||||
<a href="/evidence" data-nav="evidence"><b>Evidence</b><span>Every claim and how far it is tested.</span></a>
|
||||
<a href="/light" data-nav="light"><b>Light wallet</b><span>A balance your browser proves, trusting no node.</span></a>
|
||||
<a href="/receipt" data-nav="receipt"><b>Payment receipt</b><span>A receipt any third party re-verifies offline.</span></a>
|
||||
<a href="/oracle" data-nav="oracle"><b>State oracle on Sepolia</b><span>Devnet 3 balances read from another chain.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-panel" id="nav-panel-learn" data-group="learn" role="region" aria-labelledby="nav-btn-learn" hidden>
|
||||
<div class="panel-list">
|
||||
<a href="/litepaper" data-nav="litepaper"><b>Litepaper</b><span>The design, as published.</span></a>
|
||||
<a href="/income" data-nav="income"><b>Income per tier</b><span>IGN a day per card at three network sizes, and the electricity.</span></a>
|
||||
<a href="/ledger" data-nav="ledger"><b>Ledger</b><span>Every criticism, answered or conceded.</span></a>
|
||||
<a href="/claims" data-nav="claims"><b>What Igneum does not claim</b><span>The limits, stated first.</span></a>
|
||||
<a href="/randomx" data-nav="randomx"><b>Igneum vs RandomX</b><span>What was kept and what was rebuilt for GPUs.</span></a>
|
||||
<a href="/provenance" data-nav="provenance"><b>Built on the shoulders</b><span>Every borrowed part, credited.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-panel" id="nav-panel-build" data-group="build" role="region" aria-labelledby="nav-btn-build" hidden>
|
||||
<div class="panel-list">
|
||||
<a href="/build" data-nav="build"><b>Build on Igneum</b><span>Chain ids, RPC, a contract in five minutes.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Devnet faucet</b><span>10 IGN of devnet coin, once a day.</span></a>
|
||||
<a href="/swap" data-nav="swap"><b>Swap</b><span>Test tokens on Devnet 3; every swap is a proven block.</span></a>
|
||||
<a href="/grants" data-nav="grants" aria-current="page"><b>Grants</b><span>Tooling, apps, infrastructure, research.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-sheet" id="nav-sheet" role="dialog" aria-modal="true" aria-label="Menu" hidden>
|
||||
<div class="sheet-scroll">
|
||||
<div class="sheet-group"><div class="sheet-head">Mine</div>
|
||||
<a href="/miner" data-nav="miner"><b>Ember, the miner</b><span>One click installs the node, the miner and the prover.</span></a>
|
||||
<a href="/download" data-nav="download"><b>Download</b><span>Windows, macOS, Linux and HiveOS.</span></a>
|
||||
<a href="/app" data-nav="app"><b>The app</b><span>What you see while the card mines.</span></a>
|
||||
<a href="/wallet" data-nav="wallet"><b>The wallet</b><span>Your coins. Final means final.</span></a>
|
||||
<a href="/miners" data-nav="miners"><b>GPU bench table</b><span>Measured rates, card by card.</span></a>
|
||||
<a href="/dev-fee" data-nav="dev-fee"><b>The dev fee</b><span>The optional one, in full view, off with one flag.</span></a>
|
||||
<a href="/metamask" data-nav="metamask"><b>Add to MetaMask</b><span>Igneum as a network in your wallet.</span></a>
|
||||
</div>
|
||||
<div class="sheet-group"><div class="sheet-head">Network</div>
|
||||
<a href="/live" data-nav="live"><b>Live devnet</b><span>The chain as it grows, one lane per miner.</span></a>
|
||||
<a href="/explorer" data-nav="explorer"><b>Explorer</b><span>Look a block or an address up.</span></a>
|
||||
<a href="/journey" data-nav="journey"><b>The journey</b><span>Six phases, four gates, the log behind them.</span></a>
|
||||
<a href="/bench" data-nav="bench"><b>Engineering log</b><span>Every measurement, with the commands that made it.</span></a>
|
||||
<a href="/evidence" data-nav="evidence"><b>Evidence</b><span>Every claim and how far it is tested.</span></a>
|
||||
<a href="/light" data-nav="light"><b>Light wallet</b><span>A balance your browser proves, trusting no node.</span></a>
|
||||
<a href="/receipt" data-nav="receipt"><b>Payment receipt</b><span>A receipt any third party re-verifies offline.</span></a>
|
||||
<a href="/oracle" data-nav="oracle"><b>State oracle on Sepolia</b><span>Devnet 3 balances read from another chain.</span></a>
|
||||
</div>
|
||||
<div class="sheet-group"><div class="sheet-head">Learn</div>
|
||||
<a href="/litepaper" data-nav="litepaper"><b>Litepaper</b><span>The design, as published.</span></a>
|
||||
<a href="/income" data-nav="income"><b>Income per tier</b><span>IGN a day per card at three network sizes, and the electricity.</span></a>
|
||||
<a href="/ledger" data-nav="ledger"><b>Ledger</b><span>Every criticism, answered or conceded.</span></a>
|
||||
<a href="/claims" data-nav="claims"><b>What Igneum does not claim</b><span>The limits, stated first.</span></a>
|
||||
<a href="/randomx" data-nav="randomx"><b>Igneum vs RandomX</b><span>What was kept and what was rebuilt for GPUs.</span></a>
|
||||
<a href="/provenance" data-nav="provenance"><b>Built on the shoulders</b><span>Every borrowed part, credited.</span></a>
|
||||
</div>
|
||||
<div class="sheet-group"><div class="sheet-head">Build</div>
|
||||
<a href="/build" data-nav="build"><b>Build on Igneum</b><span>Chain ids, RPC, a contract in five minutes.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Devnet faucet</b><span>10 IGN of devnet coin, once a day.</span></a>
|
||||
<a href="/swap" data-nav="swap"><b>Swap</b><span>Test tokens on Devnet 3; every swap is a proven block.</span></a>
|
||||
<a href="/grants" data-nav="grants" aria-current="page"><b>Grants</b><span>Tooling, apps, infrastructure, research.</span></a>
|
||||
</div>
|
||||
<div class="sheet-foot">
|
||||
<a href="/download" class="btn primary big" data-nav="download">Download</a>
|
||||
<div class="sheet-social"><a href="https://discord.gg/igneum" target="_blank" rel="noopener">Discord</a><a href="https://git.igneum.network/igneum-network/spec" target="_blank" rel="noopener">Source</a><a href="https://www.reddit.com/user/Igneum_network/" target="_blank" rel="noopener">Reddit</a></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
<script>
|
||||
(function(){
|
||||
// the slim bar (site-ui-5, 7 Oct 2026): three group buttons open one panel each; the burger opens the sheet on phones.
|
||||
// Keyboard: Enter or Space opens a group, Escape closes it and returns focus to its button, arrows move between the
|
||||
// group buttons, Tab walks the open panel's links, a click outside closes. The theme toggle flips data-theme and stores it.
|
||||
var n=document.querySelector('.nav');if(!n)return;
|
||||
var btns=[].slice.call(n.querySelectorAll('.group-btn')),panels=[].slice.call(n.querySelectorAll('.nav-panel')),wrap=n.querySelector('.panels');
|
||||
var burger=document.getElementById('nav-burger'),sheet=document.getElementById('nav-sheet');
|
||||
function panelOf(g){return panels.filter(function(p){return p.getAttribute('data-group')===g;})[0];}
|
||||
function closeAll(focusBack){var was=null;btns.forEach(function(b){if(b.getAttribute('aria-expanded')==='true')was=b;b.setAttribute('aria-expanded','false');});panels.forEach(function(p){p.hidden=true;});n.classList.remove('panel-open');if(focusBack&&was)was.focus();}
|
||||
function open(g){closeAll(false);var b=btns.filter(function(x){return x.getAttribute('data-group')===g;})[0],p=panelOf(g);if(!b||!p)return;b.setAttribute('aria-expanded','true');p.hidden=false;n.classList.add('panel-open');anchor(b,p);}
|
||||
// the panel sits under its button; a panel that would run past the container's right edge aligns its right edge to the button's right edge instead (never past the viewport)
|
||||
function anchor(b,p){var pw=n.querySelector('.panel-wrap');if(!pw)return;var cr=pw.getBoundingClientRect(),br=b.getBoundingClientRect(),w=p.offsetWidth,left=br.left-cr.left;if(left+w>cr.width)left=(br.right-cr.left)-w;if(left<0)left=0;p.style.setProperty('--panel-left',Math.round(left)+'px');}
|
||||
window.addEventListener('resize',function(){var o=btns.filter(function(x){return x.getAttribute('aria-expanded')==='true';})[0];if(o)anchor(o,panelOf(o.getAttribute('data-group')));}); btns.forEach(function(b,i){
|
||||
b.addEventListener('click',function(){var on=b.getAttribute('aria-expanded')==='true';if(on)closeAll(false);else open(b.getAttribute('data-group'));});
|
||||
b.addEventListener('keydown',function(e){
|
||||
var k=e.key;
|
||||
if(k==='ArrowRight'||k==='ArrowLeft'){e.preventDefault();var j=(i+(k==='ArrowRight'?1:btns.length-1))%btns.length;btns[j].focus();if(n.classList.contains('panel-open'))open(btns[j].getAttribute('data-group'));}
|
||||
else if(k==='ArrowDown'){e.preventDefault();open(b.getAttribute('data-group'));var f=panelOf(b.getAttribute('data-group')).querySelector('a');if(f)f.focus();}
|
||||
else if(k==='Escape'){closeAll(true);}
|
||||
});
|
||||
});
|
||||
if(wrap)wrap.addEventListener('keydown',function(e){if(e.key==='Escape'){e.stopPropagation();closeAll(true);}});
|
||||
document.addEventListener('click',function(e){if(!n.classList.contains('panel-open'))return;if(e.target.closest('.group-btn')||e.target.closest('.nav-panel'))return;closeAll(false);});
|
||||
document.addEventListener('focusin',function(e){if(!n.classList.contains('panel-open'))return;if(n.contains(e.target))return;closeAll(false);});
|
||||
document.addEventListener('keydown',function(e){if(e.key==='Escape'&&n.classList.contains('panel-open'))closeAll(true);});
|
||||
// the sheet on phones
|
||||
function setSheet(o){if(!burger||!sheet)return;n.classList.toggle('open',o);sheet.hidden=!o;burger.setAttribute('aria-expanded',o?'true':'false');burger.setAttribute('aria-label',o?'Close the menu':'Open the menu');document.documentElement.classList.toggle('nav-locked',o);if(o){var f=sheet.querySelector('a');if(f)f.focus();}}
|
||||
if(burger&&sheet){
|
||||
burger.addEventListener('click',function(){setSheet(!n.classList.contains('open'));});
|
||||
sheet.addEventListener('click',function(e){if(e.target.closest('a'))setSheet(false);});
|
||||
sheet.addEventListener('keydown',function(e){
|
||||
if(e.key==='Escape'){setSheet(false);burger.focus();return;}
|
||||
if(e.key!=='Tab')return;var f=sheet.querySelectorAll('a,button');if(!f.length)return;var first=f[0],last=f[f.length-1];
|
||||
if(e.shiftKey&&document.activeElement===first){e.preventDefault();burger.focus();}else if(!e.shiftKey&&document.activeElement===last){e.preventDefault();burger.focus();}
|
||||
});
|
||||
burger.addEventListener('keydown',function(e){if(e.key==='Tab'&&!e.shiftKey&&n.classList.contains('open')){e.preventDefault();var f=sheet.querySelector('a');if(f)f.focus();}});
|
||||
var mq=window.matchMedia('(min-width:861px)');if(mq.addEventListener)mq.addEventListener('change',function(){setSheet(false);});
|
||||
}
|
||||
// the theme toggle
|
||||
var t=n.querySelector('[data-theme-toggle]');
|
||||
function paintToggle(){var dark=document.documentElement.getAttribute('data-theme')!=='light';t.setAttribute('aria-label',dark?'Switch to light theme':'Switch to dark theme');t.innerHTML=dark?'<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><circle cx="12" cy="12" r="4"/><path d="M12 2v2m0 16v2M2 12h2m16 0h2M5 5l1 1m12 12 1 1M5 19l1-1M18 6l1-1"/></svg>':'<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="M20.7 13.3A8.5 8.5 0 0 1 10.7 3.3 8.5 8.5 0 1 0 20.7 13.3Z"/></svg>';}
|
||||
if(t){t.addEventListener('click',function(){var v=document.documentElement.getAttribute('data-theme')==='light'?'dark':'light';document.documentElement.setAttribute('data-theme',v);try{localStorage.setItem('igneum-theme',v);}catch(e){}document.dispatchEvent(new CustomEvent('igneum-theme'));});paintToggle();document.addEventListener('igneum-theme',paintToggle);}
|
||||
})();
|
||||
</script>
|
||||
<!-- nav:end -->
|
||||
<main id="main">
|
||||
<section class="page-hero">
|
||||
<div class="container">
|
||||
<div class="breadcrumb"><a href="/">Igneum</a><span>/</span><span>Grants</span></div>
|
||||
<div class="page-heading"><div><div class="eyebrow"><span class="line"></span>The programme</div>
|
||||
<h1>Grants</h1>
|
||||
<p class="lead">Paid in IGN from the dev fee fund, on delivery, on the public testnet first. Four tiers. One issue to apply. A weekly review.</p></div></div>
|
||||
</div>
|
||||
</section>
|
||||
<section class="section compact"><div class="container">
|
||||
|
||||
<div class="docs-layout">
|
||||
<nav class="doc-nav" aria-label="Contents"><div class="eyebrow">Contents</div><a href="#what-a-grant-is">What a grant is</a><a href="#the-tiers">The tiers</a><a href="#how-to-apply">How to apply</a><a href="#the-review">The review</a><a href="#the-honest-lines">The honest lines</a></nav>
|
||||
<article class="doc-body" data-filter-list="grants"><section class="doc-section"><h1 id="grants">Grants</h1>
|
||||
<p>This file is the source of <a href="https://igneum.network/grants" rel="noopener">igneum.network/grants</a>.</p>
|
||||
</section>
|
||||
<section class="doc-section"><h2 id="what-a-grant-is">What a grant is</h2>
|
||||
<p>Grants are paid in IGN from the dev fee fund, on delivery. You propose a piece of work, it is accepted with a written definition of done, you build it, and it runs on the public testnet. Not a salary, not an advance, not an investment.</p>
|
||||
<p>The money is the dev fee fund: the IGN that the Ember dev fee collects. Ember, the official miner, takes an optional 1% of a miner's rewards, in full view and off with one flag; that fee goes to Igneum Labs, the company that ships the software. The protocol itself carries no fee, no fund and no allocation, and no grant is paid from emission. <a href="/dev-fee">The dev fee</a> has the mechanism.</p>
|
||||
</section>
|
||||
<section class="doc-section"><h2 id="the-tiers">The tiers</h2>
|
||||
<div class="tbl"><table><thead><tr><th>Tier</th><th>What fits</th></tr></thead><tbody><tr><td>Tooling</td><td>SDK bindings, indexers, a Hardhat or Foundry plugin for the two gas dimensions, verification tooling, a light client in another language</td></tr><tr><td>Reference apps</td><td>A token, a swap, a registry, a wallet integration, an app that uses <code>igneum_getTransactionStatus</code> and the lock the way it is meant to be used</td></tr><tr><td>Infrastructure</td><td>RPC providers, archive nodes, seed nodes in new regions, pool software, an explorer back end</td></tr><tr><td>Research</td><td>The lottery hash, the finality rule, the proving layer, the fee model; attacks on the public test vectors; measurements the project does not have</td></tr></tbody></table></div>
|
||||
<p>A grant is sized by the work in front of it, not by a table. Two grants in the same tier can differ.</p>
|
||||
</section>
|
||||
<section class="doc-section"><h2 id="how-to-apply">How to apply</h2>
|
||||
<p>Open an issue on <a href="https://git.igneum.network/igneum-network/igneum/issues/new?template=.forgejo%2Fissue_template%2Fgrant.md" rel="noopener">git.igneum.network/igneum-network/igneum</a> and pick the Grant template. It asks for:</p>
|
||||
<ol><li>What you will build, in a paragraph, and which tier it is.</li><li>What done looks like: what runs where, what a reviewer can click or call to see it working on the public testnet.</li><li>Your public work: a repository, a package, a paper, a deployed thing.</li><li>How you want to be reached.</li></ol>
|
||||
<p>A short issue is fine. The definition of done is the part that matters.</p>
|
||||
</section>
|
||||
<section class="doc-section"><h2 id="the-review">The review</h2>
|
||||
<ul><li>Every Friday. Each open application gets one of three answers inside seven days: accepted with a definition of done, questions, or no with the reason.</li><li>Accepted work is tracked in its issue. The reviewer and the builder agree the definition of done there before any work starts.</li><li>Delivery is reviewed on the public testnet first. Payment follows the review, in the issue, in the open.</li></ul>
|
||||
</section>
|
||||
<section class="doc-section"><h2 id="the-honest-lines">The honest lines</h2>
|
||||
<ul><li>Devnet and testnet coins have no value. Before mainnet there is no IGN with value: a grant delivered on the testnet is recorded in its issue, and payment comes from the fund when the fund holds IGN. Nothing is promised about when, or whether, that is.</li><li>No amount, price or date is promised. The fund is what the dev fee collects, and it is zero today.</li><li>A grant is for work delivered, never for a user count, a listing, a post or a referral.</li><li>Igneum Labs may decline any application and may close the programme; what has been accepted and delivered is still paid.</li></ul>
|
||||
<p>Not legal advice.</p></section></article>
|
||||
</div>
|
||||
<p class="gen">Generated from docs/build/grants.md in the repository at build time. Times are UTC.</p>
|
||||
</div></section>
|
||||
</main>
|
||||
<!-- footer:start -->
|
||||
<footer class="site-footer">
|
||||
<div class="container">
|
||||
<div class="footer-grid">
|
||||
<div class="footer-brand">
|
||||
<a href="/" class="logo" aria-label="Igneum home"><svg class="brand-mark" viewBox="0 0 1024 1024" aria-hidden="true"><rect width="1024" height="1024" rx="160" fill="#0C0C0E"></rect><g transform="translate(166.95 166.95) scale(6.901)"><polygon points="50,4 74,34 67,58 80,54 61,96 39,96 20,54 33,58 26,34" fill="#F2541B"></polygon><polygon points="50,42 59,58 50,82 41,58" fill="#0C0C0E"></polygon></g></svg><span class="word">IGNEUM</span><span class="stop">.</span></a>
|
||||
<p>Mined by GPUs. Proven by fire.</p>
|
||||
<div class="social" aria-label="Igneum elsewhere">
|
||||
<a href="https://git.igneum.network/igneum-network/spec" target="_blank" rel="noopener" aria-label="Igneum source: the spec, the vectors and the issues"><svg viewBox="0 0 24 24" width="22" height="22" fill="currentColor" aria-hidden="true"><path d="M8.6 17.6 3 12l5.6-5.6 1.4 1.4L5.8 12l4.2 4.2zm6.8 0-1.4-1.4L18.2 12 14 7.8l1.4-1.4L21 12z"></path></svg></a>
|
||||
<a href="https://discord.gg/igneum" target="_blank" rel="noopener" aria-label="The Igneum Discord"><svg viewBox="0 0 24 24" width="22" height="22" fill="currentColor" aria-hidden="true"><path d="M19.6 5.3A17 17 0 0 0 15.4 4l-.2.4a15.6 15.6 0 0 1 3.9 1.9 13.6 13.6 0 0 0-14.2 0A15.6 15.6 0 0 1 8.8 4.4L8.6 4a17 17 0 0 0-4.2 1.3C1.8 9.2 1.1 13 1.4 16.7a17.1 17.1 0 0 0 5.2 2.6l1.1-1.8a10.8 10.8 0 0 1-1.7-.8l.4-.3a12.2 12.2 0 0 0 11.2 0l.4.3-1.7.8 1.1 1.8a17 17 0 0 0 5.2-2.6c.4-4.3-.7-8-3-11.4zM8.7 14.4c-1 0-1.8-.9-1.8-2.1s.8-2.1 1.8-2.1 1.9 1 1.8 2.1c0 1.2-.8 2.1-1.8 2.1zm6.6 0c-1 0-1.8-.9-1.8-2.1s.8-2.1 1.8-2.1 1.9 1 1.8 2.1c0 1.2-.8 2.1-1.8 2.1z"></path></svg></a>
|
||||
<a data-social="reddit" href="https://www.reddit.com/user/Igneum_network/" target="_blank" rel="noopener" aria-label="Igneum on Reddit"><svg viewBox="0 0 24 24" width="22" height="22" fill="currentColor" aria-hidden="true"><path d="M22 12.1a2.2 2.2 0 0 0-3.7-1.6 10.8 10.8 0 0 0-5.8-1.8l1-4.6 3.2.7a1.5 1.5 0 1 0 .2-.9l-3.6-.8a.5.5 0 0 0-.5.4l-1.1 5.2a10.8 10.8 0 0 0-5.9 1.8A2.2 2.2 0 1 0 3.4 14a4.3 4.3 0 0 0 0 .7c0 3.4 3.9 6.1 8.6 6.1s8.6-2.7 8.6-6.1a4.3 4.3 0 0 0 0-.7 2.2 2.2 0 0 0 1.4-1.9zM7 13.6a1.5 1.5 0 1 1 1.5 1.5A1.5 1.5 0 0 1 7 13.6zm8.6 4.1a5.7 5.7 0 0 1-3.6 1.1 5.7 5.7 0 0 1-3.6-1.1.4.4 0 0 1 .6-.6 4.9 4.9 0 0 0 3 .9 4.9 4.9 0 0 0 3-.9.4.4 0 0 1 .6.6zm-.3-2.6a1.5 1.5 0 1 1 1.5-1.5 1.5 1.5 0 0 1-1.5 1.5z"></path></svg></a>
|
||||
</div>
|
||||
<div class="footer-dl" aria-label="Download Ember"><a href="/download#windows"><span class="osmark mini" data-os="windows" title="Windows"><svg viewBox="0 0 24 24" width="22" height="22" aria-hidden="true" focusable="false" fill="currentColor"><path d="M3 5.6l7.3-1v7.1H3zM11.4 4.4L21 3v8.7h-9.6zM3 12.3h7.3v7.1L3 18.4zM11.4 12.3H21V21l-9.6-1.4z"/></svg></span>Windows</a><a href="/download#mac"><span class="osmark mini" data-os="mac" title="macOS"><svg viewBox="0 0 24 24" width="22" height="22" aria-hidden="true" focusable="false" fill="currentColor"><path d="M16.4 12.6c0-2.5 2-3.6 2.1-3.7-1.2-1.7-3-1.9-3.6-2-1.5-.2-3 .9-3.8.9-.8 0-2-.9-3.3-.8-1.7 0-3.2 1-4.1 2.5-1.8 3-.5 7.6 1.3 10.1.9 1.2 1.9 2.6 3.2 2.5 1.3 0 1.8-.8 3.3-.8 1.6 0 2 .8 3.3.8 1.4 0 2.3-1.2 3.1-2.5 1-1.4 1.4-2.8 1.4-2.9 0 0-2.7-1-2.9-4.1zM13.9 5.3c.7-.8 1.2-2 1-3.2-1 0-2.2.7-2.9 1.5-.6.7-1.2 1.9-1 3 1.1.1 2.2-.5 2.9-1.3z"/></svg></span>macOS</a><a href="/download#linux"><span class="osmark mini" data-os="linux" title="Linux"><svg viewBox="0 0 24 24" width="22" height="22" aria-hidden="true" focusable="false" fill="currentColor"><path d="M12 2c-2.4 0-4 1.9-4 4.6 0 1.2.2 2 0 2.8-.6 1.4-2.1 2.9-2.6 4.9-.3 1.1-.1 2 .3 2.6-.6.4-1.3 1-1.1 1.7.3 1 2.1 1.2 3.2 1.8.7.4 1.5.6 2.1.1.6.2 1.3.3 2.1.3s1.5-.1 2.1-.3c.6.5 1.4.3 2.1-.1 1.1-.6 2.9-.8 3.2-1.8.2-.7-.5-1.3-1.1-1.7.4-.6.6-1.5.3-2.6-.5-2-2-3.5-2.6-4.9-.2-.8 0-1.6 0-2.8C16 3.9 14.4 2 12 2zm-1.4 4.2c.5 0 .8.5.8 1.2s-.3 1.2-.8 1.2-.8-.5-.8-1.2.3-1.2.8-1.2zm2.8 0c.5 0 .8.5.8 1.2s-.3 1.2-.8 1.2-.8-.5-.8-1.2.3-1.2.8-1.2zM12 9.3c.9 0 1.9.5 1.9 1s-1 1.2-1.9 1.2-1.9-.7-1.9-1.2 1-1 1.9-1zm0 3.4c2.2 0 3.6 2.6 3.6 4.4 0 1.5-1.6 2.3-3.6 2.3s-3.6-.8-3.6-2.3c0-1.8 1.4-4.4 3.6-4.4z"/></svg></span>Linux</a><a href="/download#hive"><span class="osmark mini" data-os="hive" title="HiveOS"><svg viewBox="0 0 24 24" width="22" height="22" aria-hidden="true" focusable="false" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linejoin="round" stroke-linecap="round"><path d="M12 2.6 20.2 7.3v9.4L12 21.4 3.8 16.7V7.3z"/><path d="M12 7.4 16 9.7v4.6L12 16.6 8 14.3V9.7z"/><path d="M12 7.4V2.6M16 9.7l4.2-2.4M16 14.3l4.2 2.4M12 16.6v4.8M8 14.3l-4.2 2.4M8 9.7 3.8 7.3"/></svg></span>HiveOS</a></div>
|
||||
<a href="https://git.igneum.network/igneum-network/spec" target="_blank" rel="noopener" class="text-link">Specification and test vectors<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="M6 18 18 6M6 6h12v12"/></svg></a>
|
||||
</div>
|
||||
<div class="footer-column"><h4>Run</h4><div>
|
||||
<a href="/download">Download Ember</a>
|
||||
<a href="/miner">The miner</a>
|
||||
<a href="/app">The app</a>
|
||||
<a href="/wallet">The wallet</a>
|
||||
<a href="/miners">GPU bench table</a>
|
||||
<a href="/dev-fee">The dev fee</a>
|
||||
<a href="/faucet">Devnet faucet</a>
|
||||
<a href="/metamask">Add Igneum to MetaMask</a>
|
||||
</div></div>
|
||||
<div class="footer-column"><h4>Read</h4><div>
|
||||
<a href="/litepaper">Litepaper</a>
|
||||
<a href="/evidence">Evidence</a>
|
||||
<a href="/bench">Engineering log</a>
|
||||
<a href="/ledger">Ledger: every criticism</a>
|
||||
<a href="/claims">What Igneum does not claim</a>
|
||||
<a href="/randomx">Igneum vs RandomX</a>
|
||||
<a href="/provenance">Built on the shoulders</a>
|
||||
</div></div>
|
||||
<div class="footer-column"><h4>Explore</h4><div>
|
||||
<a href="/live">Live devnet</a>
|
||||
<a href="/explorer">Explorer</a>
|
||||
<a href="/build">Build on Igneum</a>
|
||||
<a href="/swap">Swap</a>
|
||||
<a href="/grants">Grants</a>
|
||||
<a href="/journey">Journey</a>
|
||||
<a href="/download">Downloads: devnet build</a>
|
||||
<a href="https://discord.gg/igneum" target="_blank" rel="noopener">Community Discord</a>
|
||||
<a href="mailto:hello@igneum.network">hello@igneum.network</a>
|
||||
<a href="https://git.igneum.network/igneum-network/spec/issues" rel="noopener">An issue on the spec</a>
|
||||
</div></div>
|
||||
</div>
|
||||
<div class="footer-bottom">
|
||||
<p>Igneum Labs LTD · Unit IH-00-01-01-OF-01, Level 01, Innovation One, Dubai International Financial Centre. Experimental software. Nothing on this site is an offer to sell anything.<br>Report a flaw by email or by an issue on the spec. Nobody from Igneum will ask for your seed. © 2026 Igneum · not an offer to sell anything</p>
|
||||
<div class="theme-group" role="group" aria-label="Theme"><button type="button" data-theme-set="system" aria-pressed="true">System</button><button type="button" data-theme-set="light" aria-pressed="false">Light</button><button type="button" data-theme-set="dark" aria-pressed="false">Dark</button></div>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
<script>
|
||||
(function(){
|
||||
// theme control: stores light or dark under igneum-theme; system clears it and follows the OS. The head applied the value before paint.
|
||||
var bs=document.querySelectorAll('[data-theme-set]');if(!bs.length)return;
|
||||
var media=window.matchMedia('(prefers-color-scheme: light)');
|
||||
function stored(){try{var t=localStorage.getItem('igneum-theme');return t==='light'||t==='dark'?t:'system';}catch(e){return 'system';}}
|
||||
function apply(){var c=stored();document.documentElement.setAttribute('data-theme',c==='system'?(media.matches?'light':'dark'):c);bs.forEach(function(b){b.setAttribute('aria-pressed',b.getAttribute('data-theme-set')===c?'true':'false');});document.dispatchEvent(new CustomEvent('igneum-theme'));}
|
||||
bs.forEach(function(b){b.addEventListener('click',function(){var v=b.getAttribute('data-theme-set');try{if(v==='system')localStorage.removeItem('igneum-theme');else localStorage.setItem('igneum-theme',v);}catch(e){}apply();});});
|
||||
if(media.addEventListener)media.addEventListener('change',function(){if(stored()==='system')apply();});
|
||||
document.addEventListener('igneum-theme',function(){var c=stored();bs.forEach(function(b){b.setAttribute('aria-pressed',b.getAttribute('data-theme-set')===c?'true':'false');});});
|
||||
bs.forEach(function(b){b.setAttribute('aria-pressed',b.getAttribute('data-theme-set')===stored()?'true':'false');});
|
||||
// the network state word in the status bar: one read of the observer per page view
|
||||
var fs=document.getElementById('foot-state'),fd=document.getElementById('foot-dot');if(fs&&fd){fetch('/api/live?window=30',{cache:'no-store'}).then(function(r){return r.json();}).then(function(d){var on=d&&d.ok&&d.state&&!d.state.stale;fs.textContent=on?'devnet live':'devnet, observer stale';fd.className='dot '+(on?'live':'off');}).catch(function(){fs.textContent='devnet';});}
|
||||
})();
|
||||
</script>
|
||||
<!-- footer:end -->
|
||||
<script src="/ui.js" defer></script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -46,6 +46,7 @@
|
|||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-mine" data-group="mine" aria-expanded="false" aria-controls="nav-panel-mine" aria-haspopup="true">Mine<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-network" data-group="network" aria-expanded="false" aria-controls="nav-panel-network" aria-haspopup="true">Network<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-learn" data-group="learn" data-active aria-expanded="false" aria-controls="nav-panel-learn" aria-haspopup="true">Learn<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-build" data-group="build" aria-expanded="false" aria-controls="nav-panel-build" aria-haspopup="true">Build<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
</div>
|
||||
<div class="nav-controls">
|
||||
<button class="btn icon-btn" type="button" data-theme-toggle aria-label="Switch to light theme"><svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><circle cx="12" cy="12" r="4"/><path d="M12 2v2m0 16v2M2 12h2m16 0h2M5 5l1 1m12 12 1 1M5 19l1-1M18 6l1-1"/></svg></button>
|
||||
|
|
@ -63,7 +64,6 @@
|
|||
<a href="/wallet" data-nav="wallet"><b>The wallet</b><span>Your coins. Final means final.</span></a>
|
||||
<a href="/miners" data-nav="miners"><b>GPU bench table</b><span>Measured rates, card by card.</span></a>
|
||||
<a href="/dev-fee" data-nav="dev-fee"><b>The dev fee</b><span>The optional one, in full view, off with one flag.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Testnet faucet</b><span>Test coin for an address, once a day.</span></a>
|
||||
<a href="/metamask" data-nav="metamask"><b>Add to MetaMask</b><span>Igneum as a network in your wallet.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -74,6 +74,9 @@
|
|||
<a href="/journey" data-nav="journey"><b>The journey</b><span>Six phases, four gates, the log behind them.</span></a>
|
||||
<a href="/bench" data-nav="bench"><b>Engineering log</b><span>Every measurement, with the commands that made it.</span></a>
|
||||
<a href="/evidence" data-nav="evidence"><b>Evidence</b><span>Every claim and how far it is tested.</span></a>
|
||||
<a href="/light" data-nav="light"><b>Light wallet</b><span>A balance your browser proves, trusting no node.</span></a>
|
||||
<a href="/receipt" data-nav="receipt"><b>Payment receipt</b><span>A receipt any third party re-verifies offline.</span></a>
|
||||
<a href="/oracle" data-nav="oracle"><b>State oracle on Sepolia</b><span>Devnet 3 balances read from another chain.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-panel" id="nav-panel-learn" data-group="learn" role="region" aria-labelledby="nav-btn-learn" hidden>
|
||||
|
|
@ -86,6 +89,14 @@
|
|||
<a href="/provenance" data-nav="provenance"><b>Built on the shoulders</b><span>Every borrowed part, credited.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-panel" id="nav-panel-build" data-group="build" role="region" aria-labelledby="nav-btn-build" hidden>
|
||||
<div class="panel-list">
|
||||
<a href="/build" data-nav="build"><b>Build on Igneum</b><span>Chain ids, RPC, a contract in five minutes.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Devnet faucet</b><span>10 IGN of devnet coin, once a day.</span></a>
|
||||
<a href="/swap" data-nav="swap"><b>Swap</b><span>Test tokens on Devnet 3; every swap is a proven block.</span></a>
|
||||
<a href="/grants" data-nav="grants"><b>Grants</b><span>Tooling, apps, infrastructure, research.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-sheet" id="nav-sheet" role="dialog" aria-modal="true" aria-label="Menu" hidden>
|
||||
|
|
@ -97,7 +108,6 @@
|
|||
<a href="/wallet" data-nav="wallet"><b>The wallet</b><span>Your coins. Final means final.</span></a>
|
||||
<a href="/miners" data-nav="miners"><b>GPU bench table</b><span>Measured rates, card by card.</span></a>
|
||||
<a href="/dev-fee" data-nav="dev-fee"><b>The dev fee</b><span>The optional one, in full view, off with one flag.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Testnet faucet</b><span>Test coin for an address, once a day.</span></a>
|
||||
<a href="/metamask" data-nav="metamask"><b>Add to MetaMask</b><span>Igneum as a network in your wallet.</span></a>
|
||||
</div>
|
||||
<div class="sheet-group"><div class="sheet-head">Network</div>
|
||||
|
|
@ -106,6 +116,9 @@
|
|||
<a href="/journey" data-nav="journey"><b>The journey</b><span>Six phases, four gates, the log behind them.</span></a>
|
||||
<a href="/bench" data-nav="bench"><b>Engineering log</b><span>Every measurement, with the commands that made it.</span></a>
|
||||
<a href="/evidence" data-nav="evidence"><b>Evidence</b><span>Every claim and how far it is tested.</span></a>
|
||||
<a href="/light" data-nav="light"><b>Light wallet</b><span>A balance your browser proves, trusting no node.</span></a>
|
||||
<a href="/receipt" data-nav="receipt"><b>Payment receipt</b><span>A receipt any third party re-verifies offline.</span></a>
|
||||
<a href="/oracle" data-nav="oracle"><b>State oracle on Sepolia</b><span>Devnet 3 balances read from another chain.</span></a>
|
||||
</div>
|
||||
<div class="sheet-group"><div class="sheet-head">Learn</div>
|
||||
<a href="/litepaper" data-nav="litepaper"><b>Litepaper</b><span>The design, as published.</span></a>
|
||||
|
|
@ -115,6 +128,12 @@
|
|||
<a href="/randomx" data-nav="randomx"><b>Igneum vs RandomX</b><span>What was kept and what was rebuilt for GPUs.</span></a>
|
||||
<a href="/provenance" data-nav="provenance"><b>Built on the shoulders</b><span>Every borrowed part, credited.</span></a>
|
||||
</div>
|
||||
<div class="sheet-group"><div class="sheet-head">Build</div>
|
||||
<a href="/build" data-nav="build"><b>Build on Igneum</b><span>Chain ids, RPC, a contract in five minutes.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Devnet faucet</b><span>10 IGN of devnet coin, once a day.</span></a>
|
||||
<a href="/swap" data-nav="swap"><b>Swap</b><span>Test tokens on Devnet 3; every swap is a proven block.</span></a>
|
||||
<a href="/grants" data-nav="grants"><b>Grants</b><span>Tooling, apps, infrastructure, research.</span></a>
|
||||
</div>
|
||||
<div class="sheet-foot">
|
||||
<a href="/download" class="btn primary big" data-nav="download">Download</a>
|
||||
<div class="sheet-social"><a href="https://discord.gg/igneum" target="_blank" rel="noopener">Discord</a><a href="https://git.igneum.network/igneum-network/spec" target="_blank" rel="noopener">Source</a><a href="https://www.reddit.com/user/Igneum_network/" target="_blank" rel="noopener">Reddit</a></div>
|
||||
|
|
@ -236,7 +255,7 @@
|
|||
<a href="/wallet">The wallet</a>
|
||||
<a href="/miners">GPU bench table</a>
|
||||
<a href="/dev-fee">The dev fee</a>
|
||||
<a href="/faucet">Testnet faucet</a>
|
||||
<a href="/faucet">Devnet faucet</a>
|
||||
<a href="/metamask">Add Igneum to MetaMask</a>
|
||||
</div></div>
|
||||
<div class="footer-column"><h4>Read</h4><div>
|
||||
|
|
@ -251,6 +270,9 @@
|
|||
<div class="footer-column"><h4>Explore</h4><div>
|
||||
<a href="/live">Live devnet</a>
|
||||
<a href="/explorer">Explorer</a>
|
||||
<a href="/build">Build on Igneum</a>
|
||||
<a href="/swap">Swap</a>
|
||||
<a href="/grants">Grants</a>
|
||||
<a href="/journey">Journey</a>
|
||||
<a href="/download">Downloads: devnet build</a>
|
||||
<a href="https://discord.gg/igneum" target="_blank" rel="noopener">Community Discord</a>
|
||||
|
|
|
|||
|
|
@ -78,6 +78,7 @@
|
|||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-mine" data-group="mine" aria-expanded="false" aria-controls="nav-panel-mine" aria-haspopup="true">Mine<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-network" data-group="network" aria-expanded="false" aria-controls="nav-panel-network" aria-haspopup="true">Network<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-learn" data-group="learn" aria-expanded="false" aria-controls="nav-panel-learn" aria-haspopup="true">Learn<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-build" data-group="build" aria-expanded="false" aria-controls="nav-panel-build" aria-haspopup="true">Build<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
</div>
|
||||
<div class="nav-controls">
|
||||
<button class="btn icon-btn" type="button" data-theme-toggle aria-label="Switch to light theme"><svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><circle cx="12" cy="12" r="4"/><path d="M12 2v2m0 16v2M2 12h2m16 0h2M5 5l1 1m12 12 1 1M5 19l1-1M18 6l1-1"/></svg></button>
|
||||
|
|
@ -95,7 +96,6 @@
|
|||
<a href="/wallet" data-nav="wallet"><b>The wallet</b><span>Your coins. Final means final.</span></a>
|
||||
<a href="/miners" data-nav="miners"><b>GPU bench table</b><span>Measured rates, card by card.</span></a>
|
||||
<a href="/dev-fee" data-nav="dev-fee"><b>The dev fee</b><span>The optional one, in full view, off with one flag.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Testnet faucet</b><span>Test coin for an address, once a day.</span></a>
|
||||
<a href="/metamask" data-nav="metamask"><b>Add to MetaMask</b><span>Igneum as a network in your wallet.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -106,6 +106,9 @@
|
|||
<a href="/journey" data-nav="journey"><b>The journey</b><span>Six phases, four gates, the log behind them.</span></a>
|
||||
<a href="/bench" data-nav="bench"><b>Engineering log</b><span>Every measurement, with the commands that made it.</span></a>
|
||||
<a href="/evidence" data-nav="evidence"><b>Evidence</b><span>Every claim and how far it is tested.</span></a>
|
||||
<a href="/light" data-nav="light"><b>Light wallet</b><span>A balance your browser proves, trusting no node.</span></a>
|
||||
<a href="/receipt" data-nav="receipt"><b>Payment receipt</b><span>A receipt any third party re-verifies offline.</span></a>
|
||||
<a href="/oracle" data-nav="oracle"><b>State oracle on Sepolia</b><span>Devnet 3 balances read from another chain.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-panel" id="nav-panel-learn" data-group="learn" role="region" aria-labelledby="nav-btn-learn" hidden>
|
||||
|
|
@ -118,6 +121,14 @@
|
|||
<a href="/provenance" data-nav="provenance"><b>Built on the shoulders</b><span>Every borrowed part, credited.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-panel" id="nav-panel-build" data-group="build" role="region" aria-labelledby="nav-btn-build" hidden>
|
||||
<div class="panel-list">
|
||||
<a href="/build" data-nav="build"><b>Build on Igneum</b><span>Chain ids, RPC, a contract in five minutes.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Devnet faucet</b><span>10 IGN of devnet coin, once a day.</span></a>
|
||||
<a href="/swap" data-nav="swap"><b>Swap</b><span>Test tokens on Devnet 3; every swap is a proven block.</span></a>
|
||||
<a href="/grants" data-nav="grants"><b>Grants</b><span>Tooling, apps, infrastructure, research.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-sheet" id="nav-sheet" role="dialog" aria-modal="true" aria-label="Menu" hidden>
|
||||
|
|
@ -129,7 +140,6 @@
|
|||
<a href="/wallet" data-nav="wallet"><b>The wallet</b><span>Your coins. Final means final.</span></a>
|
||||
<a href="/miners" data-nav="miners"><b>GPU bench table</b><span>Measured rates, card by card.</span></a>
|
||||
<a href="/dev-fee" data-nav="dev-fee"><b>The dev fee</b><span>The optional one, in full view, off with one flag.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Testnet faucet</b><span>Test coin for an address, once a day.</span></a>
|
||||
<a href="/metamask" data-nav="metamask"><b>Add to MetaMask</b><span>Igneum as a network in your wallet.</span></a>
|
||||
</div>
|
||||
<div class="sheet-group"><div class="sheet-head">Network</div>
|
||||
|
|
@ -138,6 +148,9 @@
|
|||
<a href="/journey" data-nav="journey"><b>The journey</b><span>Six phases, four gates, the log behind them.</span></a>
|
||||
<a href="/bench" data-nav="bench"><b>Engineering log</b><span>Every measurement, with the commands that made it.</span></a>
|
||||
<a href="/evidence" data-nav="evidence"><b>Evidence</b><span>Every claim and how far it is tested.</span></a>
|
||||
<a href="/light" data-nav="light"><b>Light wallet</b><span>A balance your browser proves, trusting no node.</span></a>
|
||||
<a href="/receipt" data-nav="receipt"><b>Payment receipt</b><span>A receipt any third party re-verifies offline.</span></a>
|
||||
<a href="/oracle" data-nav="oracle"><b>State oracle on Sepolia</b><span>Devnet 3 balances read from another chain.</span></a>
|
||||
</div>
|
||||
<div class="sheet-group"><div class="sheet-head">Learn</div>
|
||||
<a href="/litepaper" data-nav="litepaper"><b>Litepaper</b><span>The design, as published.</span></a>
|
||||
|
|
@ -147,6 +160,12 @@
|
|||
<a href="/randomx" data-nav="randomx"><b>Igneum vs RandomX</b><span>What was kept and what was rebuilt for GPUs.</span></a>
|
||||
<a href="/provenance" data-nav="provenance"><b>Built on the shoulders</b><span>Every borrowed part, credited.</span></a>
|
||||
</div>
|
||||
<div class="sheet-group"><div class="sheet-head">Build</div>
|
||||
<a href="/build" data-nav="build"><b>Build on Igneum</b><span>Chain ids, RPC, a contract in five minutes.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Devnet faucet</b><span>10 IGN of devnet coin, once a day.</span></a>
|
||||
<a href="/swap" data-nav="swap"><b>Swap</b><span>Test tokens on Devnet 3; every swap is a proven block.</span></a>
|
||||
<a href="/grants" data-nav="grants"><b>Grants</b><span>Tooling, apps, infrastructure, research.</span></a>
|
||||
</div>
|
||||
<div class="sheet-foot">
|
||||
<a href="/download" class="btn primary big" data-nav="download">Download</a>
|
||||
<div class="sheet-social"><a href="https://discord.gg/igneum" target="_blank" rel="noopener">Discord</a><a href="https://git.igneum.network/igneum-network/spec" target="_blank" rel="noopener">Source</a><a href="https://www.reddit.com/user/Igneum_network/" target="_blank" rel="noopener">Reddit</a></div>
|
||||
|
|
@ -277,7 +296,7 @@
|
|||
<a href="/wallet">The wallet</a>
|
||||
<a href="/miners">GPU bench table</a>
|
||||
<a href="/dev-fee">The dev fee</a>
|
||||
<a href="/faucet">Testnet faucet</a>
|
||||
<a href="/faucet">Devnet faucet</a>
|
||||
<a href="/metamask">Add Igneum to MetaMask</a>
|
||||
</div></div>
|
||||
<div class="footer-column"><h4>Read</h4><div>
|
||||
|
|
@ -292,6 +311,9 @@
|
|||
<div class="footer-column"><h4>Explore</h4><div>
|
||||
<a href="/live">Live devnet</a>
|
||||
<a href="/explorer">Explorer</a>
|
||||
<a href="/build">Build on Igneum</a>
|
||||
<a href="/swap">Swap</a>
|
||||
<a href="/grants">Grants</a>
|
||||
<a href="/journey">Journey</a>
|
||||
<a href="/download">Downloads: devnet build</a>
|
||||
<a href="https://discord.gg/igneum" target="_blank" rel="noopener">Community Discord</a>
|
||||
|
|
|
|||
|
|
@ -86,6 +86,7 @@
|
|||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-mine" data-group="mine" aria-expanded="false" aria-controls="nav-panel-mine" aria-haspopup="true">Mine<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-network" data-group="network" data-active aria-expanded="false" aria-controls="nav-panel-network" aria-haspopup="true">Network<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-learn" data-group="learn" aria-expanded="false" aria-controls="nav-panel-learn" aria-haspopup="true">Learn<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-build" data-group="build" aria-expanded="false" aria-controls="nav-panel-build" aria-haspopup="true">Build<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
</div>
|
||||
<div class="nav-controls">
|
||||
<button class="btn icon-btn" type="button" data-theme-toggle aria-label="Switch to light theme"><svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><circle cx="12" cy="12" r="4"/><path d="M12 2v2m0 16v2M2 12h2m16 0h2M5 5l1 1m12 12 1 1M5 19l1-1M18 6l1-1"/></svg></button>
|
||||
|
|
@ -103,7 +104,6 @@
|
|||
<a href="/wallet" data-nav="wallet"><b>The wallet</b><span>Your coins. Final means final.</span></a>
|
||||
<a href="/miners" data-nav="miners"><b>GPU bench table</b><span>Measured rates, card by card.</span></a>
|
||||
<a href="/dev-fee" data-nav="dev-fee"><b>The dev fee</b><span>The optional one, in full view, off with one flag.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Testnet faucet</b><span>Test coin for an address, once a day.</span></a>
|
||||
<a href="/metamask" data-nav="metamask"><b>Add to MetaMask</b><span>Igneum as a network in your wallet.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -114,6 +114,9 @@
|
|||
<a href="/journey" data-nav="journey" aria-current="page"><b>The journey</b><span>Six phases, four gates, the log behind them.</span></a>
|
||||
<a href="/bench" data-nav="bench"><b>Engineering log</b><span>Every measurement, with the commands that made it.</span></a>
|
||||
<a href="/evidence" data-nav="evidence"><b>Evidence</b><span>Every claim and how far it is tested.</span></a>
|
||||
<a href="/light" data-nav="light"><b>Light wallet</b><span>A balance your browser proves, trusting no node.</span></a>
|
||||
<a href="/receipt" data-nav="receipt"><b>Payment receipt</b><span>A receipt any third party re-verifies offline.</span></a>
|
||||
<a href="/oracle" data-nav="oracle"><b>State oracle on Sepolia</b><span>Devnet 3 balances read from another chain.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-panel" id="nav-panel-learn" data-group="learn" role="region" aria-labelledby="nav-btn-learn" hidden>
|
||||
|
|
@ -126,6 +129,14 @@
|
|||
<a href="/provenance" data-nav="provenance"><b>Built on the shoulders</b><span>Every borrowed part, credited.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-panel" id="nav-panel-build" data-group="build" role="region" aria-labelledby="nav-btn-build" hidden>
|
||||
<div class="panel-list">
|
||||
<a href="/build" data-nav="build"><b>Build on Igneum</b><span>Chain ids, RPC, a contract in five minutes.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Devnet faucet</b><span>10 IGN of devnet coin, once a day.</span></a>
|
||||
<a href="/swap" data-nav="swap"><b>Swap</b><span>Test tokens on Devnet 3; every swap is a proven block.</span></a>
|
||||
<a href="/grants" data-nav="grants"><b>Grants</b><span>Tooling, apps, infrastructure, research.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-sheet" id="nav-sheet" role="dialog" aria-modal="true" aria-label="Menu" hidden>
|
||||
|
|
@ -137,7 +148,6 @@
|
|||
<a href="/wallet" data-nav="wallet"><b>The wallet</b><span>Your coins. Final means final.</span></a>
|
||||
<a href="/miners" data-nav="miners"><b>GPU bench table</b><span>Measured rates, card by card.</span></a>
|
||||
<a href="/dev-fee" data-nav="dev-fee"><b>The dev fee</b><span>The optional one, in full view, off with one flag.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Testnet faucet</b><span>Test coin for an address, once a day.</span></a>
|
||||
<a href="/metamask" data-nav="metamask"><b>Add to MetaMask</b><span>Igneum as a network in your wallet.</span></a>
|
||||
</div>
|
||||
<div class="sheet-group"><div class="sheet-head">Network</div>
|
||||
|
|
@ -146,6 +156,9 @@
|
|||
<a href="/journey" data-nav="journey" aria-current="page"><b>The journey</b><span>Six phases, four gates, the log behind them.</span></a>
|
||||
<a href="/bench" data-nav="bench"><b>Engineering log</b><span>Every measurement, with the commands that made it.</span></a>
|
||||
<a href="/evidence" data-nav="evidence"><b>Evidence</b><span>Every claim and how far it is tested.</span></a>
|
||||
<a href="/light" data-nav="light"><b>Light wallet</b><span>A balance your browser proves, trusting no node.</span></a>
|
||||
<a href="/receipt" data-nav="receipt"><b>Payment receipt</b><span>A receipt any third party re-verifies offline.</span></a>
|
||||
<a href="/oracle" data-nav="oracle"><b>State oracle on Sepolia</b><span>Devnet 3 balances read from another chain.</span></a>
|
||||
</div>
|
||||
<div class="sheet-group"><div class="sheet-head">Learn</div>
|
||||
<a href="/litepaper" data-nav="litepaper"><b>Litepaper</b><span>The design, as published.</span></a>
|
||||
|
|
@ -155,6 +168,12 @@
|
|||
<a href="/randomx" data-nav="randomx"><b>Igneum vs RandomX</b><span>What was kept and what was rebuilt for GPUs.</span></a>
|
||||
<a href="/provenance" data-nav="provenance"><b>Built on the shoulders</b><span>Every borrowed part, credited.</span></a>
|
||||
</div>
|
||||
<div class="sheet-group"><div class="sheet-head">Build</div>
|
||||
<a href="/build" data-nav="build"><b>Build on Igneum</b><span>Chain ids, RPC, a contract in five minutes.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Devnet faucet</b><span>10 IGN of devnet coin, once a day.</span></a>
|
||||
<a href="/swap" data-nav="swap"><b>Swap</b><span>Test tokens on Devnet 3; every swap is a proven block.</span></a>
|
||||
<a href="/grants" data-nav="grants"><b>Grants</b><span>Tooling, apps, infrastructure, research.</span></a>
|
||||
</div>
|
||||
<div class="sheet-foot">
|
||||
<a href="/download" class="btn primary big" data-nav="download">Download</a>
|
||||
<div class="sheet-social"><a href="https://discord.gg/igneum" target="_blank" rel="noopener">Discord</a><a href="https://git.igneum.network/igneum-network/spec" target="_blank" rel="noopener">Source</a><a href="https://www.reddit.com/user/Igneum_network/" target="_blank" rel="noopener">Reddit</a></div>
|
||||
|
|
@ -212,7 +231,7 @@
|
|||
<section class="page-hero">
|
||||
<div class="container">
|
||||
<div class="breadcrumb"><a href="/">Igneum</a><span>/</span><span>The journey</span></div>
|
||||
<div class="page-heading"><div><div class="eyebrow"><span class="line"></span>Six phases · updated 7 Oct 2026</div>
|
||||
<div class="page-heading"><div><div class="eyebrow"><span class="line"></span>Six phases · updated 8 Oct 2026</div>
|
||||
<h1>The journey.</h1>
|
||||
<p class="lead">Six phases from the specification to a fair launch. Each closes at its gate, a measurement published whether it passes or fails, so there is no date to slip. Below the phases, the latest entries of the engineering log.</p></div></div>
|
||||
</div>
|
||||
|
|
@ -226,7 +245,8 @@
|
|||
<div class="milestone next" id="phase-5"><div class="when">Armed: opens on the go word</div><div><span class="badge">Next</span><h3>5. Public testnet</h3><p>Three seed nodes and the public RPC are up; the one-click miner app on Windows, macOS and Linux, HiveOS, pools, the first rollup as a proving customer, no coin yet</p><p class="gate"><b>Gate:</b> 1,000 independent miners run 30 days and rollup proofs are delivered on time</p></div></div>
|
||||
<div class="milestone next" id="phase-6"><div class="when">After the testnet has passed its gate (1,000 independent miners for 30 days, rollup proofs on time) and one proving customer has signed: a customer paying for proofs at a published rate, or a letter of intent with a volume</div><div><span class="badge">Next</span><h3>6. Mainnet fair launch</h3><p>Genesis with no premine, 30-day ramp. No listing is arranged, promised or sought by the project</p></div></div></div>
|
||||
<div class="section-head" style="margin-top:100px"><div><div class="eyebrow"><span class="line"></span>The log, newest first</div><h2>Lately, in the log.</h2></div><div class="searchbar" style="min-width:min(100%,360px)"><svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><circle cx="10.5" cy="10.5" r="6.5"/><path d="m16 16 5 5"/></svg><label for="log-q" class="visually-hidden">Filter the log</label><input id="log-q" data-filter-input="log" placeholder="Filter: a card, a date, a word" autocomplete="off" spellcheck="false"><span class="small" data-filter-count="log"></span></div></div>
|
||||
<div class="record-count" data-filter-count="log"></div><div class="record-grid" data-filter-list="log"><article class="record"><div class="record-top"><time datetime="2026-10-07">7 Oct 2026</time><span class="badge">log</span></div><h3>The first 16 GB card</h3><p>The first 16 GB card: an RTX 5060 Ti in a Thunderbolt enclosure on the RTX 5090 Windows rig</p></article>
|
||||
<div class="record-count" data-filter-count="log"></div><div class="record-grid" data-filter-list="log"><article class="record"><div class="record-top"><time datetime="2026-10-08">8 Oct 2026</time><span class="badge">log</span></div><h3>The hot-table packs on the RTX 5090</h3><p>The hot-table packs on the RTX 5090: ld.global.cs against the plain load, unlocked and at the 1,300 MHz lock</p></article>
|
||||
<article class="record"><div class="record-top"><time datetime="2026-10-07">7 Oct 2026</time><span class="badge">log</span></div><h3>The first 16 GB card</h3><p>The first 16 GB card: an RTX 5060 Ti in a Thunderbolt enclosure on the RTX 5090 Windows rig</p></article>
|
||||
<article class="record"><div class="record-top"><time datetime="2026-10-06">6 Oct 2026</time><span class="badge">log</span></div><h3>Counter ASIC 3.0</h3><p>Counter ASIC 3.0: the class v4 rehearsal</p></article>
|
||||
<article class="record"><div class="record-top"><time datetime="2026-10-06">6 Oct 2026</time><span class="badge">log</span></div><h3>16:01Z: Ember run 6 on the three-card Windows rig</h3></article>
|
||||
<article class="record"><div class="record-top"><time datetime="2026-10-06">6 Oct 2026</time><span class="badge">log</span></div><h3>Counter ASIC 3.0 item 2</h3><p>Counter ASIC 3.0 item 2: the per-day derivation</p></article>
|
||||
|
|
@ -259,13 +279,12 @@
|
|||
<article class="record"><div class="record-top"><time datetime="2026-10-05">5 Oct 2026</time><span class="badge">log</span></div><h3>Live devnet: real transactions, the first non-empty shard proven and…</h3><p>Live devnet: real transactions, the first non-empty shard proven and paid, and the exporter's block structure fixed</p></article>
|
||||
<article class="record"><div class="record-top"><time datetime="2026-10-05">5 Oct 2026</time><span class="badge">log</span></div><h3>The program id split</h3><p>The program id split: why the Apple M5 Max rejected the RTX 5090 Windows rig's proofs, and the verifier at 114 s</p></article>
|
||||
<article class="record"><div class="record-top"><time datetime="2026-10-05">5 Oct 2026</time><span class="badge">log</span></div><h3>Live devnet: the first shards proven, verified and paid</h3></article>
|
||||
<article class="record"><div class="record-top"><time datetime="2026-10-04">4 Oct 2026</time><span class="badge">log</span></div><h3>Devnet v4 live: generator v2, two-thirds floor, fresh chain</h3><p>Devnet v4 cut-over: generator v2, 2/3 floor, three nodes and a seed on a fresh chain</p></article>
|
||||
<article class="record"><div class="record-top"><time datetime="2026-10-04">4 Oct 2026</time><span class="badge">log</span></div><h3>One-click Windows workers</h3><p>One-click Windows workers: what the Apple M5 Max could measure</p></article>
|
||||
<article class="record"><div class="record-top"><time datetime="2026-10-04">4 Oct 2026</time><span class="badge">log</span></div><h3>First live hourly swap: no pause on Mac, NVIDIA or AMD</h3><p>First hourly program swap on the live devnet: compile-ahead, no pause, two cards</p></article>
|
||||
<article class="record"><div class="record-top"><time datetime="2026-10-04">4 Oct 2026</time><span class="badge">log</span></div><h3>Proving: devnet v4 shards on the Apple M5 Max CPU, loaded machine</h3></article>
|
||||
<article class="record"><div class="record-top"><time datetime="2026-10-04">4 Oct 2026</time><span class="badge">log</span></div><h3>First live finality lock: 77.4% of weight, 17 voters</h3><p>First finality lock on the live devnet: checkpoint 242 at 77.4% of all weight, two hours after genesis</p></article>
|
||||
<article class="record"><div class="record-top"><time datetime="2026-10-04">4 Oct 2026</time><span class="badge">log</span></div><h3>The gfx1036 worker fault and what the Apple M5 Max could and could…</h3><p>The gfx1036 worker fault and what the Apple M5 Max could and could not reproduce</p></article>
|
||||
<article class="record"><div class="record-top"><time datetime="2026-10-04">4 Oct 2026</time><span class="badge">log</span></div><h3>A node 60 s behind the clock is silently dead</h3></article>
|
||||
<article class="record"><div class="record-top"><time datetime="2026-10-04">4 Oct 2026</time><span class="badge">log</span></div><h3>First machine on the one-click app: a 5090 at 118 MH/s</h3><p>First machine on the Igneum Miner app: the RTX 5090 Windows rig's RTX 5090 at 118 MH/s, via Setup.exe</p></article></div>
|
||||
<article class="record"><div class="record-top"><time datetime="2026-10-04">4 Oct 2026</time><span class="badge">log</span></div><h3>The gfx1036 worker fault and what the Apple M5 Max could and could…</h3><p>The gfx1036 worker fault and what the Apple M5 Max could and could not reproduce</p></article></div>
|
||||
<p class="empty-state" data-filter-empty="log" hidden>Nothing in the log matches that.</p>
|
||||
<p class="note">Every entry is a dated heading of <a href="/bench">the engineering log</a>, where the commands and the hardware are. The phases and their gates are the litepaper’s <a href="/litepaper#roadmap">roadmap</a>.</p>
|
||||
<div class="onward"><a href="/bench" class="btn">The engineering log</a><a href="/evidence" class="btn">Every claim and its status</a><a href="/live" class="btn">The live devnet</a></div>
|
||||
|
|
@ -294,7 +313,7 @@
|
|||
<a href="/wallet">The wallet</a>
|
||||
<a href="/miners">GPU bench table</a>
|
||||
<a href="/dev-fee">The dev fee</a>
|
||||
<a href="/faucet">Testnet faucet</a>
|
||||
<a href="/faucet">Devnet faucet</a>
|
||||
<a href="/metamask">Add Igneum to MetaMask</a>
|
||||
</div></div>
|
||||
<div class="footer-column"><h4>Read</h4><div>
|
||||
|
|
@ -309,6 +328,9 @@
|
|||
<div class="footer-column"><h4>Explore</h4><div>
|
||||
<a href="/live">Live devnet</a>
|
||||
<a href="/explorer">Explorer</a>
|
||||
<a href="/build">Build on Igneum</a>
|
||||
<a href="/swap">Swap</a>
|
||||
<a href="/grants">Grants</a>
|
||||
<a href="/journey">Journey</a>
|
||||
<a href="/download">Downloads: devnet build</a>
|
||||
<a href="https://discord.gg/igneum" target="_blank" rel="noopener">Community Discord</a>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"updated": "2026-10-07",
|
||||
"updated": "2026-10-08",
|
||||
"stage": "phase-3",
|
||||
"phases": [
|
||||
{
|
||||
|
|
@ -50,6 +50,11 @@
|
|||
}
|
||||
],
|
||||
"log": [
|
||||
{
|
||||
"date": "2026-10-08",
|
||||
"text": "The hot-table packs on the RTX 5090: ld.global.cs against the plain load, unlocked and at the 1,300 MHz lock",
|
||||
"short": "The hot-table packs on the RTX 5090"
|
||||
},
|
||||
{
|
||||
"date": "2026-10-07",
|
||||
"text": "The first 16 GB card: an RTX 5060 Ti in a Thunderbolt enclosure on the RTX 5090 Windows rig",
|
||||
|
|
@ -215,6 +220,11 @@
|
|||
"text": "Live devnet: the first shards proven, verified and paid",
|
||||
"short": "Live devnet: the first shards proven, verified and paid"
|
||||
},
|
||||
{
|
||||
"date": "2026-10-04",
|
||||
"text": "Devnet v4 cut-over: generator v2, 2/3 floor, three nodes and a seed on a fresh chain",
|
||||
"short": "Devnet v4 live: generator v2, two-thirds floor, fresh chain"
|
||||
},
|
||||
{
|
||||
"date": "2026-10-04",
|
||||
"text": "One-click Windows workers: what the Apple M5 Max could measure",
|
||||
|
|
@ -239,16 +249,6 @@
|
|||
"date": "2026-10-04",
|
||||
"text": "The gfx1036 worker fault and what the Apple M5 Max could and could not reproduce",
|
||||
"short": "The gfx1036 worker fault and what the Apple M5 Max could and could…"
|
||||
},
|
||||
{
|
||||
"date": "2026-10-04",
|
||||
"text": "A node 60 s behind the clock is silently dead",
|
||||
"short": "A node 60 s behind the clock is silently dead"
|
||||
},
|
||||
{
|
||||
"date": "2026-10-04",
|
||||
"text": "First machine on the Igneum Miner app: the RTX 5090 Windows rig's RTX 5090 at 118 MH/s, via Setup.exe",
|
||||
"short": "First machine on the one-click app: a 5090 at 118 MH/s"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
|||
119
site/lc/app.js
Normal file
119
site/lc/app.js
Normal file
|
|
@ -0,0 +1,119 @@
|
|||
// Igneum reference apps, the browser driver for /light and /receipt (8 October 2026). Fetches data from the read
|
||||
// service behind rpc.devnet.igneum.network/light and verifies every byte in this tab with core.js. Libraries, pinned:
|
||||
// BLAKE2b and keccak from @noble/hashes 2.4.0, BLS12-381 from @noble/curves 2.4.0 (pure JavaScript, served by jsdelivr
|
||||
// as ES modules). Known-failed first: before the genuine result is shown, a copy of the same proof with one byte
|
||||
// altered is run through the same verifier and must read as refused.
|
||||
import { blake2b } from 'https://cdn.jsdelivr.net/npm/@noble/hashes@2.4.0/blake2.js/+esm';
|
||||
import { keccak_256 } from 'https://cdn.jsdelivr.net/npm/@noble/hashes@2.4.0/sha3.js/+esm';
|
||||
import { bls12_381 } from 'https://cdn.jsdelivr.net/npm/@noble/curves@2.4.0/bls12-381.js/+esm';
|
||||
import { verifyBalance, verifyReceipt, formatIgn } from './core.js';
|
||||
|
||||
export const LIBRARIES = { '@noble/hashes': '2.4.0', '@noble/curves': '2.4.0' };
|
||||
const deps = { blake2b, bls: bls12_381, keccak: keccak_256 };
|
||||
const q = new URLSearchParams(location.search);
|
||||
export const API = (q.get('api') || 'https://rpc.devnet.igneum.network/light').replace(/\/$/, '');
|
||||
const $ = s => document.querySelector(s);
|
||||
const esc = s => String(s).replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>');
|
||||
const short = h => { const s = String(h).replace(/^0x/, ''); return s.slice(0, 8) + '…' + s.slice(-6); };
|
||||
const clone = x => JSON.parse(JSON.stringify(x));
|
||||
const flipHex = (s, at) => { const h = s.replace(/^0x/, ''); const i = Math.min(at, h.length - 1); const d = (parseInt(h[i], 16) ^ 1).toString(16); return (s.startsWith('0x') ? '0x' : '') + h.slice(0, i) + d + h.slice(i + 1); };
|
||||
|
||||
async function getJson(url) {
|
||||
const r = await fetch(url, { cache: 'no-store' });
|
||||
let j = null; try { j = await r.json(); } catch { j = null; }
|
||||
if (!j) throw new Error(`${url.replace(API, '')} answered ${r.status} with no JSON`);
|
||||
if (!j.ok) throw new Error(j.error || `${url.replace(API, '')} answered ${r.status}`);
|
||||
return j;
|
||||
}
|
||||
|
||||
function setStatus(text, kind = '') { const el = $('[data-status]'); if (!el) return; el.textContent = text; el.dataset.kind = kind; }
|
||||
function stepsHtml(result) {
|
||||
return '<ol class="steps">' + result.steps.map(s => `<li class="${s.ok ? 'ok' : 'bad'}"><b>${s.ok ? 'checked' : 'refused'}</b><span>${esc(s.name)}</span><small>${esc(s.detail)}</small></li>`).join('') + '</ol>';
|
||||
}
|
||||
function negativeHtml(name, result) {
|
||||
return `<div class="neg ${result.verified ? 'wrong' : 'right'}"><b>${result.verified ? 'NOT REFUSED (this is a bug)' : 'refused'}</b> <span>${esc(name)}</span><small>${esc(result.reason || 'verified')}</small></div>`;
|
||||
}
|
||||
const ago = ms => { const s = Math.max(0, Math.round((Date.now() - Number(ms)) / 1000)); return s < 90 ? `${s} s ago` : s < 5400 ? `${Math.round(s / 60)} min ago` : `${(s / 3600).toFixed(1)} h ago`; };
|
||||
|
||||
// ---- /light -------------------------------------------------------------------------------------------------------
|
||||
export async function runLight(address) {
|
||||
const out = $('[data-result]'); out.innerHTML = '';
|
||||
setStatus('fetching the latest certified checkpoint…', 'busy');
|
||||
const cp = await getJson(`${API}/checkpoint`);
|
||||
setStatus(`checkpoint ${cp.index} fetched; fetching the proof for ${short(address)}…`, 'busy');
|
||||
const proof = await getJson(`${API}/balance?address=${address}&checkpoint=${cp.hash}&index=${cp.index}`);
|
||||
// the service may answer with an earlier certificate (the first checkpoint above the carrier: the smallest proof); verified like any other
|
||||
if (proof.checkpoint_certificate) { Object.assign(cp, proof.checkpoint_certificate); }
|
||||
setStatus('verifying in this tab…', 'busy');
|
||||
await new Promise(r => setTimeout(r, 20));
|
||||
// known-failed first: the same proof with one byte of the last account-proof node altered
|
||||
const bad = clone(proof); const last = bad.account.accountProof.length - 1;
|
||||
bad.account.accountProof[last] = flipHex(bad.account.accountProof[last], 30);
|
||||
const neg = verifyBalance(cp, bad, deps);
|
||||
const res = verifyBalance(cp, proof, deps);
|
||||
window.__igneumLight = { cp, proof, neg, res };
|
||||
const top = res.verified
|
||||
? `<div class="headline"><div class="eyebrow ember">Proven balance · Devnet 3, no value</div><div class="big">${esc(formatIgn(res.balance_wei))} <span>IGN</span></div>
|
||||
<p class="pt">${esc(res.balance_wei)} wei at chain block ${res.block}, under checkpoint ${res.checkpoint} (locked ${esc(ago(Number(proof.headers[proof.headers.length - 1].timestamp)))}). Verified here in ${res.ms} ms, ${res.headers} headers checked.</p></div>`
|
||||
: `<div class="headline bad"><div class="eyebrow">Not verified · Devnet 3, no value</div><p class="pt">${esc(res.reason)}</p></div>`;
|
||||
out.innerHTML = top + negativeHtml('a copy of this proof with one byte of a trie node altered', neg) + stepsHtml(res)
|
||||
+ `<p class="note">Data served by ${esc(API)} (a read service in front of a Devnet 3 node). Nothing it answered was taken on trust: the certificate, every header hash and parent link, the coinbase inclusion, the segment record's signature and the account proof were recomputed in this tab. What is trusted: that the aggregator's statement is the true execution result (every node checks it natively before paying the record; the SP1 proof behind it is verified by nodes, not in this tab yet), and the voter list with weights, which came from the node (spec 10.1).</p>`;
|
||||
setStatus(res.verified ? 'verified' : 'refused', res.verified ? 'ok' : 'bad');
|
||||
return res;
|
||||
}
|
||||
|
||||
// ---- /receipt -----------------------------------------------------------------------------------------------------
|
||||
export async function runReceipt(tx) {
|
||||
const out = $('[data-result]'); out.innerHTML = '';
|
||||
setStatus('fetching the latest certified checkpoint…', 'busy');
|
||||
const cp = await getJson(`${API}/checkpoint`);
|
||||
setStatus(`checkpoint ${cp.index} fetched; fetching the inclusion proof…`, 'busy');
|
||||
const r = await getJson(`${API}/receipt?tx=${tx}&checkpoint=${cp.hash}&index=${cp.index}`);
|
||||
// the service may answer with an earlier certificate (the first checkpoint above the block: the smallest proof); it is verified like any other
|
||||
const receipt = { format: 'igneum-receipt-v1', issued: new Date().toISOString(), ...r, checkpoint: { ...r.checkpoint, certificate: r.checkpoint.certificate || cp } };
|
||||
delete receipt.ok; delete receipt.now;
|
||||
setStatus('verifying in this tab…', 'busy');
|
||||
await new Promise(resolve => setTimeout(resolve, 20));
|
||||
const bad = clone(receipt); bad.raw_tx_hex = flipHex(bad.raw_tx_hex, 40);
|
||||
const neg = verifyReceipt(bad, deps);
|
||||
const res = verifyReceipt(receipt, deps);
|
||||
window.__igneumReceipt = { receipt, neg, res };
|
||||
const t = res.tx || {};
|
||||
const when = new Date(Number(res.block_time || 0)).toISOString().replace('T', ' ').slice(0, 19) + ' UTC';
|
||||
const top = res.verified
|
||||
? `<div class="headline"><div class="eyebrow ember">Final · Devnet 3, no value</div><div class="big">${esc(formatIgn(t.value || '0'))} <span>IGN</span></div>
|
||||
<div class="kv"><div class="k">To</div><div class="mono">${esc(t.to || 'contract creation')}</div><div class="k">From</div><div class="mono">${esc(receipt.tx_as_reported.from)} <small>(as the node reports it; the signature is the chain's check)</small></div>
|
||||
<div class="k">Transaction</div><div class="mono">0x${esc(receipt.tx_hash)}</div><div class="k">Block</div><div class="mono">${esc(res.block)} <small>at ${esc(when)}, DAA ${esc(res.block_daa)}</small></div>
|
||||
<div class="k">Finality</div><div>checkpoint ${res.checkpoint}, ${esc(res.certificate)}; ${res.headers} headers from the block to the checkpoint, verified here in ${res.ms} ms</div>
|
||||
${receipt.execution ? `<div class="k">Execution</div><div>status ${receipt.execution.status === '0x1' ? 'success' : 'failed'}, gas ${parseInt(receipt.execution.gas_used, 16)}, ${receipt.execution.logs} log(s) <small>(as the node reports it, not proven here)</small></div>` : ''}</div></div>`
|
||||
: `<div class="headline bad"><div class="eyebrow">Not verified · Devnet 3, no value</div><p class="pt">${esc(res.reason)}</p></div>`;
|
||||
out.innerHTML = top + negativeHtml('a copy of this receipt with one nibble of the raw transaction altered', neg) + stepsHtml(res)
|
||||
+ (res.verified ? `<p><button class="btn" type="button" data-download>Download the receipt (JSON, ${Math.round(JSON.stringify(receipt).length / 1024)} KB)</button></p>
|
||||
<p class="note">The file carries the raw transaction, the including block's header and merkle path, every header up to the certified checkpoint, the certificate and the voter table. Anyone re-verifies it offline with the one-file verifier: <code>node verify-receipt.js receipt.json</code> (<a href="/lc/verify-receipt.js" download>verify-receipt.js</a>, plain JavaScript, no npm, no network). A tampered file fails there the same way the copy above failed here.</p>` : '');
|
||||
const dl = $('[data-download]');
|
||||
if (dl) dl.addEventListener('click', () => {
|
||||
const blob = new Blob([JSON.stringify(receipt, null, 1)], { type: 'application/json' });
|
||||
const a = document.createElement('a'); a.href = URL.createObjectURL(blob); a.download = `igneum-receipt-${receipt.tx_hash.slice(0, 12)}.json`; a.click(); setTimeout(() => URL.revokeObjectURL(a.href), 5000);
|
||||
});
|
||||
setStatus(res.verified ? 'verified' : 'refused', res.verified ? 'ok' : 'bad');
|
||||
return res;
|
||||
}
|
||||
|
||||
// ---- wiring ---------------------------------------------------------------------------------------------------------
|
||||
function wire() {
|
||||
const form = $('[data-form]'); if (!form) return;
|
||||
const input = form.querySelector('input'); const kind = form.dataset.form;
|
||||
if (q.get(kind === 'light' ? 'address' : 'tx')) input.value = q.get(kind === 'light' ? 'address' : 'tx');
|
||||
form.addEventListener('submit', async e => {
|
||||
e.preventDefault();
|
||||
const v = input.value.trim();
|
||||
const ok = kind === 'light' ? /^0x[0-9a-fA-F]{40}$/.test(v) : /^0x[0-9a-fA-F]{64}$/.test(v);
|
||||
if (!ok) { setStatus(kind === 'light' ? 'an address is 0x and 40 hex digits' : 'a transaction hash is 0x and 64 hex digits', 'bad'); return; }
|
||||
form.querySelector('button').disabled = true;
|
||||
try { if (kind === 'light') await runLight(v); else await runReceipt(v); }
|
||||
catch (err) { setStatus(String(err.message || err), 'bad'); $('[data-result]').innerHTML = `<div class="headline bad"><div class="eyebrow">Could not fetch · Devnet 3, no value</div><p class="pt">${esc(String(err.message || err))}</p></div>`; }
|
||||
finally { form.querySelector('button').disabled = false; }
|
||||
});
|
||||
if (input.value) form.requestSubmit();
|
||||
}
|
||||
if (typeof document !== 'undefined') { if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', wire); else wire(); }
|
||||
388
site/lc/core.js
Normal file
388
site/lc/core.js
Normal file
|
|
@ -0,0 +1,388 @@
|
|||
// Igneum reference apps, the checks (no I/O, no DOM). 8 October 2026. Used by the light wallet (/light), the receipt
|
||||
// page (/receipt) and the one-file offline receipt verifier. Everything here recomputes; nothing is taken on trust
|
||||
// from the node that served the data. `deps` is { blake2b, bls, keccak } (@noble/hashes blake2b and keccak_256,
|
||||
// @noble/curves bls12_381), injected so the browser, Node and the bundled verifier share one file.
|
||||
//
|
||||
// What a balance proof chains together (every link recomputed here):
|
||||
// certificate ──signs──> checkpoint header ──parents──> ... ──parents──> carrier header
|
||||
// carrier header.hash_merkle_root ──merkle path──> coinbase transaction hash ──payload──> IGNS segment record
|
||||
// segment record ──BLS signature by a voter──> public values ──post_root──> MPT account proof ──> balance
|
||||
// What a receipt proof chains together: certificate ──> checkpoint ──parents──> including block ──merkle──> raw tx.
|
||||
//
|
||||
// Formats, from the node's own code (vendor/igneum-node-light at 5b673577 plus e6081dd6): consensus/core/src/hashing
|
||||
// (header, transaction), crypto/merkle (the body root), consensus/core/src/proving.rs (IGNS, SegmentRecord,
|
||||
// BlockStatement), consensus/core/src/finality.rs (the coinbase extra data and IGNF), igneum/exec/src/state.rs
|
||||
// (the keccak-keyed MPT in reth's layout, eth_getProof).
|
||||
import { headerHash, voteKeyHash, verifyCheckpoint, hexToBytes, bytesToHex } from '../verify/core.js';
|
||||
|
||||
export { headerHash, voteKeyHash, verifyCheckpoint, hexToBytes, bytesToHex };
|
||||
|
||||
export const DST_SEGMENT = 'IGNEUM_SEGMENT_RECORD_V1_BLS12381G2_XMD:SHA-256_SSWU_RO_NUL_';
|
||||
export const SEGMENT_RECORD_LEN = 2 + 8 + 8 + 32 + 48 + 20 + 340 + 32 + 96;
|
||||
export const ZERO32 = new Uint8Array(32);
|
||||
const te = new TextEncoder();
|
||||
const strip = s => String(s).replace(/^0x/i, '');
|
||||
const u64le = v => { const b = new Uint8Array(8); new DataView(b.buffer).setBigUint64(0, BigInt(v), true); return b; };
|
||||
const u16le = v => { const b = new Uint8Array(2); new DataView(b.buffer).setUint16(0, Number(v), true); return b; };
|
||||
const u32le = v => { const b = new Uint8Array(4); new DataView(b.buffer).setUint32(0, Number(v), true); return b; };
|
||||
function concat(parts) { const n = parts.reduce((a, p) => a + p.length, 0); const m = new Uint8Array(n); let o = 0; for (const p of parts) { m.set(p, o); o += p.length; } return m; }
|
||||
const eq = (a, b) => a.length === b.length && a.every((x, i) => x === b[i]);
|
||||
const bigOf = b => { let v = 0n; for (const x of b) v = (v << 8n) | BigInt(x); return v; };
|
||||
export const keyed = (blake2b, key) => data => blake2b(data, { dkLen: 32, key: te.encode(key) });
|
||||
|
||||
// ---- the body merkle root (crypto/merkle/src/lib.rs): leaves padded to a power of two, a missing right child is the
|
||||
// zero hash, inner node = BLAKE2b-256 keyed "MerkleBranchHash" over left || right; one leaf is its own root --------
|
||||
export function merkleRoot(leaves, blake2b) {
|
||||
const H = keyed(blake2b, 'MerkleBranchHash');
|
||||
if (leaves.length === 0) return ZERO32;
|
||||
let level = leaves.slice();
|
||||
while (level.length > 1) {
|
||||
const next = [];
|
||||
for (let i = 0; i < level.length; i += 2) next.push(H(concat([level[i], level[i + 1] || ZERO32])));
|
||||
level = next;
|
||||
}
|
||||
return level[0];
|
||||
}
|
||||
export function merklePath(leaves, index) {
|
||||
const path = []; let level = leaves.slice(); let i = index;
|
||||
while (level.length > 1) {
|
||||
const sib = i % 2 === 0 ? (level[i + 1] || ZERO32) : level[i - 1];
|
||||
path.push(sib);
|
||||
const next = []; for (let k = 0; k < level.length; k += 2) next.push(new Uint8Array(0));
|
||||
// only the shape matters here; the hashes are recomputed by the verifier
|
||||
level = next; i = i >> 1;
|
||||
}
|
||||
return path;
|
||||
}
|
||||
export function merkleRootFromPath(leaf, index, siblings, blake2b) {
|
||||
const H = keyed(blake2b, 'MerkleBranchHash');
|
||||
let h = leaf, i = index;
|
||||
for (const s of siblings) { h = i % 2 === 0 ? H(concat([h, s])) : H(concat([s, h])); i = i >> 1; }
|
||||
return h;
|
||||
}
|
||||
|
||||
// ---- the coinbase transaction hash (consensus/core/src/hashing/tx.rs, FULL flags) from the RPC's JSON ------------
|
||||
export function coinbaseTxHash(tx, blake2b, amountWireLen = 8) {
|
||||
const version = Number(tx.version || 0);
|
||||
const parts = [u16le(version), u64le((tx.inputs || []).length)];
|
||||
for (const inp of tx.inputs || []) {
|
||||
parts.push(hexToBytes(strip(inp.previousOutpoint.transactionId)), u32le(inp.previousOutpoint.index));
|
||||
const sig = hexToBytes(strip(inp.signatureScript || ''));
|
||||
parts.push(u64le(sig.length), sig);
|
||||
if (version < 1) parts.push(new Uint8Array([Number(inp.sigOpCount || 0)]));
|
||||
parts.push(u64le(inp.sequence));
|
||||
if (version >= 1) parts.push(u16le(inp.computeBudget || 0));
|
||||
}
|
||||
parts.push(u64le((tx.outputs || []).length));
|
||||
for (const out of tx.outputs || []) {
|
||||
const v = new Uint8Array(amountWireLen); let x = BigInt(out.value);
|
||||
for (let i = 0; i < amountWireLen; i++) { v[i] = Number(x & 0xffn); x >>= 8n; }
|
||||
const spk = hexToBytes(strip(out.scriptPublicKey)); // version u16 LE || script, as the RPC serialises it
|
||||
parts.push(v, spk.subarray(0, 2), u64le(spk.length - 2), spk.subarray(2));
|
||||
if (version >= 1) parts.push(new Uint8Array([out.covenant ? 1 : 0]));
|
||||
}
|
||||
const payload = hexToBytes(strip(tx.payload || ''));
|
||||
parts.push(u64le(tx.lockTime || 0), hexToBytes(strip(tx.subnetworkId)), u64le(tx.gas || 0), u64le(payload.length), payload);
|
||||
const mass = BigInt(tx.mass || 0);
|
||||
if (version < 1) { if (mass > 0n) parts.push(u64le(mass)); } else parts.push(u64le(mass));
|
||||
return keyed(blake2b, 'TransactionHash')(concat(parts));
|
||||
}
|
||||
|
||||
// ---- the coinbase payload: blue_score u64 || subsidy || script version u16 || script len u8 || script || extra; the
|
||||
// extra data ends with nested sections `items || len_le32 || TAG`: IGNF last, IGNP before it, IGNS before that ----
|
||||
export function coinbaseExtraData(payload) {
|
||||
if (payload.length < 19) return new Uint8Array(0);
|
||||
const scriptLen = payload[18];
|
||||
return payload.subarray(19 + scriptLen);
|
||||
}
|
||||
function takeSection(extra, tag) {
|
||||
const n = extra.length;
|
||||
if (n < 8) return { items: null, before: extra };
|
||||
const t = String.fromCharCode(...extra.subarray(n - 4));
|
||||
if (t !== tag) return { items: null, before: extra };
|
||||
const len = new DataView(extra.buffer, extra.byteOffset + n - 8, 4).getUint32(0, true);
|
||||
if (len + 8 > n) return { items: null, before: extra };
|
||||
return { items: extra.subarray(n - 8 - len, n - 8), before: extra.subarray(0, n - 8 - len) };
|
||||
}
|
||||
export function segmentRecordsOf(payload) {
|
||||
const extra = coinbaseExtraData(payload);
|
||||
const f = takeSection(extra, 'IGNF');
|
||||
const p = takeSection(f.before, 'IGNP');
|
||||
const s = takeSection(p.before, 'IGNS');
|
||||
const out = [];
|
||||
if (!s.items) return out;
|
||||
for (let o = 0; o + SEGMENT_RECORD_LEN <= s.items.length; o += SEGMENT_RECORD_LEN) out.push(parseSegmentRecord(s.items.subarray(o, o + SEGMENT_RECORD_LEN)));
|
||||
return out;
|
||||
}
|
||||
export function parseSegmentRecord(b) {
|
||||
if (b.length !== SEGMENT_RECORD_LEN) throw new Error(`segment record is ${b.length} bytes, not ${SEGMENT_RECORD_LEN}`);
|
||||
const dv = new DataView(b.buffer, b.byteOffset, b.byteLength);
|
||||
let o = 0;
|
||||
const version = dv.getUint16(o, true); o += 2;
|
||||
const first = dv.getBigUint64(o, true); o += 8;
|
||||
const last = dv.getBigUint64(o, true); o += 8;
|
||||
const block = b.subarray(o, o + 32); o += 32;
|
||||
const pubkey = b.subarray(o, o + 48); o += 48;
|
||||
const payout = b.subarray(o, o + 20); o += 20;
|
||||
const publicValues = b.subarray(o, o + 340); o += 340;
|
||||
const proofHash = b.subarray(o, o + 32); o += 32;
|
||||
const signature = b.subarray(o, o + 96);
|
||||
return { bytes: b, version, first, last, block, pubkey, payout, publicValues, proofHash, signature, statement: parseBlockStatement(publicValues) };
|
||||
}
|
||||
export function parseBlockStatement(b) {
|
||||
const dv = new DataView(b.buffer, b.byteOffset, b.byteLength);
|
||||
const h = o => bytesToHex(b.subarray(o, o + 32));
|
||||
return {
|
||||
chain_id: dv.getBigUint64(0), number: dv.getBigUint64(8), block_hash: h(16), parent_hash: h(48), shard_count: dv.getUint32(80),
|
||||
tx_commitment: h(84), pre_root: h(116), post_root: h(148), receipts: h(180), gas_used: dv.getBigUint64(212), pgas_used: dv.getBigUint64(220),
|
||||
executed: dv.getUint32(228), skipped: dv.getUint32(232), provers: h(236), shard_vk: h(268), agg_vk: h(300), chain_len: dv.getBigUint64(332),
|
||||
};
|
||||
}
|
||||
export function segmentRecordMessage(chainId, r) {
|
||||
return concat([te.encode('igneum-segment-record-v1/' + chainId), new Uint8Array([0]), u64le(r.first), u64le(r.last), r.block, r.payout, r.publicValues, r.proofHash]);
|
||||
}
|
||||
export function verifySegmentRecordSignature(chainId, r, bls) {
|
||||
const L = bls.longSignatures;
|
||||
return L.verify(r.signature, L.hash(segmentRecordMessage(chainId, r), DST_SEGMENT), r.pubkey);
|
||||
}
|
||||
|
||||
// ---- RLP and the Merkle Patricia trie (keccak-keyed, Ethereum's layout) ----------------------------------------
|
||||
export function rlpDecode(b) {
|
||||
const [item, rest] = rlpItem(b, 0);
|
||||
if (rest !== b.length) throw new Error('rlp: trailing bytes');
|
||||
return item;
|
||||
}
|
||||
function rlpItem(b, o) {
|
||||
if (o >= b.length) throw new Error('rlp: short');
|
||||
const x = b[o];
|
||||
if (x < 0x80) return [b.subarray(o, o + 1), o + 1];
|
||||
if (x < 0xb8) { const n = x - 0x80; return [b.subarray(o + 1, o + 1 + n), o + 1 + n]; }
|
||||
if (x < 0xc0) { const ll = x - 0xb7; const n = Number(bigOf(b.subarray(o + 1, o + 1 + ll))); return [b.subarray(o + 1 + ll, o + 1 + ll + n), o + 1 + ll + n]; }
|
||||
let n, start;
|
||||
if (x < 0xf8) { n = x - 0xc0; start = o + 1; } else { const ll = x - 0xf7; n = Number(bigOf(b.subarray(o + 1, o + 1 + ll))); start = o + 1 + ll; }
|
||||
const end = start + n; if (end > b.length) throw new Error('rlp: list overruns');
|
||||
const items = []; let p = start;
|
||||
while (p < end) { const [it, q] = rlpItem(b, p); items.push(it); p = q; }
|
||||
return [items, end];
|
||||
}
|
||||
export function rlpEncode(item) {
|
||||
if (item instanceof Uint8Array) {
|
||||
if (item.length === 1 && item[0] < 0x80) return item;
|
||||
return concat([rlpLen(item.length, 0x80), item]);
|
||||
}
|
||||
const body = concat(item.map(rlpEncode));
|
||||
return concat([rlpLen(body.length, 0xc0), body]);
|
||||
}
|
||||
function rlpLen(n, base) {
|
||||
if (n < 56) return new Uint8Array([base + n]);
|
||||
const bytes = []; let x = n; while (x > 0) { bytes.unshift(x & 0xff); x = Math.floor(x / 256); }
|
||||
return new Uint8Array([base + 55 + bytes.length, ...bytes]);
|
||||
}
|
||||
export const trimBig = v => { v = BigInt(v); if (v === 0n) return new Uint8Array(0); let h = v.toString(16); if (h.length % 2) h = '0' + h; return hexToBytes(h); };
|
||||
const nibbles = b => { const out = []; for (const x of b) { out.push(x >> 4, x & 15); } return out; };
|
||||
function hpDecode(b) { // hex-prefix: returns [nibbles, isLeaf]
|
||||
const n = nibbles(b); const flag = n[0];
|
||||
const body = flag & 1 ? n.slice(1) : n.slice(2);
|
||||
return [body, (flag & 2) !== 0];
|
||||
}
|
||||
// Walks the proof from the root to the key; returns the value bytes (Uint8Array) or null for a proven absence.
|
||||
// Throws on any node that does not hash to its reference, any malformed node, or a path that does not reach a verdict.
|
||||
export function mptVerify(root, key, proofNodes, keccak) {
|
||||
const path = nibbles(key); let want = root; let pos = 0;
|
||||
const byHash = new Map(); for (const n of proofNodes) byHash.set(bytesToHex(keccak(n)), n);
|
||||
if (proofNodes.length === 0) { if (eq(root, keccak(rlpEncode(new Uint8Array(0))))) return null; throw new Error('mpt: no proof nodes for a non-empty root'); }
|
||||
let node = byHash.get(bytesToHex(want));
|
||||
if (!node) throw new Error('mpt: the first proof node is not the root');
|
||||
for (let guard = 0; guard < 128; guard++) {
|
||||
const items = rlpDecode(node);
|
||||
if (!Array.isArray(items)) throw new Error('mpt: node is not a list');
|
||||
let next;
|
||||
if (items.length === 17) {
|
||||
if (pos === path.length) { const v = items[16]; return v.length ? v : null; }
|
||||
next = items[path[pos]]; pos += 1;
|
||||
} else if (items.length === 2) {
|
||||
const [np, leaf] = hpDecode(items[0]);
|
||||
for (let i = 0; i < np.length; i++) if (path[pos + i] !== np[i]) return null; // the key diverges: proven absent
|
||||
pos += np.length;
|
||||
if (leaf) { if (pos !== path.length) return null; return items[1]; }
|
||||
next = items[1];
|
||||
} else throw new Error('mpt: node with ' + items.length + ' items');
|
||||
if (next instanceof Uint8Array) {
|
||||
if (next.length === 0) return null; // an empty slot: proven absent
|
||||
if (next.length !== 32) throw new Error('mpt: bad reference');
|
||||
node = byHash.get(bytesToHex(next));
|
||||
if (!node) throw new Error('mpt: a referenced node is missing from the proof');
|
||||
want = next;
|
||||
} else {
|
||||
node = rlpEncode(next); // an embedded node (under 32 bytes)
|
||||
}
|
||||
}
|
||||
throw new Error('mpt: path too deep');
|
||||
}
|
||||
// Verifies an eth_getProof account proof against `stateRoot`; returns {exists, nonce, balance, storageRoot, codeHash}.
|
||||
export function verifyAccountProof(stateRoot, address, proofHex, keccak) {
|
||||
const key = keccak(hexToBytes(strip(address)));
|
||||
const v = mptVerify(stateRoot, key, proofHex.map(h => hexToBytes(strip(h))), keccak);
|
||||
if (v === null) return { exists: false, nonce: 0n, balance: 0n, storageRoot: null, codeHash: null };
|
||||
const items = rlpDecode(v);
|
||||
if (!Array.isArray(items) || items.length !== 4) throw new Error('mpt: account leaf is not [nonce, balance, storageRoot, codeHash]');
|
||||
return { exists: true, nonce: bigOf(items[0]), balance: bigOf(items[1]), storageRoot: bytesToHex(items[2]), codeHash: bytesToHex(items[3]) };
|
||||
}
|
||||
export function verifyStorageProof(storageRoot, slot, proofHex, keccak) {
|
||||
const key = keccak(hexToBytes(strip(slot).padStart(64, '0')));
|
||||
const v = mptVerify(storageRoot, key, proofHex.map(h => hexToBytes(strip(h))), keccak);
|
||||
if (v === null) return 0n;
|
||||
const item = rlpDecode(v);
|
||||
if (Array.isArray(item)) throw new Error('mpt: storage leaf is a list');
|
||||
return bigOf(item);
|
||||
}
|
||||
|
||||
// ---- the header path: headers[0] is the oldest, each next header names the previous as a direct parent ------------
|
||||
export function verifyHeaderPath(headers, blake2b, fromHash, toHash) {
|
||||
if (!headers.length) throw new Error('no headers');
|
||||
for (let i = 0; i < headers.length; i++) {
|
||||
const h = headers[i];
|
||||
const got = headerHash(h, blake2b);
|
||||
if (got !== strip(h.hash)) throw new Error(`header ${i} (${strip(h.hash).slice(0, 12)}) does not recompute: ${got.slice(0, 12)}`);
|
||||
if (i > 0) {
|
||||
const direct = (h.parents_by_level && h.parents_by_level[0]) || [];
|
||||
if (!direct.includes(strip(headers[i - 1].hash))) throw new Error(`header ${i} does not name header ${i - 1} as a direct parent`);
|
||||
}
|
||||
}
|
||||
if (fromHash && strip(headers[0].hash) !== strip(fromHash)) throw new Error('the first header is not the block the proof starts from');
|
||||
if (toHash && strip(headers[headers.length - 1].hash) !== strip(toHash)) throw new Error('the last header is not the certified checkpoint');
|
||||
return headers.length;
|
||||
}
|
||||
|
||||
// ---- the balance proof ------------------------------------------------------------------------------------------
|
||||
// `cp` is the /api/checkpoint body (certificate, voters, headers to the previous lock); `proof` is the /balance body:
|
||||
// { address, chain_id, checkpoint: {hash, index}, headers: [carrier .. checkpoint], carrier: { coinbase: <RpcTransaction>,
|
||||
// evm_tx_hashes: [hex...], leaf_index: 0, merkle_siblings: [hex...] }, segment_record_hex, account: eth_getProof result }.
|
||||
// Returns { verified, steps: [{name, ok, detail}], balance, ... } and stops at the first failing step.
|
||||
export function verifyBalance(cp, proof, deps) {
|
||||
const { blake2b, bls, keccak } = deps;
|
||||
const steps = []; const t0 = now();
|
||||
const step = (name, fn) => { try { const d = fn(); steps.push({ name, ok: true, detail: d }); return d; } catch (e) { steps.push({ name, ok: false, detail: String(e.message || e) }); throw e; } };
|
||||
const done = extra => ({ ...extra, steps, ms: Math.round((now() - t0) * 10) / 10 });
|
||||
try {
|
||||
const cert = step('certificate: BLS aggregate over the checkpoint, 2/3 of active and 17/30 of total weight', () => {
|
||||
const r = verifyCheckpoint(cp, { blake2b, bls });
|
||||
if (!r.verified) throw new Error(r.reason);
|
||||
return `checkpoint ${r.index}, ${r.signers} of ${r.voters} voters, ${(r.weight_fraction_total * 100).toFixed(1)}% of total weight, ${r.headers_checked} headers to the previous lock`;
|
||||
});
|
||||
step('the proof names the certified checkpoint', () => {
|
||||
if (strip(proof.checkpoint.hash) !== strip(cp.hash) || Number(proof.checkpoint.index) !== Number(cp.index)) throw new Error('the balance proof is for another checkpoint than the certificate');
|
||||
if (proof.chain_id !== cp.chain_id) throw new Error(`chain ${proof.chain_id} is not ${cp.chain_id}`);
|
||||
return `${cp.chain_id}, checkpoint ${cp.index}`;
|
||||
});
|
||||
step('header chain from the carrier block up to the checkpoint (every hash recomputed, every parent link checked)', () =>
|
||||
`${verifyHeaderPath(proof.headers, blake2b, proof.headers[0].hash, cp.hash)} headers, ${strip(proof.headers[0].hash).slice(0, 12)} up to ${strip(cp.hash).slice(0, 12)}`);
|
||||
const carrier = proof.headers[0];
|
||||
const record = step('the coinbase transaction is in the carrier block (hash recomputed, merkle path to hash_merkle_root)', () => {
|
||||
const cb = coinbaseTxHash(proof.carrier.coinbase, blake2b, proof.carrier.amount_wire_len || 8);
|
||||
const sibs = proof.carrier.merkle_siblings.map(s => hexToBytes(strip(s)));
|
||||
const root = merkleRootFromPath(cb, Number(proof.carrier.leaf_index), sibs, blake2b);
|
||||
if (bytesToHex(root) !== strip(carrier.hash_merkle_root)) throw new Error('the merkle path does not reach the carrier\'s hash_merkle_root');
|
||||
const recs = segmentRecordsOf(hexToBytes(strip(proof.carrier.coinbase.payload)));
|
||||
const want = strip(proof.segment_record_hex);
|
||||
const rec = recs.find(r => bytesToHex(r.bytes) === want);
|
||||
if (!rec) throw new Error(`the carrier's coinbase carries ${recs.length} segment record(s), none is the named one`);
|
||||
return `coinbase ${bytesToHex(cb).slice(0, 12)}, leaf ${proof.carrier.leaf_index} of ${proof.carrier.evm_tx_hashes.length + 1}, record for blocks ${rec.first} to ${rec.last}`;
|
||||
}) && segmentRecordsOf(hexToBytes(strip(proof.carrier.coinbase.payload))).find(r => bytesToHex(r.bytes) === strip(proof.segment_record_hex));
|
||||
const agg = step('the segment record is signed by its aggregator (BLS over the record under the network\'s tag)', () => {
|
||||
if (!verifySegmentRecordSignature(cp.chain_id, record, bls)) throw new Error('the aggregator\'s signature does not verify');
|
||||
// the aggregator signs with a vote key; a prove-only key has no mining weight and is not in the voter table, which is
|
||||
// reported, not refused (the record's standing comes from the nodes' native check and the payout, not from weight)
|
||||
const kh = voteKeyHash(record.pubkey, blake2b);
|
||||
const voter = (cp.voters || []).find(v => (v.vote_key_hash || voteKeyHash(hexToBytes(v.pubkey_hex), blake2b)) === kh);
|
||||
const total = (cp.voters || []).reduce((a, v) => a + Number(v.weight), 0);
|
||||
return voter
|
||||
? `aggregator ${kh.slice(0, 12)}, a voter with weight ${voter.weight} of ${total} (${(100 * Number(voter.weight) / total).toFixed(2)}%)`
|
||||
: `aggregator ${kh.slice(0, 12)}, a prove-only key (not in the voter table of ${cp.voters.length}, no mining weight)`;
|
||||
});
|
||||
const st = record.statement;
|
||||
step('the record\'s statement names the chain and the block whose state it commits', () => {
|
||||
if (Number(st.number) !== Number(record.last)) throw new Error('the statement is not for the segment\'s last block');
|
||||
if (bytesToHex(record.block) !== st.block_hash) throw new Error('the record\'s block hash is not the statement\'s');
|
||||
// the EVM chain id in the statement is the one in force at that block (Devnet 3: 4463 below its class v5 floor, 4464 above);
|
||||
// the record's binding to the chain is the signed message, which names the network by its string ("igneum-devnet-3")
|
||||
const ids = cp.chain_id === 'igneum-devnet-3' ? [4463, 4464] : [Number(proof.account.evm_chain_id)];
|
||||
if (!ids.includes(Number(st.chain_id))) throw new Error(`statement chain id ${st.chain_id} is not ${cp.chain_id}'s (${ids.join(' or ')})`);
|
||||
return `EVM chain id ${st.chain_id}, chain block ${st.number}, post_root ${st.post_root.slice(0, 12)}, ${st.executed} executed, chain_len ${st.chain_len}`;
|
||||
});
|
||||
let acct = null;
|
||||
step('account proof under post_root (keccak-keyed Merkle Patricia trie, every node hashed)', () => {
|
||||
if (Number(proof.account.blockNumber) !== Number(st.number)) throw new Error('the account proof is for another block than the statement');
|
||||
if (strip(proof.account.stateRoot) !== st.post_root) throw new Error('the node\'s state root is not the proven post_root');
|
||||
const a = verifyAccountProof(hexToBytes(st.post_root), proof.address, proof.account.accountProof, keccak);
|
||||
acct = a;
|
||||
if (a.exists && a.balance !== BigInt(proof.account.balance)) throw new Error('the proven balance is not the balance the node reported');
|
||||
if (!a.exists && BigInt(proof.account.balance) !== 0n) throw new Error('the node reports a balance for an account the trie does not hold');
|
||||
return `${proof.account.accountProof.length} nodes, ${a.exists ? 'account present' : 'account absent (exclusion proof)'}`;
|
||||
});
|
||||
const balance = acct.exists ? acct.balance : 0n;
|
||||
return done({ verified: true, balance, balance_wei: balance.toString(), nonce: acct.nonce.toString(), block: Number(st.number), post_root: st.post_root, checkpoint: Number(cp.index), headers: proof.headers.length, aggregator: agg, certificate: cert });
|
||||
} catch (e) {
|
||||
return done({ verified: false, reason: String(e.message || e) });
|
||||
}
|
||||
}
|
||||
|
||||
// ---- the receipt proof ------------------------------------------------------------------------------------------
|
||||
// `receipt` = { chain_id, tx_hash, raw_tx_hex, checkpoint: {hash, index, certificate: <the /api/checkpoint body>},
|
||||
// including_block: { header, evm_tx_hashes, leaf_index, merkle_siblings }, headers: [including .. checkpoint],
|
||||
// execution (optional, as the node reports it): { chain_block, status, gas_used, ... } }
|
||||
export function verifyReceipt(receipt, deps) {
|
||||
const { blake2b, bls, keccak } = deps;
|
||||
const steps = []; const t0 = now();
|
||||
const step = (name, fn) => { try { const d = fn(); steps.push({ name, ok: true, detail: d }); return d; } catch (e) { steps.push({ name, ok: false, detail: String(e.message || e) }); throw e; } };
|
||||
const done = extra => ({ ...extra, steps, ms: Math.round((now() - t0) * 10) / 10 });
|
||||
try {
|
||||
const cp = receipt.checkpoint.certificate;
|
||||
const cert = step('certificate: BLS aggregate over the checkpoint, 2/3 of active and 17/30 of total weight', () => {
|
||||
const r = verifyCheckpoint(cp, { blake2b, bls });
|
||||
if (!r.verified) throw new Error(r.reason);
|
||||
if (strip(cp.hash) !== strip(receipt.checkpoint.hash) || receipt.chain_id !== cp.chain_id) throw new Error('the receipt names another checkpoint or chain than its certificate');
|
||||
return `checkpoint ${r.index} on ${cp.chain_id}, ${r.signers} of ${r.voters} voters, ${(r.weight_fraction_total * 100).toFixed(1)}% of total weight`;
|
||||
});
|
||||
let tx = null;
|
||||
step('the transaction hash is keccak256 of the raw signed transaction', () => {
|
||||
const raw = hexToBytes(strip(receipt.raw_tx_hex));
|
||||
const h = bytesToHex(keccak(raw));
|
||||
if (h !== strip(receipt.tx_hash)) throw new Error(`the raw bytes hash to ${h.slice(0, 12)}, not ${strip(receipt.tx_hash).slice(0, 12)}`);
|
||||
tx = parseTx(raw);
|
||||
return `${raw.length} bytes, type ${tx.type}, to ${tx.to || 'contract creation'}, value ${tx.value} wei, nonce ${tx.nonce}`;
|
||||
});
|
||||
step('header chain from the including block up to the checkpoint (every hash recomputed, every parent link checked)', () =>
|
||||
`${verifyHeaderPath(receipt.headers, blake2b, receipt.including_block.header.hash, cp.hash)} headers, ${strip(receipt.headers[0].hash).slice(0, 12)} up to ${strip(cp.hash).slice(0, 12)}`);
|
||||
step('the transaction is a leaf of the including block\'s hash_merkle_root', () => {
|
||||
const ib = receipt.including_block;
|
||||
const sibs = ib.merkle_siblings.map(s => hexToBytes(strip(s)));
|
||||
const root = merkleRootFromPath(hexToBytes(strip(receipt.tx_hash)), Number(ib.leaf_index), sibs, blake2b);
|
||||
if (bytesToHex(root) !== strip(receipt.headers[0].hash_merkle_root)) throw new Error('the merkle path does not reach the including block\'s hash_merkle_root');
|
||||
return `leaf ${ib.leaf_index} of ${ib.leaf_count}`;
|
||||
});
|
||||
return done({ verified: true, tx, headers: receipt.headers.length, checkpoint: Number(cp.index), certificate: cert, block: strip(receipt.headers[0].hash), block_daa: receipt.headers[0].daa_score, block_time: receipt.headers[0].timestamp });
|
||||
} catch (e) {
|
||||
return done({ verified: false, reason: String(e.message || e) });
|
||||
}
|
||||
}
|
||||
|
||||
// A typed (EIP-1559 type 2, EIP-2930 type 1) or legacy raw transaction: the fields a receipt shows. No signature
|
||||
// recovery here (the node's `from` is shown as reported; the chain's own check of the signature is what put the
|
||||
// transaction in a block).
|
||||
export function parseTx(raw) {
|
||||
const type = raw[0] <= 0x7f ? raw[0] : 0;
|
||||
const body = rlpDecode(type ? raw.subarray(1) : raw);
|
||||
const hex = b => '0x' + bytesToHex(b);
|
||||
if (type === 2) return { type, chain_id: bigOf(body[0]).toString(), nonce: bigOf(body[1]).toString(), to: body[5].length ? hex(body[5]) : null, value: bigOf(body[6]).toString(), data: hex(body[7]), gas: bigOf(body[4]).toString() };
|
||||
if (type === 1) return { type, chain_id: bigOf(body[0]).toString(), nonce: bigOf(body[1]).toString(), to: body[4].length ? hex(body[4]) : null, value: bigOf(body[5]).toString(), data: hex(body[6]), gas: bigOf(body[3]).toString() };
|
||||
return { type: 0, nonce: bigOf(body[0]).toString(), to: body[3].length ? hex(body[3]) : null, value: bigOf(body[4]).toString(), data: hex(body[5]), gas: bigOf(body[2]).toString() };
|
||||
}
|
||||
|
||||
export function formatIgn(wei, decimals = 18) {
|
||||
const v = BigInt(wei); const base = 10n ** BigInt(decimals);
|
||||
const whole = v / base; let frac = (v % base).toString().padStart(decimals, '0').replace(/0+$/, '');
|
||||
if (frac.length > 6) frac = frac.slice(0, 6);
|
||||
return whole.toString() + (frac ? '.' + frac : '');
|
||||
}
|
||||
const now = () => (typeof performance !== 'undefined' ? performance : Date).now();
|
||||
86
site/lc/test.html
Normal file
86
site/lc/test.html
Normal file
|
|
@ -0,0 +1,86 @@
|
|||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Igneum reference apps test: genuine and tampered</title>
|
||||
<meta name="robots" content="noindex">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<style>body{font-family:ui-monospace,Menlo,monospace;font-size:13px;background:#0C0C0E;color:#E8E4DA;padding:24px;max-width:1100px}h1{font-size:16px}h2{font-size:14px;margin-top:28px}table{display:block;overflow-x:auto;max-width:100%}code{overflow-wrap:anywhere}td{padding:4px 10px;border-bottom:1px solid #222;vertical-align:top}.ok{color:#7ED957}.bad{color:#F2541B}p{max-width:90ch}</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Igneum reference apps: the negative cases, in this tab (Devnet 3, no value)</h1>
|
||||
<p>Each row runs <code>site/lc/core.js</code> on live Devnet 3 data from <code id="api"></code>. A tampered case must read <b>refused</b>; the genuine case must read <b>verified</b>. The same cases run under Node in <code>tools/reference-apps/light-service/verify.test.mjs</code>. Parameters: <code>?api=</code> (the read service), <code>?address=</code> (the balance to prove; default: the miner of the latest block), <code>?tx=</code> (a transaction; default: one in a recent block).</p>
|
||||
<h2>Receipt</h2>
|
||||
<table id="r"><thead><tr><td>case</td><td>result</td><td>ms</td><td>reason</td></tr></thead><tbody></tbody></table>
|
||||
<h2>Balance</h2>
|
||||
<table id="b"><thead><tr><td>case</td><td>result</td><td>ms</td><td>reason</td></tr></thead><tbody></tbody></table>
|
||||
<pre id="done"></pre>
|
||||
<script type="module">
|
||||
import { blake2b } from 'https://cdn.jsdelivr.net/npm/@noble/hashes@2.4.0/blake2.js/+esm';
|
||||
import { keccak_256 } from 'https://cdn.jsdelivr.net/npm/@noble/hashes@2.4.0/sha3.js/+esm';
|
||||
import { bls12_381 } from 'https://cdn.jsdelivr.net/npm/@noble/curves@2.4.0/bls12-381.js/+esm';
|
||||
import { verifyBalance, verifyReceipt } from './core.js';
|
||||
const deps = { blake2b, bls: bls12_381, keccak: keccak_256 };
|
||||
const q = new URLSearchParams(location.search);
|
||||
const API = (q.get('api') || 'https://rpc.devnet.igneum.network/light').replace(/\/$/, '');
|
||||
const RPC = q.get('rpc') || 'https://rpc.devnet.igneum.network';
|
||||
document.getElementById('api').textContent = API;
|
||||
const clone = x => JSON.parse(JSON.stringify(x));
|
||||
const flipHex = (s, at) => { const h = s.replace(/^0x/, ''); const i = Math.min(at, h.length - 1); const d = (parseInt(h[i], 16) ^ 1).toString(16); return (s.startsWith('0x') ? '0x' : '') + h.slice(0, i) + d + h.slice(i + 1); };
|
||||
const get = async u => { const r = await fetch(u, { cache: 'no-store' }); const j = await r.json(); if (!j.ok) throw new Error(j.error || r.status); return j; };
|
||||
const rpc = async (method, params) => { const r = await fetch(RPC, { method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify({ jsonrpc: '2.0', id: 1, method, params }) }); const j = await r.json(); if (j.error) throw new Error(j.error.message); return j.result; };
|
||||
const out = [];
|
||||
function row(table, name, r, want) {
|
||||
const ok = r.verified === want; out.push({ table, name, want, ...r, behaved: ok });
|
||||
const tr = document.createElement('tr');
|
||||
tr.innerHTML = `<td>${name}</td><td class="${ok ? 'ok' : 'bad'}">${r.verified ? 'verified' : 'refused'}${ok ? '' : ' (WRONG)'}</td><td>${r.ms}</td><td>${r.reason || ''}</td>`;
|
||||
document.querySelector('#' + table + ' tbody').appendChild(tr);
|
||||
}
|
||||
try {
|
||||
const cp = await get(`${API}/checkpoint`);
|
||||
// a transaction to prove: the first in a chain block below the checkpoint
|
||||
let tx = q.get('tx');
|
||||
if (!tx) { const cb = await rpc('eth_getBlockByHash', ['0x' + cp.hash, false]); const n = parseInt(cb.number, 16); for (let k = n - 1; k > n - 200 && !tx; k--) { const b = await rpc('eth_getBlockByNumber', ['0x' + k.toString(16), false]); if (b && b.transactions.length) tx = b.transactions[0]; } }
|
||||
const rr = await get(`${API}/receipt?tx=${tx}&checkpoint=${cp.hash}&index=${cp.index}`);
|
||||
const receipt = { format: 'igneum-receipt-v1', ...rr, checkpoint: { ...rr.checkpoint, certificate: rr.checkpoint.certificate || cp } };
|
||||
const R = [
|
||||
['raw transaction altered by one nibble', d => { d.raw_tx_hex = flipHex(d.raw_tx_hex, 40); }],
|
||||
['transaction hash altered', d => { d.tx_hash = flipHex(d.tx_hash, 10); }],
|
||||
['merkle leaf index moved', d => { d.including_block.leaf_index = d.including_block.leaf_index === 1 ? 2 : 1; }],
|
||||
['a merkle sibling altered', d => { d.including_block.merkle_siblings[0] = flipHex(d.including_block.merkle_siblings[0], 3); }],
|
||||
['a header removed from the path', d => { if (d.headers.length > 2) d.headers.splice(Math.floor(d.headers.length / 2), 1); else d.headers[0].nonce = String(BigInt(d.headers[0].nonce) ^ 1n); }],
|
||||
['a header nonce altered', d => { const h = d.headers[Math.floor(d.headers.length / 2)]; h.nonce = String(BigInt(h.nonce) ^ 1n); }],
|
||||
['certificate signature altered', d => { d.checkpoint.certificate.certificate.aggregate_signature_hex = flipHex(d.checkpoint.certificate.certificate.aggregate_signature_hex, 20); }],
|
||||
['receipt names another checkpoint than its certificate', d => { d.checkpoint.hash = flipHex(d.checkpoint.hash, 60); }],
|
||||
];
|
||||
for (const [name, mutate] of R) { const d = clone(receipt); mutate(d); row('r', name, verifyReceipt(d, deps), false); }
|
||||
row('r', `genuine receipt for ${tx.slice(0, 14)} (${receipt.headers.length} headers, checkpoint ${cp.index})`, verifyReceipt(receipt, deps), true);
|
||||
// a balance to prove
|
||||
let address = q.get('address');
|
||||
if (!address) { const b = await rpc('eth_getBlockByNumber', ['latest', false]); address = b.igneum.rewards[0].miner; }
|
||||
let proof = null;
|
||||
try { proof = await get(`${API}/balance?address=${address}&checkpoint=${cp.hash}&index=${cp.index}`); } catch (e) { document.querySelector('#b tbody').innerHTML = `<tr><td colspan="4" class="bad">balance proof not available: ${e.message}</td></tr>`; }
|
||||
if (proof && proof.checkpoint_certificate) Object.assign(cp, proof.checkpoint_certificate);
|
||||
if (proof) {
|
||||
const B = [
|
||||
['account proof: a node altered', d => { const i = d.account.accountProof.length - 1; d.account.accountProof[i] = flipHex(d.account.accountProof[i], 30); }],
|
||||
['reported balance raised by one wei', d => { d.account.balance = '0x' + (BigInt(d.account.balance) + 1n).toString(16); }],
|
||||
['state root altered', d => { d.account.stateRoot = flipHex(d.account.stateRoot, 8); }],
|
||||
['post_root altered inside the segment record', d => { d.segment_record_hex = flipHex(d.segment_record_hex, 2 * (2 + 8 + 8 + 32 + 48 + 20 + 148) + 3); }],
|
||||
['aggregator signature altered', d => { d.segment_record_hex = flipHex(d.segment_record_hex, d.segment_record_hex.length - 10); }],
|
||||
['coinbase payload altered', d => { d.carrier.coinbase.payload = flipHex(d.carrier.coinbase.payload, 30); }],
|
||||
['a merkle sibling altered (or added to a one-leaf body)', d => { if (d.carrier.merkle_siblings.length) d.carrier.merkle_siblings[0] = flipHex(d.carrier.merkle_siblings[0], 1); else d.carrier.merkle_siblings.push('00'.repeat(32)); }],
|
||||
['a header removed from the path', d => { if (d.headers.length > 2) d.headers.splice(1, 1); else d.headers[0].nonce = String(BigInt(d.headers[0].nonce) ^ 1n); }],
|
||||
['another address with this proof', d => { d.address = '0x' + '11'.repeat(20); }],
|
||||
];
|
||||
for (const [name, mutate] of B) { const d = clone(proof); mutate(d); row('b', name, verifyBalance(cp, d, deps), false); }
|
||||
{ const c = clone(cp); c.certificate.aggregate_signature_hex = flipHex(c.certificate.aggregate_signature_hex, 20); row('b', 'certificate signature altered', verifyBalance(c, proof, deps), false); }
|
||||
const g = verifyBalance(cp, proof, deps);
|
||||
row('b', `genuine balance of ${address.slice(0, 12)} at chain block ${proof.segment.last} (${proof.headers.length} headers, checkpoint ${cp.index})`, g, true);
|
||||
}
|
||||
} catch (e) { document.getElementById('done').textContent = 'ERROR ' + (e.message || e); }
|
||||
const bad = out.filter(x => !x.behaved).length + (document.getElementById('done').textContent.startsWith('ERROR') ? 1 : 0);
|
||||
document.getElementById('done').textContent += (bad ? `\nFAILED ${bad} case(s)` : `\nRESULT every case behaved (${out.length} cases)`) + '\n' + JSON.stringify(out.map(x => ({ table: x.table, name: x.name, verified: x.verified, ms: x.ms, reason: x.reason || null })));
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
5322
site/lc/verify-receipt.js
Normal file
5322
site/lc/verify-receipt.js
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -4,13 +4,13 @@
|
|||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
|
||||
<title>Igneum ledger: every criticism, answered</title>
|
||||
<meta name="description" content="Every criticism Igneum expects, in the critic's words, with what was done, the status and the date. 192 entries. Nothing deleted, nothing softened.">
|
||||
<meta name="description" content="Every criticism Igneum expects, in the critic's words, with what was done, the status and the date. 193 entries. Nothing deleted, nothing softened.">
|
||||
<link rel="canonical" href="https://igneum.network/ledger">
|
||||
<meta name="theme-color" content="#0C0C0E">
|
||||
<meta property="og:type" content="website">
|
||||
<meta property="og:site_name" content="Igneum">
|
||||
<meta property="og:title" content="Igneum ledger: every criticism, answered">
|
||||
<meta property="og:description" content="192 criticisms in the critic's words, with what was done, the status and the date.">
|
||||
<meta property="og:description" content="193 criticisms in the critic's words, with what was done, the status and the date.">
|
||||
<meta property="og:url" content="https://igneum.network/ledger">
|
||||
<meta property="og:image" content="https://igneum.network/og-small.png?v=3">
|
||||
<meta property="og:image:width" content="256">
|
||||
|
|
@ -18,7 +18,7 @@
|
|||
<meta property="og:image:alt" content="Igneum. Mined by GPUs. Proven by fire.">
|
||||
<meta name="twitter:card" content="summary">
|
||||
<meta name="twitter:title" content="Igneum ledger: every criticism, answered">
|
||||
<meta name="twitter:description" content="192 criticisms in the critic's words, with what was done, the status and the date.">
|
||||
<meta name="twitter:description" content="193 criticisms in the critic's words, with what was done, the status and the date.">
|
||||
<meta name="twitter:image" content="https://igneum.network/og-small.png?v=3">
|
||||
<meta name="twitter:image:alt" content="Igneum. Mined by GPUs. Proven by fire.">
|
||||
<link rel="icon" href="/favicon.ico" sizes="48x48">
|
||||
|
|
@ -90,6 +90,7 @@ blockquote{margin:10px 0;padding:10px 14px;border-left:3px solid var(--line-2);c
|
|||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-mine" data-group="mine" aria-expanded="false" aria-controls="nav-panel-mine" aria-haspopup="true">Mine<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-network" data-group="network" aria-expanded="false" aria-controls="nav-panel-network" aria-haspopup="true">Network<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-learn" data-group="learn" aria-expanded="false" aria-controls="nav-panel-learn" aria-haspopup="true">Learn<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-build" data-group="build" aria-expanded="false" aria-controls="nav-panel-build" aria-haspopup="true">Build<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
</div>
|
||||
<div class="nav-controls">
|
||||
<button class="btn icon-btn" type="button" data-theme-toggle aria-label="Switch to light theme"><svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><circle cx="12" cy="12" r="4"/><path d="M12 2v2m0 16v2M2 12h2m16 0h2M5 5l1 1m12 12 1 1M5 19l1-1M18 6l1-1"/></svg></button>
|
||||
|
|
@ -107,7 +108,6 @@ blockquote{margin:10px 0;padding:10px 14px;border-left:3px solid var(--line-2);c
|
|||
<a href="/wallet" data-nav="wallet"><b>The wallet</b><span>Your coins. Final means final.</span></a>
|
||||
<a href="/miners" data-nav="miners"><b>GPU bench table</b><span>Measured rates, card by card.</span></a>
|
||||
<a href="/dev-fee" data-nav="dev-fee"><b>The dev fee</b><span>The optional one, in full view, off with one flag.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Testnet faucet</b><span>Test coin for an address, once a day.</span></a>
|
||||
<a href="/metamask" data-nav="metamask"><b>Add to MetaMask</b><span>Igneum as a network in your wallet.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -118,6 +118,9 @@ blockquote{margin:10px 0;padding:10px 14px;border-left:3px solid var(--line-2);c
|
|||
<a href="/journey" data-nav="journey"><b>The journey</b><span>Six phases, four gates, the log behind them.</span></a>
|
||||
<a href="/bench" data-nav="bench"><b>Engineering log</b><span>Every measurement, with the commands that made it.</span></a>
|
||||
<a href="/evidence" data-nav="evidence"><b>Evidence</b><span>Every claim and how far it is tested.</span></a>
|
||||
<a href="/light" data-nav="light"><b>Light wallet</b><span>A balance your browser proves, trusting no node.</span></a>
|
||||
<a href="/receipt" data-nav="receipt"><b>Payment receipt</b><span>A receipt any third party re-verifies offline.</span></a>
|
||||
<a href="/oracle" data-nav="oracle"><b>State oracle on Sepolia</b><span>Devnet 3 balances read from another chain.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-panel" id="nav-panel-learn" data-group="learn" role="region" aria-labelledby="nav-btn-learn" hidden>
|
||||
|
|
@ -130,6 +133,14 @@ blockquote{margin:10px 0;padding:10px 14px;border-left:3px solid var(--line-2);c
|
|||
<a href="/provenance" data-nav="provenance"><b>Built on the shoulders</b><span>Every borrowed part, credited.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-panel" id="nav-panel-build" data-group="build" role="region" aria-labelledby="nav-btn-build" hidden>
|
||||
<div class="panel-list">
|
||||
<a href="/build" data-nav="build"><b>Build on Igneum</b><span>Chain ids, RPC, a contract in five minutes.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Devnet faucet</b><span>10 IGN of devnet coin, once a day.</span></a>
|
||||
<a href="/swap" data-nav="swap"><b>Swap</b><span>Test tokens on Devnet 3; every swap is a proven block.</span></a>
|
||||
<a href="/grants" data-nav="grants"><b>Grants</b><span>Tooling, apps, infrastructure, research.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-sheet" id="nav-sheet" role="dialog" aria-modal="true" aria-label="Menu" hidden>
|
||||
|
|
@ -141,7 +152,6 @@ blockquote{margin:10px 0;padding:10px 14px;border-left:3px solid var(--line-2);c
|
|||
<a href="/wallet" data-nav="wallet"><b>The wallet</b><span>Your coins. Final means final.</span></a>
|
||||
<a href="/miners" data-nav="miners"><b>GPU bench table</b><span>Measured rates, card by card.</span></a>
|
||||
<a href="/dev-fee" data-nav="dev-fee"><b>The dev fee</b><span>The optional one, in full view, off with one flag.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Testnet faucet</b><span>Test coin for an address, once a day.</span></a>
|
||||
<a href="/metamask" data-nav="metamask"><b>Add to MetaMask</b><span>Igneum as a network in your wallet.</span></a>
|
||||
</div>
|
||||
<div class="sheet-group"><div class="sheet-head">Network</div>
|
||||
|
|
@ -150,6 +160,9 @@ blockquote{margin:10px 0;padding:10px 14px;border-left:3px solid var(--line-2);c
|
|||
<a href="/journey" data-nav="journey"><b>The journey</b><span>Six phases, four gates, the log behind them.</span></a>
|
||||
<a href="/bench" data-nav="bench"><b>Engineering log</b><span>Every measurement, with the commands that made it.</span></a>
|
||||
<a href="/evidence" data-nav="evidence"><b>Evidence</b><span>Every claim and how far it is tested.</span></a>
|
||||
<a href="/light" data-nav="light"><b>Light wallet</b><span>A balance your browser proves, trusting no node.</span></a>
|
||||
<a href="/receipt" data-nav="receipt"><b>Payment receipt</b><span>A receipt any third party re-verifies offline.</span></a>
|
||||
<a href="/oracle" data-nav="oracle"><b>State oracle on Sepolia</b><span>Devnet 3 balances read from another chain.</span></a>
|
||||
</div>
|
||||
<div class="sheet-group"><div class="sheet-head">Learn</div>
|
||||
<a href="/litepaper" data-nav="litepaper"><b>Litepaper</b><span>The design, as published.</span></a>
|
||||
|
|
@ -159,6 +172,12 @@ blockquote{margin:10px 0;padding:10px 14px;border-left:3px solid var(--line-2);c
|
|||
<a href="/randomx" data-nav="randomx"><b>Igneum vs RandomX</b><span>What was kept and what was rebuilt for GPUs.</span></a>
|
||||
<a href="/provenance" data-nav="provenance"><b>Built on the shoulders</b><span>Every borrowed part, credited.</span></a>
|
||||
</div>
|
||||
<div class="sheet-group"><div class="sheet-head">Build</div>
|
||||
<a href="/build" data-nav="build"><b>Build on Igneum</b><span>Chain ids, RPC, a contract in five minutes.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Devnet faucet</b><span>10 IGN of devnet coin, once a day.</span></a>
|
||||
<a href="/swap" data-nav="swap"><b>Swap</b><span>Test tokens on Devnet 3; every swap is a proven block.</span></a>
|
||||
<a href="/grants" data-nav="grants"><b>Grants</b><span>Tooling, apps, infrastructure, research.</span></a>
|
||||
</div>
|
||||
<div class="sheet-foot">
|
||||
<a href="/download" class="btn primary big" data-nav="download">Download</a>
|
||||
<div class="sheet-social"><a href="https://discord.gg/igneum" target="_blank" rel="noopener">Discord</a><a href="https://git.igneum.network/igneum-network/spec" target="_blank" rel="noopener">Source</a><a href="https://www.reddit.com/user/Igneum_network/" target="_blank" rel="noopener">Reddit</a></div>
|
||||
|
|
@ -216,9 +235,9 @@ blockquote{margin:10px 0;padding:10px 14px;border-left:3px solid var(--line-2);c
|
|||
<section class="page-hero">
|
||||
<div class="container">
|
||||
<div class="breadcrumb"><a href="/">Igneum</a><span>/</span><span>The ledger</span></div>
|
||||
<div class="page-heading"><div><div class="eyebrow"><span class="line"></span>Ledger · 192 entries · regenerated from the repository</div>
|
||||
<div class="page-heading"><div><div class="eyebrow"><span class="line"></span>Ledger · 193 entries · regenerated from the repository</div>
|
||||
<h1>Every criticism, answered<br><span class="accent">or conceded.</span></h1>
|
||||
<p class="lead">This is every criticism the project expects, in the critic's words, with what was done about it and the date. 192 entries since 3 October 2026. Entries are never deleted; a status that changes keeps its history on the line. Where the critic was right the entry says Conceded. Where nothing has been done it says Open and names what settles it. The founder mined through the GPU years. Ethereum's move to proof of stake in September 2022 ended that income and the miners' place in that chain. This is one person building, with AI systems doing the engineering, the coin he wanted to exist for miners: GPU-mined, the miners are the provers, no founder allocation, every cost stated. Help is welcome and a team is wanted: cryptographers, node engineers, miners who will test. This ledger is the application form: pick an open row and write to <a href="mailto:hello@igneum.network">hello@igneum.network</a> with its id.</p></div></div>
|
||||
<p class="lead">This is every criticism the project expects, in the critic's words, with what was done about it and the date. 193 entries since 3 October 2026. Entries are never deleted; a status that changes keeps its history on the line. Where the critic was right the entry says Conceded. Where nothing has been done it says Open and names what settles it. The founder mined through the GPU years. Ethereum's move to proof of stake in September 2022 ended that income and the miners' place in that chain. This is one person building, with AI systems doing the engineering, the coin he wanted to exist for miners: GPU-mined, the miners are the provers, no founder allocation, every cost stated. Help is welcome and a team is wanted: cryptographers, node engineers, miners who will test. This ledger is the application form: pick an open row and write to <a href="mailto:hello@igneum.network">hello@igneum.network</a> with its id.</p></div></div>
|
||||
</div>
|
||||
</section>
|
||||
<section class="section compact"><div class="container">
|
||||
|
|
@ -227,11 +246,11 @@ blockquote{margin:10px 0;padding:10px 14px;border-left:3px solid var(--line-2);c
|
|||
<tbody>
|
||||
<tr><td class="num">3</td><td><button type="button" class="chip" data-filter="Open">Open</button></td><td>Nothing has settled it yet. The entry names what will</td></tr>
|
||||
<tr><td class="num">64</td><td><button type="button" class="chip" data-filter="Conceded">Conceded</button></td><td>The critic is right. "Stated" means the public text says so; "not yet stated" means it does not yet</td></tr>
|
||||
<tr><td class="num">66</td><td><button type="button" class="chip" data-filter="Fixed or built">Fixed or built</button></td><td>A code, spec or text change answers it, with the commit or the page named</td></tr>
|
||||
<tr><td class="num">67</td><td><button type="button" class="chip" data-filter="Fixed or built">Fixed or built</button></td><td>A code, spec or text change answers it, with the commit or the page named</td></tr>
|
||||
<tr><td class="num">27</td><td><button type="button" class="chip" data-filter="Closed by rule or decided">Closed by rule or decided</button></td><td>A consensus rule or a decision by the owner answers it, dated</td></tr>
|
||||
<tr><td class="num">16</td><td><button type="button" class="chip" data-filter="Answered with evidence">Answered with evidence</button></td><td>A measurement or a simulation exists and is named</td></tr>
|
||||
<tr><td class="num">16</td><td><button type="button" class="chip" data-filter="Answered by design">Answered by design</button></td><td>A design rule answers it; no measurement is possible yet</td></tr>
|
||||
<tr><td class="num">192</td><td><button type="button" class="chip" data-filter="">All</button></td><td>Every entry. The sections: <a href="#ap">The in-house adversarial pass</a>, <a href="#m">Mining and chips</a>, <a href="#f">Finality and attacks</a>, <a href="#p">Proving and the zkEVM</a>, <a href="#e">Economics and the coin</a>, <a href="#g">Governance and the founders</a>, <a href="#c">Comparisons</a>, <a href="#l">Legal and regulatory</a>, <a href="#x">Launch and operations</a>, <a href="#d">Builders</a></td></tr>
|
||||
<tr><td class="num">193</td><td><button type="button" class="chip" data-filter="">All</button></td><td>Every entry. The sections: <a href="#ap">The in-house adversarial pass</a>, <a href="#m">Mining and chips</a>, <a href="#f">Finality and attacks</a>, <a href="#p">Proving and the zkEVM</a>, <a href="#e">Economics and the coin</a>, <a href="#g">Governance and the founders</a>, <a href="#c">Comparisons</a>, <a href="#l">Legal and regulatory</a>, <a href="#x">Launch and operations</a>, <a href="#d">Builders</a></td></tr>
|
||||
</tbody></table></div>
|
||||
<div class="toolbar"><input type="search" id="q" placeholder="Search the ledger" aria-label="Search the ledger"><span id="shown"></span></div>
|
||||
<h2 id="m">Mining and chips</h2>
|
||||
|
|
@ -1401,7 +1420,7 @@ blockquote{margin:10px 0;padding:10px 14px;border-left:3px solid var(--line-2);c
|
|||
<article class="entry" id="AP-F8-1" data-bucket="Fixed or built">
|
||||
<div class="head"><span class="id">AP-F8-1</span><h3>A load whose source was last written by <code>or</code>, <code>mul</code> or <code>mulhi</code> makes a cross-hash hot set</h3><span class="date">7 October 2026</span></div>
|
||||
<blockquote>The item histogram of class v4 over 2^26 nonces is not uniform: the top 0.1 percent of items take 0.520 percent of reads against 0.115 for a uniform control (4.05x), one item takes 78,479 reads (153x the mean), and site 15 feeds 6.37 percent of its reads into that top 0.1 percent in every iteration." (attack-pass row F8, <code>a repository file</code>, 7 October 2026)</blockquote>
|
||||
<div class="status"><span class="badge b-fixed-or-built">Fixed in part, finding bounded, stated</span> <span class="did">7 October 2026, night, the Counter ASIC lane's words): class v4 sub-version 3 (igneum-pow 017e7037, the audit-freeze tag) is frozen with the dataflow rule, the shared-operand rule, the 0.98 ratio and the total draw; the in-house pass's F8 re-gate reads 60 of 64 seeds under 1.2x with the four-seed tail accepted by the coordinator as the window model's unattributed residue (no chip consequence); the pass then attributed the class by value (eight live hot sets at 1.54x to 2.24x in the lowest 30 of 29,032 accepted programs, each about 1 MB of items at 0.3 percent of reads, 1.002x to a chip); class v5 (1c420786, frozen 21:53 UK) carries the fix as rule (c'''), the per-site distinct-index floor at 0.995 on the state flag (its census refuses 2.435 percent of accepted programs; seven of seven live hot sets refused at 0.9821 to 0.9919; the eighth's ratio owed tonight), with a named residual (three mild shadow-block-written concentrations at 0.9992 to 0.9997, about 1.0004x, a value-level test in the next class); the record is <code>a repository file</code> section 7c and the class v5 design's section 14. The eighth live hot set (seed 122960, id 4be7393ab6c84802, the deepest found: X_f +0.111 percent, 1.54x the window model, its hottest item at 475,616 reads from an all-ones source) reads minimum site 12 at 0.9824 at the acceptance's own 2^20 sample (live 0.9822), refused by class v5's (c''') floor at 0.995; so the floor refuses nine of nine live hot sets by X_f at or above f found in the tail of 269,250 accepted programs (minimum sites 0.9809 to 0.9919; the ninth, seed 228763 from a non-saturated source, at 0.9809 on 8 October 2026) against 0 hot sets in 20 random programs; what it misses stays the three mild shadow-block-written concentrations at 0.9992 to 0.9997 (Devnet 3's first program among them), about 1.0004x to a chip, the value-level test in the next class (22:41 local time; the logs under <code>a repository file/</code> on branch adv-accept; the v5 design's section 14). The public sentence (the coordinator's wording, 7 October 2026, night; the count moved to nine at 01:13 local time on 8 October when the ninth live hot set, seed 228763 from a non-saturated source, read 0.9809 and was refused): nine of nine hot sets refused; the diffuse era-stride excess, bounded under 0.1 percent of a hash's reads per site, is not caught by the floor and is the next class's test. The reason, read by the in-house pass (adv-cache-2) and the class v5 lane together: the distinct-index count at 2^20 sees concentration on few word indices whatever their source, saturated or not (the hot sets put about 3 percent of a site's reads on 512 indices, so the ratio falls to 0.981 to 0.992; the final tally 9 of 9 live hot sets and both single-item programs refused, 7 clean-live programs refused among the 12 deepest, 3 mild residuals missed) and not a diffuse excess over the top 0.1 percent of items (16,384 items), which is what the era-stride low-bit law produces (13 of 27 drawn-era programs carry a site over 1.04x, 8 over 1.2x, worst 1.75x; 0 of 29 refused at the 2^20 sample, minimum sites 0.9965 to 1.0000); its chip value is about 1.0024x at the worst site read, under this row's bound by an order; the row for it is AP-F8-6. The RTX 5080 grid's knee is not in tonight; X37 keeps the 5080's stock premium only.</span></div>
|
||||
<div class="status"><span class="badge b-fixed-or-built">Fixed in part, finding bounded, stated</span> <span class="did">7 October 2026, night, the Counter ASIC lane's words): class v4 sub-version 3 (igneum-pow 017e7037, the audit-freeze tag) is frozen with the dataflow rule, the shared-operand rule, the 0.98 ratio and the total draw; the in-house pass's F8 re-gate reads 60 of 64 seeds under 1.2x with the four-seed tail accepted by the coordinator as the window model's unattributed residue (no chip consequence); the pass then attributed the class by value (eight live hot sets at 1.54x to 2.24x in the lowest 30 of 29,032 accepted programs, each about 1 MB of items at 0.3 percent of reads, 1.002x to a chip); class v5 (1c420786, frozen 21:53 UK) carries the fix as rule (c'''), the per-site distinct-index floor at 0.995 on the state flag (its census refuses 2.435 percent of accepted programs; seven of seven live hot sets refused at 0.9821 to 0.9919; the eighth's ratio owed tonight), with a named residual (three mild shadow-block-written concentrations at 0.9992 to 0.9997, about 1.0004x, a value-level test in the next class); the record is <code>a repository file</code> section 7c and the class v5 design's section 14. The eighth live hot set (seed 122960, id 4be7393ab6c84802, the deepest found: X_f +0.111 percent, 1.54x the window model, its hottest item at 475,616 reads from an all-ones source) reads minimum site 12 at 0.9824 at the acceptance's own 2^20 sample (live 0.9822), refused by class v5's (c''') floor at 0.995; so the floor refuses nine of nine live hot sets by X_f at or above f found in the tail of 269,250 accepted programs (minimum sites 0.9809 to 0.9919; the ninth, seed 228763 from a non-saturated source, at 0.9809 on 8 October 2026) against 0 hot sets in 20 random programs; what it misses stays the three mild shadow-block-written concentrations at 0.9992 to 0.9997 (Devnet 3's first program among them), about 1.0004x to a chip, the value-level test in the next class (22:41 local time; the logs under <code>a repository file/</code> on branch adv-accept; the v5 design's section 14). The public sentence (the coordinator's wording, 7 October 2026, night; the count moved to nine at 01:13 local time on 8 October when the ninth live hot set, seed 228763 from a non-saturated source, read 0.9809 and was refused): nine of nine hot sets refused; the diffuse era-stride excess, bounded under 0.1 percent of a hash's reads per site, is not caught by the floor and is the next class's test. The reason, read by the in-house pass (adv-cache-2) and the class v5 lane together: the distinct-index count at 2^20 sees concentration on few word indices whatever their source, saturated or not (the hot sets put about 3 percent of a site's reads on 512 indices, so the ratio falls to 0.981 to 0.992; the final tally 9 of 9 live hot sets and both single-item programs refused, 7 clean-live programs refused among the 12 deepest, 3 mild residuals missed) and not a diffuse excess over the top 0.1 percent of items (16,384 items), which is what the era-stride low-bit law produces (13 of 27 drawn-era programs carry a site over 1.04x, 8 over 1.2x, worst 1.75x; 0 of 29 refused at the 2^20 sample, minimum sites 0.9965 to 1.0000); its chip value is about 1.0024x at the worst site read, under this row's bound by an order; the row for it is AP-F8-6. The RTX 5080 grid's knee is not in tonight; X37 keeps the 5080's stock premium only. The tail is attributed (8 October 2026, 09:46 UK, the hash lane): one narrow-window site per seed with a quarter-bit bucket concentration from a mad, xor or sub writer, no lossy source, no chip consequence beyond the window model; the per-site bucket bound that would refuse it is a morning item for the next class, not a change to 017e7037.</span></div>
|
||||
<details><summary>The answer as first written</summary><p>Correct as a fault, wrong as a null. The window layer (spec 01 1.13.1 as proposed, <code>a repository file</code> 1.4) moves the uniform null from 0.115 to 0.160 percent at the top 0.1 percent (1.39x, not 4.05x) and explains every per-site row of F8's attribution except site 15. Site 15's source r6 was last written by <code>or r6, r4</code> (instruction 61, the load at 63), a non-injective op whose output bits are 1 with probability 3/4, so the all-ones source recurs with probability (3/4)^32 per read; the era map sends it to item 0xca5b92, F8's hottest item exactly, and F8's next seven items are exactly the seven one-zero-bit sources whose zero survives the window mask. The popcount model at the measured bias (p = 0.7585) predicts 77,348 all-ones reads against 78,479, and the program's top-0.1-percent share at 0.58 against 0.52. The acceptance rule's part (a) takes any write as a fresh source and part (c) counts saturation on final register values only, so the class of fault passes it: of 1,024 chain-shaped class v4 programs 96.6 percent carry a load whose source's last writer is <code>or</code>, <code>mul</code> or <code>mulhi</code>, 48.5 percent an <code>or</code>-sourced one (0.30 percent of all reads per site), 4.9 percent an <code>or</code>-of-<code>or</code> chain (p3's class: 72 percent of that site's reads, 4.6 percent of all reads, on 0.1 percent of items). The ceiling under rule (c)'s 120-of-128 floor is one site repeating its item in all 8 iterations, 6.25 percent of reads, a chip edge of at most 1.067x in 64 bytes of SRAM; the public claim's 2x margin stands, and the public line says "bounded", not "uniform" (<code>a repository file</code> sections 1 to 4).</p></details>
|
||||
</article>
|
||||
<article class="entry" id="AP-F8-3" data-bucket="Fixed or built">
|
||||
|
|
@ -1422,12 +1441,18 @@ blockquote{margin:10px 0;padding:10px 14px;border-left:3px solid var(--line-2);c
|
|||
<div class="status"><span class="badge b-fixed-or-built">Fixed</span> <span class="did">7 October 2026, night): the id and its derivation text come from one byte recipe, every pinned pack's id re-derives from its own text in the suite (the igneum-pow suite on box 2 green at 0f45c8be: 64 + 2 + 7 + 4 + 19 + 2 + 7), the spec states the suffix; no object moved.</span></div>
|
||||
|
||||
</article>
|
||||
<article class="entry" id="AP-F8-5" data-bucket="Conceded">
|
||||
<article class="entry" id="AP-F8-5" data-bucket="Fixed or built">
|
||||
<div class="head"><span class="id">AP-F8-5</span><h3>The public specification did not describe the shipped acceptance rule (documentary; no object change)</h3><span class="date">7 October 2026</span></div>
|
||||
<blockquote>An implementation written from a repository file section 1.4.6 at 017e7037 mines a different program from the node on 264 of 400 epochs." Found by the in-house pass adv-accept-3 (report-acceptance-rule-3.md at 0c150e3c, finding 3, section 6.2, 7 October 2026, night): the text described (a), (b) and (c) with a 32-attempt cap and an id without a suffix, while the code adds (a') with the shared-operand rule, (c'), (c'') at 2^20 evaluations, the 256-attempt cap keyed on the class v4 shape, the total draw with the last resort, generator 4 and the sub-version suffix, and executes the 256-instruction shadow block 27 times per iteration inside the acceptance interpreter. Measured (sweep 97, 400 seeds, 1,317 attempt verdicts): 759 verdicts differ (758 the code rejects and the text accepts: (a') 733, (c'') 15, (c) 10; 1 the other way, the shadow block changing a (c) statistic); 264 of 400 seeds choose another attempt; the parts the text did carry, (a) and (b), agree on every row.</blockquote>
|
||||
<div class="status"><span class="badge b-conceded">Conceded, stated</span> <span class="did">7 October 2026, night, the ledger close): <code>a repository file</code>, What Igneum does not claim, "A delay function that outlives a quantum computer. No." with the fallback (a hash-chain delay behind the version byte that moves the signature scheme, one class change) and the reading (a liveness nuisance, not a break of finality). Still not sized. Was: Conceded, flagged in spec 04 section 4.8.</span></div>
|
||||
<div class="status"><span class="badge b-fixed-or-built">Spec fixed</span> <span class="did">7 October 2026, night, the site audit lane by main's order, branch spec-accept-23): sections 1.4.3 and 1.4.6 of <code>a repository file</code> rewritten to the shipped rule at igneum-pow 017e7037 with every constant named and every order of operations stated (1.4.3: the two per-register states of the draw, the dataflow table, the shared-operand rule, the shadow block's draw and the draw counts per class; 1.4.6.1 to 1.4.6.6: (a) cyclic over two passes, (b), (a') to the fixpoint then a checking pass, (c) with the shadow executed and its limits in a table, (c') and (c'') with the integer form of the ratio compare, the attempts and the two caps with the measured per-part rates, the last resort stated as unreachable and unverified, the program id with the generator-4 suffix, a constants table in the shape the crate's read-back test parses, the pinned ids a reader must reproduce); section 1.7 gains the shadow block's execution; section 1.13.1 names the two consumed era draws. The hash lane's <code>igneum-pow/tests</code> read-back test parses the two tables against the crate's <code>pub const</code> items and derives every pinned id (its landing is the row's check; AP-F8-4 carries the derivation-text half of the same finding). Fixed on two measurements by the finding lane: Q4c at master 8b834634, before the closed-form dataset was stated, a text-only implementation of sections 1.3, 1.4.2, 1.4.3, 1.4.6, 1.6, 1.7 and 1.13.1 re-derived the 400 epoch programs of sweep 97 under the Devnet 3 era with 0 of 400 differing on any field and one function (<code>dataset_elem</code>) taken from the crate (report section 6.5, log 983-textderive-8b834634.tsv); Q4d at master 56eebc0d, with <code>dataset_elem</code> written from 1.4.6.4 and its two pinned vectors reproduced, 0 of 400 differing with 0 crate imports (report section 6.6, log 984-textderive-56eebc0d.tsv, 8 October 2026, 01:5x UK).</span></div>
|
||||
<details><summary>The answer as first written</summary><p>Correct, and the largest divergence source the pass found was documentary. The rule the chain runs was right; the text a second implementer would read was three sub-versions behind it. The fix is the text, written to the code line by line, and a test that fails when the two drift again.</p></details>
|
||||
</article>
|
||||
<article class="entry" id="AP-F8-7" data-bucket="Conceded">
|
||||
<div class="head"><span class="id">AP-F8-7</span><h3>The hash's reads are not uniformly random: about half of epochs carry one load site with a biased address bit</h3><span class="date">7 October 2026</span></div>
|
||||
<blockquote>The served text says every hash is a chain of random reads over the dataset. Measured at the acceptance rule's own 2^20 sample over 4,900 drawn eras (lane D's family harness, 8 October 2026) and in adv-cache-2's drawn-program reading the night before: the reads are spread over the whole dataset and the distinct-index floor holds at 0.995 on every accepted program, but 52 to 58 percent of accepted programs in every stratum carry one load site whose address bit R (the era's stride rotation), R+1 or R+2 is biased over 6 sigma, a third over 100 sigma, the worst z 1,024: a product's bit 0 at P = 1/4 landing on an address bit.</blockquote>
|
||||
<div class="status"><span class="badge b-conceded">Conceded, stated</span> <span class="did">7 October 2026, night, the ledger close): <code>a repository file</code>, What Igneum does not claim, "A delay function that outlives a quantum computer. No." with the fallback (a hash-chain delay behind the version byte that moves the signature scheme, one class change) and the reading (a liveness nuisance, not a break of finality). Still not sized. Was: Conceded, flagged in spec 04 section 4.8.</span></div>
|
||||
<details><summary>The answer as first written</summary><p>Correct as a measurement and bounded as a gain. The favoured half of one site's window serves 75 instead of 50 percent of that site's reads, 25 percent of 1/16 of a hash's reads, about 1.6 percent, to a chip storing half the dataset; a chip storing all of it gains nothing (the f = 1 verdict unchanged, and the partial store already costs 1.26x the ops). The sentence that said "random" now says what was measured.</p></details>
|
||||
</article>
|
||||
|
||||
<p class="intro" style="margin-top:var(--sec)">Source: the project's criticism ledger, a file in the repository, rendered to this page at build time; the repository is published at the public testnet. A criticism that is not here, or that shows an entry is wrong, is added with credit if wanted: <a href="mailto:hello@igneum.network">hello@igneum.network</a> or <a href="https://github.com/igneum-network/spec/issues" rel="noopener">an issue on the specification repository</a>.</p>
|
||||
</div></section>
|
||||
|
|
@ -1454,7 +1479,7 @@ blockquote{margin:10px 0;padding:10px 14px;border-left:3px solid var(--line-2);c
|
|||
<a href="/wallet">The wallet</a>
|
||||
<a href="/miners">GPU bench table</a>
|
||||
<a href="/dev-fee">The dev fee</a>
|
||||
<a href="/faucet">Testnet faucet</a>
|
||||
<a href="/faucet">Devnet faucet</a>
|
||||
<a href="/metamask">Add Igneum to MetaMask</a>
|
||||
</div></div>
|
||||
<div class="footer-column"><h4>Read</h4><div>
|
||||
|
|
@ -1469,6 +1494,9 @@ blockquote{margin:10px 0;padding:10px 14px;border-left:3px solid var(--line-2);c
|
|||
<div class="footer-column"><h4>Explore</h4><div>
|
||||
<a href="/live">Live devnet</a>
|
||||
<a href="/explorer">Explorer</a>
|
||||
<a href="/build">Build on Igneum</a>
|
||||
<a href="/swap">Swap</a>
|
||||
<a href="/grants">Grants</a>
|
||||
<a href="/journey">Journey</a>
|
||||
<a href="/download">Downloads: devnet build</a>
|
||||
<a href="https://discord.gg/igneum" target="_blank" rel="noopener">Community Discord</a>
|
||||
|
|
|
|||
46
site/lib/proving-health.mjs
Normal file
46
site/lib/proving-health.mjs
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
// The proving feed's own staleness (8 October 2026). /api/live's "proven" and "paid" shard states come from the observer's
|
||||
// node (igneum_getProvingStatus and igneum_getProofRecords on its execution RPC), never from the chain directly. Three
|
||||
// ways that node can lie while the DAG feed stays live, each read here against what the chain itself shows:
|
||||
// 1. the status snapshot is old (the observer's last successful igneum_getProvingStatus read), PROVING_STATUS_STALE_S;
|
||||
// 2. the node's execution tip trails the newest block's DAA by more than PROVING_TIP_LAG_DAA (a stalled executor);
|
||||
// 3. blocks in the last 10 minutes carried proof records (the IGNP section the observer counts per block) and the
|
||||
// node credited no shard (no row moved to verified or paid) for PROVING_SILENCE_S: the "blind to records" class
|
||||
// (Devnet 3, 7 to 8 October 2026: the observer's node froze at 7,304 paid shards from 23:57Z while blocks carried
|
||||
// 8,457 records by 03:00Z and hub-1's node counted 11,861 paid by 08:56Z).
|
||||
// A quiet chain (no records carried) is not stale for lack of credits: there was nothing to credit.
|
||||
export const PROVING_STATUS_STALE_S = 60;
|
||||
export const PROVING_TIP_LAG_DAA = 300;
|
||||
export const PROVING_SILENCE_S = 600;
|
||||
|
||||
const ms = v => { if (v === null || v === undefined || v === '') return null; const t = typeof v === 'number' ? v : Date.parse(String(v).replace(' ', 'T')); return Number.isFinite(t) ? t : null; };
|
||||
function span(s) { s = Math.max(0, Math.round(s)); if (s < 60) return s + ' s'; const m = Math.floor(s / 60); if (m < 60) return m + ' min'; const h = Math.floor(m / 60); return h + ' h ' + (m % 60) + ' min'; }
|
||||
|
||||
/**
|
||||
* @param {object} a proving: the API's proving object (supported, tip_daa, ...); newestDaa: the newest block's DAA score in the
|
||||
* feed; records10m: proof records carried by blocks in the last 10 minutes; lastChangeAt: when a shard last moved to verified
|
||||
* or paid (null = never); statusAt: the observer's last successful status read (null on an older observer); now: ms.
|
||||
* @returns {{stale: boolean, reason: string, status_age_s: number|null, tip_lag_daa: number|null, records_10m: number, last_change_at: string|null}}
|
||||
*/
|
||||
export function provingHealth(a) {
|
||||
const now = a.now ?? Date.now(), pv = a.proving || null;
|
||||
const statusAt = ms(a.statusAt), lastChange = ms(a.lastChangeAt);
|
||||
const status_age_s = statusAt === null ? null : Math.round(Math.max(0, now - statusAt) / 100) / 10;
|
||||
const records_10m = Number(a.records10m) > 0 ? Math.round(Number(a.records10m)) : 0;
|
||||
const tipDaa = pv && pv.tip_daa !== null && pv.tip_daa !== undefined ? Number(pv.tip_daa) : null;
|
||||
const newest = a.newestDaa !== null && a.newestDaa !== undefined ? Number(a.newestDaa) : null;
|
||||
const tip_lag_daa = tipDaa !== null && newest !== null && Number.isFinite(tipDaa) && Number.isFinite(newest) ? Math.max(0, newest - tipDaa) : null;
|
||||
const last_change_at = lastChange === null ? null : (typeof a.lastChangeAt === 'string' && /T.*Z$/.test(a.lastChangeAt) ? a.lastChangeAt : new Date(lastChange).toISOString());
|
||||
const out = { stale: false, reason: '', status_age_s, tip_lag_daa, records_10m, last_change_at };
|
||||
if (!pv || !pv.supported) { out.stale = true; out.reason = (pv && pv.reason) || 'the observer has not reported the proving layer'; return out; }
|
||||
if (status_age_s !== null && status_age_s > PROVING_STATUS_STALE_S) { out.stale = true; out.reason = 'proving status last read ' + Math.round(status_age_s) + ' s ago'; return out; }
|
||||
if (tip_lag_daa !== null && tip_lag_daa > PROVING_TIP_LAG_DAA) { out.stale = true; out.reason = 'the observer\'s node is ' + tip_lag_daa + ' DAA behind the chain'; return out; }
|
||||
if (records_10m > 0) {
|
||||
const silence = lastChange === null ? null : (now - lastChange) / 1000;
|
||||
if (silence === null || silence > PROVING_SILENCE_S) {
|
||||
out.stale = true;
|
||||
out.reason = 'blocks carried ' + records_10m + ' proof record' + (records_10m === 1 ? '' : 's') + ' in the last 10 min and the observer\'s node credited none' + (silence === null ? ' (never)' : ' for ' + span(silence));
|
||||
return out;
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
64
site/lib/proving-health.test.mjs
Normal file
64
site/lib/proving-health.test.mjs
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
// The proving feed's own staleness (8 October 2026, main's order: a stale snapshot must read as stale). The page's "proven"
|
||||
// states come from the observer's node, not from the chain directly; a node that stops crediting payouts (the "blind to
|
||||
// records" class: Devnet 3's observer node froze at 7,304 paid shards from 23:57Z on 7 October while blocks kept carrying
|
||||
// records and hub-1 counted 11,861 by 08:56Z) leaves a snapshot that still says supported, active and a paid total. Known-failed
|
||||
// first: that snapshot read as fresh before this module existed; it must read as stale, with the reason in words.
|
||||
import { test } from 'node:test';
|
||||
import assert from 'node:assert/strict';
|
||||
import { provingHealth, PROVING_STATUS_STALE_S, PROVING_TIP_LAG_DAA, PROVING_SILENCE_S } from './proving-health.mjs';
|
||||
|
||||
const NOW = Date.parse('2026-10-08T08:56:47Z');
|
||||
const live = { supported: true, active: true, tip_daa: 57767, paid_shards_total: 7304 };
|
||||
const h = (over) => provingHealth({ proving: live, newestDaa: 57770, records10m: 12, lastChangeAt: new Date(NOW - 20_000).toISOString(), statusAt: new Date(NOW - 1_500).toISOString(), now: NOW, ...over });
|
||||
|
||||
test('the 8 October 2026 shape: records carried in the window, no shard credited for nine hours: stale, and the reason says so', () => {
|
||||
const r = h({ records10m: 48, lastChangeAt: '2026-10-07T23:57:25Z' });
|
||||
assert.equal(r.stale, true);
|
||||
assert.match(r.reason, /48 proof records? in the last 10 min/);
|
||||
assert.match(r.reason, /credited none/);
|
||||
assert.match(r.reason, /8 h 59 min/);
|
||||
assert.equal(r.records_10m, 48); assert.equal(r.last_change_at, '2026-10-07T23:57:25Z');
|
||||
});
|
||||
test('a snapshot the observer last read too long ago is stale, with its age', () => {
|
||||
const r = h({ statusAt: new Date(NOW - 95_000).toISOString() });
|
||||
assert.equal(r.stale, true); assert.match(r.reason, /last read 95 s ago/); assert.equal(r.status_age_s, 95);
|
||||
assert.equal(PROVING_STATUS_STALE_S, 60);
|
||||
});
|
||||
test('an observer node whose execution tip trails the chain by more than the allowance is stale', () => {
|
||||
const r = h({ newestDaa: 57767 + 400 });
|
||||
assert.equal(r.stale, true); assert.match(r.reason, /400 DAA behind the chain/); assert.equal(r.tip_lag_daa, 400);
|
||||
assert.equal(PROVING_TIP_LAG_DAA, 300);
|
||||
assert.equal(h({ newestDaa: 57767 + 300 }).stale, false, 'at the allowance it is fresh');
|
||||
});
|
||||
test('fresh: the status just read, the tip at the chain, records in the window and a credit 20 s ago', () => {
|
||||
const r = h({});
|
||||
assert.equal(r.stale, false); assert.equal(r.reason, ''); assert.equal(r.status_age_s, 1.5); assert.equal(r.tip_lag_daa, 3);
|
||||
});
|
||||
test('a quiet chain (no records carried in the window) is not stale for lack of credits', () => {
|
||||
assert.equal(h({ records10m: 0, lastChangeAt: '2026-10-07T23:57:25Z' }).stale, false);
|
||||
assert.equal(h({ records10m: 0, lastChangeAt: null }).stale, false);
|
||||
});
|
||||
test('records in the window and no credit ever: stale', () => {
|
||||
const r = h({ records10m: 5, lastChangeAt: null });
|
||||
assert.equal(r.stale, true); assert.match(r.reason, /credited none/); assert.match(r.reason, /never/);
|
||||
});
|
||||
test('a silence shorter than the allowance is fresh; longer is stale', () => {
|
||||
assert.equal(PROVING_SILENCE_S, 600);
|
||||
assert.equal(h({ records10m: 5, lastChangeAt: new Date(NOW - 599_000).toISOString() }).stale, false);
|
||||
assert.equal(h({ records10m: 5, lastChangeAt: new Date(NOW - 601_000).toISOString() }).stale, true);
|
||||
});
|
||||
test('an older observer without status_at is judged by the other rules only', () => {
|
||||
const r = h({ statusAt: null });
|
||||
assert.equal(r.stale, false); assert.equal(r.status_age_s, null);
|
||||
});
|
||||
test('an unsupported proving layer is stale with the observer\'s reason', () => {
|
||||
const r = h({ proving: { supported: false, reason: 'evm rpc unreachable (fetch failed)' } });
|
||||
assert.equal(r.stale, true); assert.equal(r.reason, 'evm rpc unreachable (fetch failed)');
|
||||
});
|
||||
test('the forbidden wording is gone from the site and the scene: a chain block with no shards is never "no shard plan yet"', async () => {
|
||||
const { readFileSync } = await import('node:fs');
|
||||
for (const f of ['scene/live-dag.js', 'site/live-dag.js', 'site/live.html', 'site/live-steps.js', 'site/block.html']) {
|
||||
const src = readFileSync(new URL('../../' + f, import.meta.url), 'utf8');
|
||||
assert.equal(/no shard plan yet/i.test(src), false, f + ' says "no shard plan yet"');
|
||||
}
|
||||
});
|
||||
362
site/light.html
Normal file
362
site/light.html
Normal file
|
|
@ -0,0 +1,362 @@
|
|||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
|
||||
<title>Igneum light wallet</title>
|
||||
<meta name="description" content="A Devnet 3 balance your browser proves itself: certificate, headers, coinbase, segment record and account proof, all recomputed in the tab. Devnet 3, no value.">
|
||||
<link rel="canonical" href="https://igneum.network/light">
|
||||
<meta name="theme-color" content="#0C0C0E">
|
||||
<meta property="og:type" content="website">
|
||||
<meta property="og:site_name" content="Igneum">
|
||||
<meta property="og:title" content="Igneum light wallet">
|
||||
<meta property="og:description" content="A Devnet 3 balance your browser proves itself: certificate, headers, coinbase, segment record and account proof, all recomputed in the tab. Devnet 3, no value.">
|
||||
<meta property="og:url" content="https://igneum.network/light">
|
||||
<meta property="og:image" content="https://igneum.network/og.png?v=3">
|
||||
<meta property="og:image:width" content="1200">
|
||||
<meta property="og:image:height" content="630">
|
||||
<meta property="og:image:alt" content="Igneum. Mined by GPUs. Proven by fire.">
|
||||
<meta name="twitter:card" content="summary_large_image">
|
||||
<meta name="twitter:title" content="Igneum light wallet">
|
||||
<meta name="twitter:description" content="A Devnet 3 balance your browser proves itself: certificate, headers, coinbase, segment record and account proof, all recomputed in the tab. Devnet 3, no value.">
|
||||
<meta name="twitter:image" content="https://igneum.network/og.png?v=3">
|
||||
<meta name="twitter:image:alt" content="Igneum. Mined by GPUs. Proven by fire.">
|
||||
<link rel="icon" href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1024 1024'%3E%3Crect width='1024' height='1024' fill='%230C0C0E'/%3E%3Cg transform='translate(166.95 166.95) scale(6.901)'%3E%3Cpolygon points='50,4 74,34 67,58 80,54 61,96 39,96 20,54 33,58 26,34' fill='%23F2541B'/%3E%3Cpolygon points='50,42 59,58 50,82 41,58' fill='%230C0C0E'/%3E%3C/g%3E%3C/svg%3E" type="image/svg+xml">
|
||||
<link rel="icon" href="/favicon.ico" sizes="48x48">
|
||||
<link rel="icon" href="/favicon-32.png" type="image/png" sizes="32x32">
|
||||
<link rel="icon" href="/icon-192.png" type="image/png" sizes="192x192">
|
||||
<link rel="icon" href="/icon-512.png" type="image/png" sizes="512x512">
|
||||
<link rel="apple-touch-icon" href="/apple-touch-icon.png" sizes="180x180">
|
||||
<link rel="manifest" href="/site.webmanifest">
|
||||
<!-- head:start -->
|
||||
<link rel="preload" href="/fonts/unbounded-900.woff2" as="font" type="font/woff2" crossorigin>
|
||||
<link rel="preload" href="/fonts/plex-sans-400.woff2" as="font" type="font/woff2" crossorigin>
|
||||
<meta name="color-scheme" content="dark light">
|
||||
<link rel="stylesheet" href="/site.css">
|
||||
<style>
|
||||
/* Shared by every page: the head partial, injected by the build between the head markers. Edit the partial, not the page. */
|
||||
/* Fonts, self-hosted (latin subsets, OFL): Unbounded 500/700/900, IBM Plex Sans 400/500/600, IBM Plex Mono 400/500. Fallbacks carry size and ascent overrides so the swap does not move the layout. The tokens, type and components are in /site.css (docs/plans/site-ui-3.md). */
|
||||
@font-face{font-family:'Unbounded';font-style:normal;font-weight:500;font-display:swap;src:url(/fonts/unbounded-500.woff2) format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
|
||||
@font-face{font-family:'Unbounded';font-style:normal;font-weight:700;font-display:swap;src:url(/fonts/unbounded-700.woff2) format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
|
||||
@font-face{font-family:'Unbounded';font-style:normal;font-weight:900;font-display:swap;src:url(/fonts/unbounded-900.woff2) format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
|
||||
@font-face{font-family:'IBM Plex Sans';font-style:normal;font-weight:400;font-display:swap;src:url(/fonts/plex-sans-400.woff2) format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
|
||||
@font-face{font-family:'IBM Plex Sans';font-style:normal;font-weight:500;font-display:swap;src:url(/fonts/plex-sans-500.woff2) format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
|
||||
@font-face{font-family:'IBM Plex Sans';font-style:normal;font-weight:600;font-display:swap;src:url(/fonts/plex-sans-600.woff2) format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
|
||||
@font-face{font-family:'IBM Plex Mono';font-style:normal;font-weight:400;font-display:swap;src:url(/fonts/plex-mono-400.woff2) format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
|
||||
@font-face{font-family:'IBM Plex Mono';font-style:normal;font-weight:500;font-display:swap;src:url(/fonts/plex-mono-500.woff2) format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
|
||||
@font-face{font-family:'Unbounded Fallback';src:local('Arial Black'),local('Arial-Black'),local('Impact');size-adjust:114%;ascent-override:87.5%;descent-override:21.5%;line-gap-override:0%}
|
||||
@font-face{font-family:'Plex Sans Fallback';src:local('Arial'),local('Helvetica Neue'),local('Helvetica');size-adjust:100.5%;ascent-override:102%;descent-override:27.4%;line-gap-override:0%}
|
||||
@font-face{font-family:'Plex Mono Fallback';src:local('Courier New'),local('Menlo');size-adjust:100%;ascent-override:102.5%;descent-override:27.5%;line-gap-override:0%}
|
||||
</style>
|
||||
<script>
|
||||
/* theme before first paint: ?theme=light|dark for one view (the capture tool), else the stored choice under igneum-theme, else the system setting; ?motion=off marks the page data-motion=off so every .reveal is drawn at once (a headless render never scrolls) */
|
||||
(function(){var t=null;try{t=new URLSearchParams(location.search).get("theme");}catch(e){}if(t!=="light"&&t!=="dark"){try{t=localStorage.getItem("igneum-theme");}catch(e){t=null;}}if(t!=="light"&&t!=="dark")t=window.matchMedia&&window.matchMedia("(prefers-color-scheme: light)").matches?"light":"dark";document.documentElement.setAttribute("data-theme",t);try{if(new URLSearchParams(location.search).get("motion")==="off")document.documentElement.setAttribute("data-motion","off");}catch(e){}})();
|
||||
</script>
|
||||
<!-- head:end -->
|
||||
<style>
|
||||
/* reference apps (8 Oct 2026): the verify form, the proven headline, the step list; tokens and components are in /site.css */
|
||||
.vform{display:grid;gap:10px;margin:0}
|
||||
.vform label{font:500 var(--t-sm)/1.4 var(--f-mono);letter-spacing:.08em;text-transform:uppercase;color:var(--ash)}
|
||||
.vform .row{display:flex;gap:10px;flex-wrap:wrap}.vform input{flex:1 1 320px;font-family:var(--f-mono);font-size:14px}
|
||||
.vstatus{font:400 13px/1.5 var(--f-mono);color:var(--ash);min-height:20px}.vstatus[data-kind="ok"]{color:var(--ember-text)}.vstatus[data-kind="bad"]{color:var(--molten-text)}
|
||||
.headline{background:var(--graphite);border:1px solid var(--line);border-radius:var(--r-card);padding:var(--s-5);margin:var(--s-5) 0 var(--s-4)}
|
||||
.headline.bad{border-color:var(--molten)}
|
||||
.headline .big{font:900 clamp(32px,6vw,56px)/1.05 var(--f-display);color:var(--bone);margin:10px 0 8px;overflow-wrap:anywhere}.headline .big span{font-size:.45em;color:var(--ash);font-weight:700}
|
||||
.headline .kv{margin-top:var(--s-3)}.headline .kv small{color:var(--ash);display:block}.headline .mono{font-family:var(--f-mono);font-size:13px;overflow-wrap:anywhere}
|
||||
.kv>div{min-width:0;overflow-wrap:anywhere}.card .kv .mono{font-family:var(--f-mono);font-size:13px}
|
||||
@media (max-width:640px){.kv{grid-template-columns:1fr}.kv>div{padding:6px 0}.kv .k{padding-top:10px;border-top:1px solid var(--line)}.kv>div:not(.k){border-top:0}}
|
||||
.neg{border-left:2px solid var(--ember);background:var(--row);border-radius:0 var(--r-row) var(--r-row) 0;padding:12px var(--s-4);margin:0 0 var(--s-3);font-size:14px;color:var(--ink-2)}
|
||||
.neg b{font:500 11px/1 var(--f-mono);letter-spacing:.12em;text-transform:uppercase;color:var(--ember-text);margin-right:8px}.neg.wrong{border-color:var(--molten)}.neg.wrong b{color:var(--molten-text)}
|
||||
.neg small{display:block;color:var(--ash);font-family:var(--f-mono);font-size:12px;margin-top:4px;overflow-wrap:anywhere}
|
||||
.steps{list-style:none;margin:0;padding:0;display:grid;gap:8px}
|
||||
.steps li{display:grid;grid-template-columns:84px 1fr;gap:4px 12px;background:var(--row);border:1px solid var(--line);border-radius:var(--r-row);padding:10px 14px;font-size:14px;color:var(--ink-2)}
|
||||
.steps li b{font:500 11px/1.6 var(--f-mono);letter-spacing:.12em;text-transform:uppercase;color:var(--ember-text)}.steps li.bad b{color:var(--molten-text)}
|
||||
.steps li small{grid-column:2;color:var(--ash);font-family:var(--f-mono);font-size:12px;overflow-wrap:anywhere}
|
||||
.why{border:1px solid var(--line-2);border-radius:var(--r-card);padding:var(--s-4) var(--s-5);background:var(--obsidian);margin:var(--s-5) 0}
|
||||
.why p{margin:0;font-size:15px;color:var(--ink-2)}.why p+p{margin-top:8px}
|
||||
.meta{display:grid;gap:6px;font:400 13px/1.6 var(--f-mono);color:var(--ash);margin:var(--s-4) 0 0}.meta code{overflow-wrap:anywhere}
|
||||
@media (max-width:640px){.steps li{grid-template-columns:1fr}.steps li small{grid-column:1}}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<!-- nav:start -->
|
||||
<a class="skip" href="#main">Skip to content</a>
|
||||
<nav class="nav" aria-label="Main" data-nav-version="5">
|
||||
<div class="container nav-row">
|
||||
<a href="/" class="logo" aria-label="Igneum home">
|
||||
<svg class="brand-mark" viewBox="0 0 1024 1024" aria-hidden="true"><rect width="1024" height="1024" rx="160" fill="#0C0C0E"></rect><g transform="translate(166.95 166.95) scale(6.901)"><polygon points="50,4 74,34 67,58 80,54 61,96 39,96 20,54 33,58 26,34" fill="#F2541B"></polygon><polygon points="50,42 59,58 50,82 41,58" fill="#0C0C0E"></polygon></g></svg>
|
||||
<span class="word">IGNEUM</span>
|
||||
</a>
|
||||
<span class="devnet" id="nav-devnet" title="igneum-devnet-3, chain id 4463. Coins have no value. The chain may reset."><span class="dot off" id="foot-dot"></span><span id="foot-state">devnet</span></span>
|
||||
<div class="nav-groups" id="nav-groups" role="list">
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-mine" data-group="mine" aria-expanded="false" aria-controls="nav-panel-mine" aria-haspopup="true">Mine<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-network" data-group="network" data-active aria-expanded="false" aria-controls="nav-panel-network" aria-haspopup="true">Network<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-learn" data-group="learn" aria-expanded="false" aria-controls="nav-panel-learn" aria-haspopup="true">Learn<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-build" data-group="build" aria-expanded="false" aria-controls="nav-panel-build" aria-haspopup="true">Build<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
</div>
|
||||
<div class="nav-controls">
|
||||
<button class="btn icon-btn" type="button" data-theme-toggle aria-label="Switch to light theme"><svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><circle cx="12" cy="12" r="4"/><path d="M12 2v2m0 16v2M2 12h2m16 0h2M5 5l1 1m12 12 1 1M5 19l1-1M18 6l1-1"/></svg></button>
|
||||
<a href="/download" class="btn primary small cta" data-nav="download">Download</a>
|
||||
<button class="burger" id="nav-burger" type="button" aria-expanded="false" aria-controls="nav-sheet" aria-label="Open the menu" aria-haspopup="true"><svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path class="bars" d="M4 6h16M4 12h16M4 18h16"/><path class="cross" d="m6 6 12 12M6 18 18 6"/></svg></button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="panels" id="nav-panels">
|
||||
<div class="panel-wrap container">
|
||||
<div class="nav-panel" id="nav-panel-mine" data-group="mine" role="region" aria-labelledby="nav-btn-mine" hidden>
|
||||
<div class="panel-list">
|
||||
<a href="/miner" data-nav="miner"><b>Ember, the miner</b><span>One click installs the node, the miner and the prover.</span></a>
|
||||
<a href="/download" data-nav="download"><b>Download</b><span>Windows, macOS, Linux and HiveOS.</span></a>
|
||||
<a href="/app" data-nav="app"><b>The app</b><span>What you see while the card mines.</span></a>
|
||||
<a href="/wallet" data-nav="wallet"><b>The wallet</b><span>Your coins. Final means final.</span></a>
|
||||
<a href="/miners" data-nav="miners"><b>GPU bench table</b><span>Measured rates, card by card.</span></a>
|
||||
<a href="/dev-fee" data-nav="dev-fee"><b>The dev fee</b><span>The optional one, in full view, off with one flag.</span></a>
|
||||
<a href="/metamask" data-nav="metamask"><b>Add to MetaMask</b><span>Igneum as a network in your wallet.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-panel" id="nav-panel-network" data-group="network" role="region" aria-labelledby="nav-btn-network" hidden>
|
||||
<div class="panel-list">
|
||||
<a href="/live" data-nav="live"><b>Live devnet</b><span>The chain as it grows, one lane per miner.</span></a>
|
||||
<a href="/explorer" data-nav="explorer"><b>Explorer</b><span>Look a block or an address up.</span></a>
|
||||
<a href="/journey" data-nav="journey"><b>The journey</b><span>Six phases, four gates, the log behind them.</span></a>
|
||||
<a href="/bench" data-nav="bench"><b>Engineering log</b><span>Every measurement, with the commands that made it.</span></a>
|
||||
<a href="/evidence" data-nav="evidence"><b>Evidence</b><span>Every claim and how far it is tested.</span></a>
|
||||
<a href="/light" data-nav="light" aria-current="page"><b>Light wallet</b><span>A balance your browser proves, trusting no node.</span></a>
|
||||
<a href="/receipt" data-nav="receipt"><b>Payment receipt</b><span>A receipt any third party re-verifies offline.</span></a>
|
||||
<a href="/oracle" data-nav="oracle"><b>State oracle on Sepolia</b><span>Devnet 3 balances read from another chain.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-panel" id="nav-panel-learn" data-group="learn" role="region" aria-labelledby="nav-btn-learn" hidden>
|
||||
<div class="panel-list">
|
||||
<a href="/litepaper" data-nav="litepaper"><b>Litepaper</b><span>The design, as published.</span></a>
|
||||
<a href="/income" data-nav="income"><b>Income per tier</b><span>IGN a day per card at three network sizes, and the electricity.</span></a>
|
||||
<a href="/ledger" data-nav="ledger"><b>Ledger</b><span>Every criticism, answered or conceded.</span></a>
|
||||
<a href="/claims" data-nav="claims"><b>What Igneum does not claim</b><span>The limits, stated first.</span></a>
|
||||
<a href="/randomx" data-nav="randomx"><b>Igneum vs RandomX</b><span>What was kept and what was rebuilt for GPUs.</span></a>
|
||||
<a href="/provenance" data-nav="provenance"><b>Built on the shoulders</b><span>Every borrowed part, credited.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-panel" id="nav-panel-build" data-group="build" role="region" aria-labelledby="nav-btn-build" hidden>
|
||||
<div class="panel-list">
|
||||
<a href="/build" data-nav="build"><b>Build on Igneum</b><span>Chain ids, RPC, a contract in five minutes.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Devnet faucet</b><span>10 IGN of devnet coin, once a day.</span></a>
|
||||
<a href="/swap" data-nav="swap"><b>Swap</b><span>Test tokens on Devnet 3; every swap is a proven block.</span></a>
|
||||
<a href="/grants" data-nav="grants"><b>Grants</b><span>Tooling, apps, infrastructure, research.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-sheet" id="nav-sheet" role="dialog" aria-modal="true" aria-label="Menu" hidden>
|
||||
<div class="sheet-scroll">
|
||||
<div class="sheet-group"><div class="sheet-head">Mine</div>
|
||||
<a href="/miner" data-nav="miner"><b>Ember, the miner</b><span>One click installs the node, the miner and the prover.</span></a>
|
||||
<a href="/download" data-nav="download"><b>Download</b><span>Windows, macOS, Linux and HiveOS.</span></a>
|
||||
<a href="/app" data-nav="app"><b>The app</b><span>What you see while the card mines.</span></a>
|
||||
<a href="/wallet" data-nav="wallet"><b>The wallet</b><span>Your coins. Final means final.</span></a>
|
||||
<a href="/miners" data-nav="miners"><b>GPU bench table</b><span>Measured rates, card by card.</span></a>
|
||||
<a href="/dev-fee" data-nav="dev-fee"><b>The dev fee</b><span>The optional one, in full view, off with one flag.</span></a>
|
||||
<a href="/metamask" data-nav="metamask"><b>Add to MetaMask</b><span>Igneum as a network in your wallet.</span></a>
|
||||
</div>
|
||||
<div class="sheet-group"><div class="sheet-head">Network</div>
|
||||
<a href="/live" data-nav="live"><b>Live devnet</b><span>The chain as it grows, one lane per miner.</span></a>
|
||||
<a href="/explorer" data-nav="explorer"><b>Explorer</b><span>Look a block or an address up.</span></a>
|
||||
<a href="/journey" data-nav="journey"><b>The journey</b><span>Six phases, four gates, the log behind them.</span></a>
|
||||
<a href="/bench" data-nav="bench"><b>Engineering log</b><span>Every measurement, with the commands that made it.</span></a>
|
||||
<a href="/evidence" data-nav="evidence"><b>Evidence</b><span>Every claim and how far it is tested.</span></a>
|
||||
<a href="/light" data-nav="light" aria-current="page"><b>Light wallet</b><span>A balance your browser proves, trusting no node.</span></a>
|
||||
<a href="/receipt" data-nav="receipt"><b>Payment receipt</b><span>A receipt any third party re-verifies offline.</span></a>
|
||||
<a href="/oracle" data-nav="oracle"><b>State oracle on Sepolia</b><span>Devnet 3 balances read from another chain.</span></a>
|
||||
</div>
|
||||
<div class="sheet-group"><div class="sheet-head">Learn</div>
|
||||
<a href="/litepaper" data-nav="litepaper"><b>Litepaper</b><span>The design, as published.</span></a>
|
||||
<a href="/income" data-nav="income"><b>Income per tier</b><span>IGN a day per card at three network sizes, and the electricity.</span></a>
|
||||
<a href="/ledger" data-nav="ledger"><b>Ledger</b><span>Every criticism, answered or conceded.</span></a>
|
||||
<a href="/claims" data-nav="claims"><b>What Igneum does not claim</b><span>The limits, stated first.</span></a>
|
||||
<a href="/randomx" data-nav="randomx"><b>Igneum vs RandomX</b><span>What was kept and what was rebuilt for GPUs.</span></a>
|
||||
<a href="/provenance" data-nav="provenance"><b>Built on the shoulders</b><span>Every borrowed part, credited.</span></a>
|
||||
</div>
|
||||
<div class="sheet-group"><div class="sheet-head">Build</div>
|
||||
<a href="/build" data-nav="build"><b>Build on Igneum</b><span>Chain ids, RPC, a contract in five minutes.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Devnet faucet</b><span>10 IGN of devnet coin, once a day.</span></a>
|
||||
<a href="/swap" data-nav="swap"><b>Swap</b><span>Test tokens on Devnet 3; every swap is a proven block.</span></a>
|
||||
<a href="/grants" data-nav="grants"><b>Grants</b><span>Tooling, apps, infrastructure, research.</span></a>
|
||||
</div>
|
||||
<div class="sheet-foot">
|
||||
<a href="/download" class="btn primary big" data-nav="download">Download</a>
|
||||
<div class="sheet-social"><a href="https://discord.gg/igneum" target="_blank" rel="noopener">Discord</a><a href="https://git.igneum.network/igneum-network/spec" target="_blank" rel="noopener">Source</a><a href="https://www.reddit.com/user/Igneum_network/" target="_blank" rel="noopener">Reddit</a></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
<script>
|
||||
(function(){
|
||||
// the slim bar (site-ui-5, 7 Oct 2026): three group buttons open one panel each; the burger opens the sheet on phones.
|
||||
// Keyboard: Enter or Space opens a group, Escape closes it and returns focus to its button, arrows move between the
|
||||
// group buttons, Tab walks the open panel's links, a click outside closes. The theme toggle flips data-theme and stores it.
|
||||
var n=document.querySelector('.nav');if(!n)return;
|
||||
var btns=[].slice.call(n.querySelectorAll('.group-btn')),panels=[].slice.call(n.querySelectorAll('.nav-panel')),wrap=n.querySelector('.panels');
|
||||
var burger=document.getElementById('nav-burger'),sheet=document.getElementById('nav-sheet');
|
||||
function panelOf(g){return panels.filter(function(p){return p.getAttribute('data-group')===g;})[0];}
|
||||
function closeAll(focusBack){var was=null;btns.forEach(function(b){if(b.getAttribute('aria-expanded')==='true')was=b;b.setAttribute('aria-expanded','false');});panels.forEach(function(p){p.hidden=true;});n.classList.remove('panel-open');if(focusBack&&was)was.focus();}
|
||||
function open(g){closeAll(false);var b=btns.filter(function(x){return x.getAttribute('data-group')===g;})[0],p=panelOf(g);if(!b||!p)return;b.setAttribute('aria-expanded','true');p.hidden=false;n.classList.add('panel-open');anchor(b,p);}
|
||||
// the panel sits under its button; a panel that would run past the container's right edge aligns its right edge to the button's right edge instead (never past the viewport)
|
||||
function anchor(b,p){var pw=n.querySelector('.panel-wrap');if(!pw)return;var cr=pw.getBoundingClientRect(),br=b.getBoundingClientRect(),w=p.offsetWidth,left=br.left-cr.left;if(left+w>cr.width)left=(br.right-cr.left)-w;if(left<0)left=0;p.style.setProperty('--panel-left',Math.round(left)+'px');}
|
||||
window.addEventListener('resize',function(){var o=btns.filter(function(x){return x.getAttribute('aria-expanded')==='true';})[0];if(o)anchor(o,panelOf(o.getAttribute('data-group')));}); btns.forEach(function(b,i){
|
||||
b.addEventListener('click',function(){var on=b.getAttribute('aria-expanded')==='true';if(on)closeAll(false);else open(b.getAttribute('data-group'));});
|
||||
b.addEventListener('keydown',function(e){
|
||||
var k=e.key;
|
||||
if(k==='ArrowRight'||k==='ArrowLeft'){e.preventDefault();var j=(i+(k==='ArrowRight'?1:btns.length-1))%btns.length;btns[j].focus();if(n.classList.contains('panel-open'))open(btns[j].getAttribute('data-group'));}
|
||||
else if(k==='ArrowDown'){e.preventDefault();open(b.getAttribute('data-group'));var f=panelOf(b.getAttribute('data-group')).querySelector('a');if(f)f.focus();}
|
||||
else if(k==='Escape'){closeAll(true);}
|
||||
});
|
||||
});
|
||||
if(wrap)wrap.addEventListener('keydown',function(e){if(e.key==='Escape'){e.stopPropagation();closeAll(true);}});
|
||||
document.addEventListener('click',function(e){if(!n.classList.contains('panel-open'))return;if(e.target.closest('.group-btn')||e.target.closest('.nav-panel'))return;closeAll(false);});
|
||||
document.addEventListener('focusin',function(e){if(!n.classList.contains('panel-open'))return;if(n.contains(e.target))return;closeAll(false);});
|
||||
document.addEventListener('keydown',function(e){if(e.key==='Escape'&&n.classList.contains('panel-open'))closeAll(true);});
|
||||
// the sheet on phones
|
||||
function setSheet(o){if(!burger||!sheet)return;n.classList.toggle('open',o);sheet.hidden=!o;burger.setAttribute('aria-expanded',o?'true':'false');burger.setAttribute('aria-label',o?'Close the menu':'Open the menu');document.documentElement.classList.toggle('nav-locked',o);if(o){var f=sheet.querySelector('a');if(f)f.focus();}}
|
||||
if(burger&&sheet){
|
||||
burger.addEventListener('click',function(){setSheet(!n.classList.contains('open'));});
|
||||
sheet.addEventListener('click',function(e){if(e.target.closest('a'))setSheet(false);});
|
||||
sheet.addEventListener('keydown',function(e){
|
||||
if(e.key==='Escape'){setSheet(false);burger.focus();return;}
|
||||
if(e.key!=='Tab')return;var f=sheet.querySelectorAll('a,button');if(!f.length)return;var first=f[0],last=f[f.length-1];
|
||||
if(e.shiftKey&&document.activeElement===first){e.preventDefault();burger.focus();}else if(!e.shiftKey&&document.activeElement===last){e.preventDefault();burger.focus();}
|
||||
});
|
||||
burger.addEventListener('keydown',function(e){if(e.key==='Tab'&&!e.shiftKey&&n.classList.contains('open')){e.preventDefault();var f=sheet.querySelector('a');if(f)f.focus();}});
|
||||
var mq=window.matchMedia('(min-width:861px)');if(mq.addEventListener)mq.addEventListener('change',function(){setSheet(false);});
|
||||
}
|
||||
// the theme toggle
|
||||
var t=n.querySelector('[data-theme-toggle]');
|
||||
function paintToggle(){var dark=document.documentElement.getAttribute('data-theme')!=='light';t.setAttribute('aria-label',dark?'Switch to light theme':'Switch to dark theme');t.innerHTML=dark?'<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><circle cx="12" cy="12" r="4"/><path d="M12 2v2m0 16v2M2 12h2m16 0h2M5 5l1 1m12 12 1 1M5 19l1-1M18 6l1-1"/></svg>':'<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="M20.7 13.3A8.5 8.5 0 0 1 10.7 3.3 8.5 8.5 0 1 0 20.7 13.3Z"/></svg>';}
|
||||
if(t){t.addEventListener('click',function(){var v=document.documentElement.getAttribute('data-theme')==='light'?'dark':'light';document.documentElement.setAttribute('data-theme',v);try{localStorage.setItem('igneum-theme',v);}catch(e){}document.dispatchEvent(new CustomEvent('igneum-theme'));});paintToggle();document.addEventListener('igneum-theme',paintToggle);}
|
||||
})();
|
||||
</script>
|
||||
<!-- nav:end -->
|
||||
<main id="main" class="wrap">
|
||||
<div class="head">
|
||||
<div class="breadcrumb"><a href="/">Igneum</a><span>/</span><span>Light wallet</span></div>
|
||||
<div class="eyebrow"><span class="line"></span>Reference app 1 · Devnet 3, no value</div>
|
||||
<h1>A balance your browser proves<span class="accent">.</span></h1>
|
||||
</div>
|
||||
<p class="note">Paste a Devnet 3 address. This tab fetches the latest finality certificate, the header chain, the carrier block's coinbase, the segment record and an account proof from a read service, then checks every byte itself: BLS over the checkpoint, every header hash and parent link, the merkle path, the aggregator's signature, the Merkle Patricia proof under the proven state root. The service cannot lie about the balance. It can only refuse to answer.</p>
|
||||
|
||||
<div class="why">
|
||||
<p><b>Why this only works on a proven chain.</b> The balance rests on a state root that an aggregator signed inside a block, after proving the segment's execution, and that every node checks against its own execution before paying the record. On a chain without proofs a light client has only a node's word for a balance.</p>
|
||||
<p>Source: <code>site/lc/core.js</code> (the checks), <code>site/lc/app.js</code> (this page), <code>tools/reference-apps/light-service/serve.mjs</code> (the read service), fork branch <code>light-apps-node</code> (<code>eth_getProof</code> on the node). Test with the negative cases: <a href="/lc/test">/lc/test</a> in the browser, <code>tools/reference-apps/light-service/verify.test.mjs</code> under Node.</p>
|
||||
</div>
|
||||
|
||||
<section class="card" aria-labelledby="verify">
|
||||
<h2 id="verify">Verify a balance</h2>
|
||||
<form class="vform" data-form="light" novalidate>
|
||||
<label for="address">Devnet 3 address</label>
|
||||
<div class="row"><input id="address" name="address" inputmode="text" autocomplete="off" spellcheck="false" placeholder="0x…" pattern="^0x[0-9a-fA-F]{40}$"><button class="btn primary" type="submit">Verify in this tab</button></div>
|
||||
<div class="vstatus" data-status role="status" aria-live="polite">Devnet 3, no value. Nothing here is a wallet that sends. It reads and proves.</div>
|
||||
</form>
|
||||
<div data-result></div>
|
||||
</section>
|
||||
|
||||
<h2 id="checked">What is checked, in order</h2>
|
||||
<ol>
|
||||
<li>The certificate: the aggregate BLS signature of the signers over <code>igneum-vote-v1/igneum-devnet-3 || index || checkpoint hash</code>, the canonical voter order, the rule (two thirds of active weight, 17/30 of total), and the header chain from the previous lock.</li>
|
||||
<li>The header path from the carrier block up to the certified checkpoint: every header hash recomputes (BLAKE2b-256 keyed BlockHash over the header fields), every next header names the previous as a direct parent.</li>
|
||||
<li>The coinbase transaction is in the carrier block: its hash recomputes (BLAKE2b-256 keyed TransactionHash over the serialized transaction) and the merkle path reaches the header's <code>hash_merkle_root</code>.</li>
|
||||
<li>The segment record in the coinbase extra data: the aggregator's BLS signature over the record under the network's tag, whether the key is a voter with weight or a prove-only key, and the statement names the chain and the block whose state it commits.</li>
|
||||
<li>The account proof: a keccak-keyed Merkle Patricia proof under the record's <code>post_root</code>, every node hashed on the way down, the balance read from the leaf.</li>
|
||||
</ol>
|
||||
<p class="note">What is trusted and said so on the result: the aggregator's statement being the true execution result (nodes check it natively before paying; the SP1 proof behind it is verified by nodes, not in this tab yet), and the voter table with weights, which comes from the node (spec 10.1). The read service names the node it reads.</p>
|
||||
<p class="asof">Devnet 3, no value. The chain may reset. Pages like this one are demonstrations of the verification path, not a product.</p>
|
||||
</main>
|
||||
<script type="module" src="/lc/app.js"></script>
|
||||
<!-- footer:start -->
|
||||
<footer class="site-footer">
|
||||
<div class="container">
|
||||
<div class="footer-grid">
|
||||
<div class="footer-brand">
|
||||
<a href="/" class="logo" aria-label="Igneum home"><svg class="brand-mark" viewBox="0 0 1024 1024" aria-hidden="true"><rect width="1024" height="1024" rx="160" fill="#0C0C0E"></rect><g transform="translate(166.95 166.95) scale(6.901)"><polygon points="50,4 74,34 67,58 80,54 61,96 39,96 20,54 33,58 26,34" fill="#F2541B"></polygon><polygon points="50,42 59,58 50,82 41,58" fill="#0C0C0E"></polygon></g></svg><span class="word">IGNEUM</span><span class="stop">.</span></a>
|
||||
<p>Mined by GPUs. Proven by fire.</p>
|
||||
<div class="social" aria-label="Igneum elsewhere">
|
||||
<a href="https://git.igneum.network/igneum-network/spec" target="_blank" rel="noopener" aria-label="Igneum source: the spec, the vectors and the issues"><svg viewBox="0 0 24 24" width="22" height="22" fill="currentColor" aria-hidden="true"><path d="M8.6 17.6 3 12l5.6-5.6 1.4 1.4L5.8 12l4.2 4.2zm6.8 0-1.4-1.4L18.2 12 14 7.8l1.4-1.4L21 12z"></path></svg></a>
|
||||
<a href="https://discord.gg/igneum" target="_blank" rel="noopener" aria-label="The Igneum Discord"><svg viewBox="0 0 24 24" width="22" height="22" fill="currentColor" aria-hidden="true"><path d="M19.6 5.3A17 17 0 0 0 15.4 4l-.2.4a15.6 15.6 0 0 1 3.9 1.9 13.6 13.6 0 0 0-14.2 0A15.6 15.6 0 0 1 8.8 4.4L8.6 4a17 17 0 0 0-4.2 1.3C1.8 9.2 1.1 13 1.4 16.7a17.1 17.1 0 0 0 5.2 2.6l1.1-1.8a10.8 10.8 0 0 1-1.7-.8l.4-.3a12.2 12.2 0 0 0 11.2 0l.4.3-1.7.8 1.1 1.8a17 17 0 0 0 5.2-2.6c.4-4.3-.7-8-3-11.4zM8.7 14.4c-1 0-1.8-.9-1.8-2.1s.8-2.1 1.8-2.1 1.9 1 1.8 2.1c0 1.2-.8 2.1-1.8 2.1zm6.6 0c-1 0-1.8-.9-1.8-2.1s.8-2.1 1.8-2.1 1.9 1 1.8 2.1c0 1.2-.8 2.1-1.8 2.1z"></path></svg></a>
|
||||
<a data-social="reddit" href="https://www.reddit.com/user/Igneum_network/" target="_blank" rel="noopener" aria-label="Igneum on Reddit"><svg viewBox="0 0 24 24" width="22" height="22" fill="currentColor" aria-hidden="true"><path d="M22 12.1a2.2 2.2 0 0 0-3.7-1.6 10.8 10.8 0 0 0-5.8-1.8l1-4.6 3.2.7a1.5 1.5 0 1 0 .2-.9l-3.6-.8a.5.5 0 0 0-.5.4l-1.1 5.2a10.8 10.8 0 0 0-5.9 1.8A2.2 2.2 0 1 0 3.4 14a4.3 4.3 0 0 0 0 .7c0 3.4 3.9 6.1 8.6 6.1s8.6-2.7 8.6-6.1a4.3 4.3 0 0 0 0-.7 2.2 2.2 0 0 0 1.4-1.9zM7 13.6a1.5 1.5 0 1 1 1.5 1.5A1.5 1.5 0 0 1 7 13.6zm8.6 4.1a5.7 5.7 0 0 1-3.6 1.1 5.7 5.7 0 0 1-3.6-1.1.4.4 0 0 1 .6-.6 4.9 4.9 0 0 0 3 .9 4.9 4.9 0 0 0 3-.9.4.4 0 0 1 .6.6zm-.3-2.6a1.5 1.5 0 1 1 1.5-1.5 1.5 1.5 0 0 1-1.5 1.5z"></path></svg></a>
|
||||
</div>
|
||||
<div class="footer-dl" aria-label="Download Ember"><a href="/download#windows"><span class="osmark mini" data-os="windows" title="Windows"><svg viewBox="0 0 24 24" width="22" height="22" aria-hidden="true" focusable="false" fill="currentColor"><path d="M3 5.6l7.3-1v7.1H3zM11.4 4.4L21 3v8.7h-9.6zM3 12.3h7.3v7.1L3 18.4zM11.4 12.3H21V21l-9.6-1.4z"/></svg></span>Windows</a><a href="/download#mac"><span class="osmark mini" data-os="mac" title="macOS"><svg viewBox="0 0 24 24" width="22" height="22" aria-hidden="true" focusable="false" fill="currentColor"><path d="M16.4 12.6c0-2.5 2-3.6 2.1-3.7-1.2-1.7-3-1.9-3.6-2-1.5-.2-3 .9-3.8.9-.8 0-2-.9-3.3-.8-1.7 0-3.2 1-4.1 2.5-1.8 3-.5 7.6 1.3 10.1.9 1.2 1.9 2.6 3.2 2.5 1.3 0 1.8-.8 3.3-.8 1.6 0 2 .8 3.3.8 1.4 0 2.3-1.2 3.1-2.5 1-1.4 1.4-2.8 1.4-2.9 0 0-2.7-1-2.9-4.1zM13.9 5.3c.7-.8 1.2-2 1-3.2-1 0-2.2.7-2.9 1.5-.6.7-1.2 1.9-1 3 1.1.1 2.2-.5 2.9-1.3z"/></svg></span>macOS</a><a href="/download#linux"><span class="osmark mini" data-os="linux" title="Linux"><svg viewBox="0 0 24 24" width="22" height="22" aria-hidden="true" focusable="false" fill="currentColor"><path d="M12 2c-2.4 0-4 1.9-4 4.6 0 1.2.2 2 0 2.8-.6 1.4-2.1 2.9-2.6 4.9-.3 1.1-.1 2 .3 2.6-.6.4-1.3 1-1.1 1.7.3 1 2.1 1.2 3.2 1.8.7.4 1.5.6 2.1.1.6.2 1.3.3 2.1.3s1.5-.1 2.1-.3c.6.5 1.4.3 2.1-.1 1.1-.6 2.9-.8 3.2-1.8.2-.7-.5-1.3-1.1-1.7.4-.6.6-1.5.3-2.6-.5-2-2-3.5-2.6-4.9-.2-.8 0-1.6 0-2.8C16 3.9 14.4 2 12 2zm-1.4 4.2c.5 0 .8.5.8 1.2s-.3 1.2-.8 1.2-.8-.5-.8-1.2.3-1.2.8-1.2zm2.8 0c.5 0 .8.5.8 1.2s-.3 1.2-.8 1.2-.8-.5-.8-1.2.3-1.2.8-1.2zM12 9.3c.9 0 1.9.5 1.9 1s-1 1.2-1.9 1.2-1.9-.7-1.9-1.2 1-1 1.9-1zm0 3.4c2.2 0 3.6 2.6 3.6 4.4 0 1.5-1.6 2.3-3.6 2.3s-3.6-.8-3.6-2.3c0-1.8 1.4-4.4 3.6-4.4z"/></svg></span>Linux</a><a href="/download#hive"><span class="osmark mini" data-os="hive" title="HiveOS"><svg viewBox="0 0 24 24" width="22" height="22" aria-hidden="true" focusable="false" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linejoin="round" stroke-linecap="round"><path d="M12 2.6 20.2 7.3v9.4L12 21.4 3.8 16.7V7.3z"/><path d="M12 7.4 16 9.7v4.6L12 16.6 8 14.3V9.7z"/><path d="M12 7.4V2.6M16 9.7l4.2-2.4M16 14.3l4.2 2.4M12 16.6v4.8M8 14.3l-4.2 2.4M8 9.7 3.8 7.3"/></svg></span>HiveOS</a></div>
|
||||
<a href="https://git.igneum.network/igneum-network/spec" target="_blank" rel="noopener" class="text-link">Specification and test vectors<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="M6 18 18 6M6 6h12v12"/></svg></a>
|
||||
</div>
|
||||
<div class="footer-column"><h4>Run</h4><div>
|
||||
<a href="/download">Download Ember</a>
|
||||
<a href="/miner">The miner</a>
|
||||
<a href="/app">The app</a>
|
||||
<a href="/wallet">The wallet</a>
|
||||
<a href="/miners">GPU bench table</a>
|
||||
<a href="/dev-fee">The dev fee</a>
|
||||
<a href="/faucet">Devnet faucet</a>
|
||||
<a href="/metamask">Add Igneum to MetaMask</a>
|
||||
</div></div>
|
||||
<div class="footer-column"><h4>Read</h4><div>
|
||||
<a href="/litepaper">Litepaper</a>
|
||||
<a href="/evidence">Evidence</a>
|
||||
<a href="/bench">Engineering log</a>
|
||||
<a href="/ledger">Ledger: every criticism</a>
|
||||
<a href="/claims">What Igneum does not claim</a>
|
||||
<a href="/randomx">Igneum vs RandomX</a>
|
||||
<a href="/provenance">Built on the shoulders</a>
|
||||
</div></div>
|
||||
<div class="footer-column"><h4>Explore</h4><div>
|
||||
<a href="/live">Live devnet</a>
|
||||
<a href="/explorer">Explorer</a>
|
||||
<a href="/build">Build on Igneum</a>
|
||||
<a href="/swap">Swap</a>
|
||||
<a href="/grants">Grants</a>
|
||||
<a href="/journey">Journey</a>
|
||||
<a href="/download">Downloads: devnet build</a>
|
||||
<a href="https://discord.gg/igneum" target="_blank" rel="noopener">Community Discord</a>
|
||||
<a href="mailto:hello@igneum.network">hello@igneum.network</a>
|
||||
<a href="https://git.igneum.network/igneum-network/spec/issues" rel="noopener">An issue on the spec</a>
|
||||
</div></div>
|
||||
</div>
|
||||
<div class="footer-bottom">
|
||||
<p>Igneum Labs LTD · Unit IH-00-01-01-OF-01, Level 01, Innovation One, Dubai International Financial Centre. Experimental software. Nothing on this site is an offer to sell anything.<br>Report a flaw by email or by an issue on the spec. Nobody from Igneum will ask for your seed. © 2026 Igneum · not an offer to sell anything</p>
|
||||
<div class="theme-group" role="group" aria-label="Theme"><button type="button" data-theme-set="system" aria-pressed="true">System</button><button type="button" data-theme-set="light" aria-pressed="false">Light</button><button type="button" data-theme-set="dark" aria-pressed="false">Dark</button></div>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
<script>
|
||||
(function(){
|
||||
// theme control: stores light or dark under igneum-theme; system clears it and follows the OS. The head applied the value before paint.
|
||||
var bs=document.querySelectorAll('[data-theme-set]');if(!bs.length)return;
|
||||
var media=window.matchMedia('(prefers-color-scheme: light)');
|
||||
function stored(){try{var t=localStorage.getItem('igneum-theme');return t==='light'||t==='dark'?t:'system';}catch(e){return 'system';}}
|
||||
function apply(){var c=stored();document.documentElement.setAttribute('data-theme',c==='system'?(media.matches?'light':'dark'):c);bs.forEach(function(b){b.setAttribute('aria-pressed',b.getAttribute('data-theme-set')===c?'true':'false');});document.dispatchEvent(new CustomEvent('igneum-theme'));}
|
||||
bs.forEach(function(b){b.addEventListener('click',function(){var v=b.getAttribute('data-theme-set');try{if(v==='system')localStorage.removeItem('igneum-theme');else localStorage.setItem('igneum-theme',v);}catch(e){}apply();});});
|
||||
if(media.addEventListener)media.addEventListener('change',function(){if(stored()==='system')apply();});
|
||||
document.addEventListener('igneum-theme',function(){var c=stored();bs.forEach(function(b){b.setAttribute('aria-pressed',b.getAttribute('data-theme-set')===c?'true':'false');});});
|
||||
bs.forEach(function(b){b.setAttribute('aria-pressed',b.getAttribute('data-theme-set')===stored()?'true':'false');});
|
||||
// the network state word in the status bar: one read of the observer per page view
|
||||
var fs=document.getElementById('foot-state'),fd=document.getElementById('foot-dot');if(fs&&fd){fetch('/api/live?window=30',{cache:'no-store'}).then(function(r){return r.json();}).then(function(d){var on=d&&d.ok&&d.state&&!d.state.stale;fs.textContent=on?'devnet live':'devnet, observer stale';fd.className='dot '+(on?'live':'off');}).catch(function(){fs.textContent='devnet';});}
|
||||
})();
|
||||
</script>
|
||||
<!-- footer:end -->
|
||||
<script>
|
||||
(function(){
|
||||
// one request per button; the wallet shows the chain to the user and decides. No key, no seed, no signature here.
|
||||
var CHAINS = {
|
||||
testnet: { chainId: '0x116e', chainName: 'Igneum Testnet', nativeCurrency: { name: 'Igneum', symbol: 'IGN', decimals: 18 }, rpcUrls: ['https://rpc.testnet.igneum.network'], blockExplorerUrls: [] },
|
||||
devnet: { chainId: '0x116f', chainName: 'Igneum Devnet (local node)', nativeCurrency: { name: 'Igneum', symbol: 'IGN', decimals: 18 }, rpcUrls: ['http://127.0.0.1:26790'], blockExplorerUrls: [] }
|
||||
};
|
||||
function status(name, text) { var el = document.querySelector('[data-status="' + name + '"]'); if (el) el.textContent = text; }
|
||||
Array.prototype.forEach.call(document.querySelectorAll('[data-add]'), function (btn) {
|
||||
btn.addEventListener('click', function () {
|
||||
var name = btn.getAttribute('data-add'); var chain = CHAINS[name];
|
||||
if (!window.ethereum || !window.ethereum.request) { status(name, 'No Ethereum wallet found in this browser. Install MetaMask, or add the network by hand (below).'); return; }
|
||||
status(name, 'Waiting for the wallet...');
|
||||
window.ethereum.request({ method: 'wallet_addEthereumChain', params: [chain] })
|
||||
.then(function () { status(name, 'Added. The wallet is on ' + chain.chainName + ' (chain id ' + parseInt(chain.chainId, 16) + ').'); })
|
||||
.catch(function (e) { status(name, e && e.code === 4001 ? 'Cancelled in the wallet.' : 'The wallet refused: ' + ((e && e.message) || 'unknown error') + '. Add it by hand (below).'); });
|
||||
});
|
||||
});
|
||||
})();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -143,6 +143,7 @@ body.all .pager{display:none}
|
|||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-mine" data-group="mine" aria-expanded="false" aria-controls="nav-panel-mine" aria-haspopup="true">Mine<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-network" data-group="network" aria-expanded="false" aria-controls="nav-panel-network" aria-haspopup="true">Network<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-learn" data-group="learn" data-active aria-expanded="false" aria-controls="nav-panel-learn" aria-haspopup="true">Learn<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-build" data-group="build" aria-expanded="false" aria-controls="nav-panel-build" aria-haspopup="true">Build<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
</div>
|
||||
<div class="nav-controls">
|
||||
<button class="btn icon-btn" type="button" data-theme-toggle aria-label="Switch to light theme"><svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><circle cx="12" cy="12" r="4"/><path d="M12 2v2m0 16v2M2 12h2m16 0h2M5 5l1 1m12 12 1 1M5 19l1-1M18 6l1-1"/></svg></button>
|
||||
|
|
@ -160,7 +161,6 @@ body.all .pager{display:none}
|
|||
<a href="/wallet" data-nav="wallet"><b>The wallet</b><span>Your coins. Final means final.</span></a>
|
||||
<a href="/miners" data-nav="miners"><b>GPU bench table</b><span>Measured rates, card by card.</span></a>
|
||||
<a href="/dev-fee" data-nav="dev-fee"><b>The dev fee</b><span>The optional one, in full view, off with one flag.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Testnet faucet</b><span>Test coin for an address, once a day.</span></a>
|
||||
<a href="/metamask" data-nav="metamask"><b>Add to MetaMask</b><span>Igneum as a network in your wallet.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -171,6 +171,9 @@ body.all .pager{display:none}
|
|||
<a href="/journey" data-nav="journey"><b>The journey</b><span>Six phases, four gates, the log behind them.</span></a>
|
||||
<a href="/bench" data-nav="bench"><b>Engineering log</b><span>Every measurement, with the commands that made it.</span></a>
|
||||
<a href="/evidence" data-nav="evidence"><b>Evidence</b><span>Every claim and how far it is tested.</span></a>
|
||||
<a href="/light" data-nav="light"><b>Light wallet</b><span>A balance your browser proves, trusting no node.</span></a>
|
||||
<a href="/receipt" data-nav="receipt"><b>Payment receipt</b><span>A receipt any third party re-verifies offline.</span></a>
|
||||
<a href="/oracle" data-nav="oracle"><b>State oracle on Sepolia</b><span>Devnet 3 balances read from another chain.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-panel" id="nav-panel-learn" data-group="learn" role="region" aria-labelledby="nav-btn-learn" hidden>
|
||||
|
|
@ -183,6 +186,14 @@ body.all .pager{display:none}
|
|||
<a href="/provenance" data-nav="provenance"><b>Built on the shoulders</b><span>Every borrowed part, credited.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-panel" id="nav-panel-build" data-group="build" role="region" aria-labelledby="nav-btn-build" hidden>
|
||||
<div class="panel-list">
|
||||
<a href="/build" data-nav="build"><b>Build on Igneum</b><span>Chain ids, RPC, a contract in five minutes.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Devnet faucet</b><span>10 IGN of devnet coin, once a day.</span></a>
|
||||
<a href="/swap" data-nav="swap"><b>Swap</b><span>Test tokens on Devnet 3; every swap is a proven block.</span></a>
|
||||
<a href="/grants" data-nav="grants"><b>Grants</b><span>Tooling, apps, infrastructure, research.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-sheet" id="nav-sheet" role="dialog" aria-modal="true" aria-label="Menu" hidden>
|
||||
|
|
@ -194,7 +205,6 @@ body.all .pager{display:none}
|
|||
<a href="/wallet" data-nav="wallet"><b>The wallet</b><span>Your coins. Final means final.</span></a>
|
||||
<a href="/miners" data-nav="miners"><b>GPU bench table</b><span>Measured rates, card by card.</span></a>
|
||||
<a href="/dev-fee" data-nav="dev-fee"><b>The dev fee</b><span>The optional one, in full view, off with one flag.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Testnet faucet</b><span>Test coin for an address, once a day.</span></a>
|
||||
<a href="/metamask" data-nav="metamask"><b>Add to MetaMask</b><span>Igneum as a network in your wallet.</span></a>
|
||||
</div>
|
||||
<div class="sheet-group"><div class="sheet-head">Network</div>
|
||||
|
|
@ -203,6 +213,9 @@ body.all .pager{display:none}
|
|||
<a href="/journey" data-nav="journey"><b>The journey</b><span>Six phases, four gates, the log behind them.</span></a>
|
||||
<a href="/bench" data-nav="bench"><b>Engineering log</b><span>Every measurement, with the commands that made it.</span></a>
|
||||
<a href="/evidence" data-nav="evidence"><b>Evidence</b><span>Every claim and how far it is tested.</span></a>
|
||||
<a href="/light" data-nav="light"><b>Light wallet</b><span>A balance your browser proves, trusting no node.</span></a>
|
||||
<a href="/receipt" data-nav="receipt"><b>Payment receipt</b><span>A receipt any third party re-verifies offline.</span></a>
|
||||
<a href="/oracle" data-nav="oracle"><b>State oracle on Sepolia</b><span>Devnet 3 balances read from another chain.</span></a>
|
||||
</div>
|
||||
<div class="sheet-group"><div class="sheet-head">Learn</div>
|
||||
<a href="/litepaper" data-nav="litepaper" aria-current="page"><b>Litepaper</b><span>The design, as published.</span></a>
|
||||
|
|
@ -212,6 +225,12 @@ body.all .pager{display:none}
|
|||
<a href="/randomx" data-nav="randomx"><b>Igneum vs RandomX</b><span>What was kept and what was rebuilt for GPUs.</span></a>
|
||||
<a href="/provenance" data-nav="provenance"><b>Built on the shoulders</b><span>Every borrowed part, credited.</span></a>
|
||||
</div>
|
||||
<div class="sheet-group"><div class="sheet-head">Build</div>
|
||||
<a href="/build" data-nav="build"><b>Build on Igneum</b><span>Chain ids, RPC, a contract in five minutes.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Devnet faucet</b><span>10 IGN of devnet coin, once a day.</span></a>
|
||||
<a href="/swap" data-nav="swap"><b>Swap</b><span>Test tokens on Devnet 3; every swap is a proven block.</span></a>
|
||||
<a href="/grants" data-nav="grants"><b>Grants</b><span>Tooling, apps, infrastructure, research.</span></a>
|
||||
</div>
|
||||
<div class="sheet-foot">
|
||||
<a href="/download" class="btn primary big" data-nav="download">Download</a>
|
||||
<div class="sheet-social"><a href="https://discord.gg/igneum" target="_blank" rel="noopener">Discord</a><a href="https://git.igneum.network/igneum-network/spec" target="_blank" rel="noopener">Source</a><a href="https://www.reddit.com/user/Igneum_network/" target="_blank" rel="noopener">Reddit</a></div>
|
||||
|
|
@ -330,7 +349,7 @@ body.all .pager{display:none}
|
|||
<div class="tbl"><table>
|
||||
<thead><tr><th>Piece</th><th>Closest precedent</th><th>What Igneum adds</th><th>State, 7 Oct 2026</th></tr></thead>
|
||||
<tbody>
|
||||
<tr><td>A mining program that regenerates itself, for GPUs</td><td>RandomX on Monero since 2019, for CPUs, a program per hash; the one chip announced against it, Bitmain’s Antminer X9, withdrawn in May 2026 before launch. ProgPoW, as KAWPOW on Ravencoin since 2020, changes the maths inside a fixed program shape every few blocks on GPUs (approximate)</td><td>A whole kernel per hour compiled to native code, a daily dataset from a 256 MB cache, a verifiable delay before the seed, era draws from a genesis reserve</td><td>Measured: hourly swaps on Apple, NVIDIA and AMD cards on the live devnet, 4 October 2026</td></tr>
|
||||
<tr><td>A mining program that regenerates itself, for GPUs</td><td>RandomX on Monero since 2019, for CPUs, a program per hash; one chip shipped against it, Bitmain’s Antminer X5 (September 2023), a board of RISC-V chips at 1.46x per joule over a desktop CPU, on silicon believed mining privately from about 2021; the X9 was withdrawn in May 2026 with zero units; RandomX v2 was released on 25 March 2026 with its activation pending. ProgPoW, as KAWPOW on Ravencoin since 2020, changes the maths inside a fixed program shape every few blocks on GPUs (approximate)</td><td>A whole kernel per hour compiled to native code, a daily dataset from a 256 MB cache, a verifiable delay before the seed, era draws from a genesis reserve</td><td>Measured: hourly swaps on Apple, NVIDIA and AMD cards on the live devnet, 4 October 2026</td></tr>
|
||||
<tr><td>The mining card does paid, useful, verifiable work</td><td>Primecoin's prime chains in 2013 were not useful. Aleo ran proving as consensus and the fastest prover won (both approximate)</td><td>Proving kept apart from the lottery; shards assigned by sortition, not by speed</td><td>Implemented: proving v0 and v1 on Devnet 3 from block zero (7 October 2026), v0 on the first devnet since 5 October 2026. The job market for other chains is Designed</td></tr>
|
||||
<tr><td>A proof-of-work chain where every block is proven</td><td>zkEVMs run as rollups on proof-of-stake Ethereum. Conflux has run GPU-mined EVM apps on a DAG since 2020, without proofs (approximate)</td><td>Proven state on a proof-of-work base layer, produced by the miners themselves</td><td>Implemented in part: shards proven and paid on the devnet. The aggregated block proof checked in consensus is Designed</td></tr>
|
||||
<tr><td>Finality held by miners and not moved by hour-long rentals</td><td>Decred votes with stake. Horizen penalises hidden chains. Kaspa limits merge depth (approximate)</td><td>Vote weight is 30 days of blocks per key. Hashrate that appeared today has no vote</td><td>Implemented: rule v3 live on Devnet 3 from block zero, first lock 7 October 2026; rule v2 ran the first devnet from its first lock on 4 October 2026. External review is owed at gate 3</td></tr>
|
||||
|
|
@ -424,19 +443,19 @@ body.all .pager{display:none}
|
|||
<section id="mining">
|
||||
<h2>Mining: a program that never holds still</h2>
|
||||
<p>Every GPU chain that promised ASIC resistance shipped a fixed algorithm, and a fixed algorithm gets a chip the moment the prize pays for one. Igneum does not have a fixed algorithm.</p>
|
||||
<p>Each hour the chain derives a seed from a locked checkpoint one epoch back, passes it through a ten-minute verifiable delay so no miner can see which program a seed implies before choosing whether to publish a block, and feeds it to a deterministic generator. The generator emits a random integer program built from what graphics cards are uniquely good at: wide parallel integer maths, shuffles between the 32 lanes of a warp, and random reads over a multi-gigabyte dataset that changes daily, so the program waits on memory latency, not on maths or bandwidth. Measured: an RTX 5090 hashes at 95 GB/s of useful 4-byte loads against 1,638 GB/s of sequential writes (engineering log, the RTX 5090 entries). The memory footprint and instruction count are fixed and only the maths sequence is random, so no hour favours one vendor's cards and nobody gains by grinding the seed. Miners compile the program once per hour. Anyone running a node, a wallet or an exchange checks a hash on an ordinary CPU in under ten milliseconds by simulating one warp, so nobody needs a GPU except to mine. Measured: 0.61 ms per warp on one Apple M5 Max core for class v2 and 2.1 ms for class v3 (the mixer at x8, 5 October 2026, one core at load average 5.5, worst cold unit 2.15 ms), 3.4x the class v2 verifier; the 10 ms gate leaves 4.8x (4.6x on the worst cold unit); a 2019-class laptop core is not yet measured.</p>
|
||||
<p>Each hour the chain derives a seed from a locked checkpoint one epoch back, passes it through a ten-minute verifiable delay so no miner can see which program a seed implies before choosing whether to publish a block, and feeds it to a deterministic generator. The generator emits a random integer program built from what graphics cards are uniquely good at: wide parallel integer maths, shuffles between the 32 lanes of a warp, and dependent reads spread over a multi-gigabyte dataset that changes daily, so the program waits on memory latency, not on maths or bandwidth. Measured: an RTX 5090 hashes at 95 GB/s of useful 4-byte loads against 1,638 GB/s of sequential writes (engineering log, the RTX 5090 entries). The memory footprint and instruction count are fixed and only the maths sequence is random, so no hour favours one vendor's cards and nobody gains by grinding the seed. Miners compile the program once per hour. Anyone running a node, a wallet or an exchange checks a hash on an ordinary CPU in under ten milliseconds by simulating one warp, so nobody needs a GPU except to mine. Measured: 0.61 ms per warp on one Apple M5 Max core for class v2 and 2.1 ms for class v3 (the mixer at x8, 5 October 2026, one core at load average 5.5, worst cold unit 2.15 ms), 3.4x the class v2 verifier; the 10 ms gate leaves 4.8x (4.6x on the worst cold unit); a 2019-class laptop core is not yet measured.</p>
|
||||
<p>The hash is a lottery, not a general-purpose cryptographic hash. It has to be unpredictable per nonce, free of any shortcut cheaper than honest evaluation, and free of bias a miner can exploit. It does not need preimage or collision resistance. Open: no analysis of the lottery properties exists yet. It is the first job of the external review in phase 1, and until then the hash is a design claim backed by the measurements below.</p>
|
||||
<div class="tbl"><table>
|
||||
<thead><tr><th>Clock</th><th>What changes</th><th>Miner update needed?</th></tr></thead>
|
||||
<tbody>
|
||||
<tr><td>Every hash</td><td>The 128 dataset addresses depend on the nonce, so every hash reads different memory. The one-bit select inside the maths costs a chip nothing and is not a defence; the random reads are</td><td>No</td></tr>
|
||||
<tr><td>Every hash</td><td>The 128 dataset addresses depend on the nonce, so every hash reads different memory. The one-bit select inside the maths costs a chip nothing and is not a defence; the dependent reads are</td><td>No</td></tr>
|
||||
<tr><td>Every hour</td><td>A new random program</td><td>No, the miner compiles whatever arrives</td></tr>
|
||||
<tr><td>Every day</td><td>A new dataset</td><td>No</td></tr>
|
||||
<tr><td>Every six months</td><td>A new instruction mix and memory pattern drawn by the chain from rules fixed at genesis, and a new family of instructions unlocked from a reserve written at genesis, so the program space widens every era. A schedule change against fixed datapaths and human forks, not a surprise: a programmable chip reads every drawn parameter as firmware</td><td>No</td></tr>
|
||||
<tr><td>Continuously</td><td>The dataset grows on a schedule fixed at genesis, slowly enough that consumer cards keep up for years. A chip is built with fixed memory, so it is on a countdown from the day it ships. Ethereum's growing dataset ran Bitmain's E3 out of memory in 2020 this way, approximate, with nobody doing anything</td><td>No</td></tr>
|
||||
</tbody>
|
||||
</table></div>
|
||||
<p>Three ideas carry the chip resistance. <strong>The hash rewrites itself.</strong> A new program every hour, drawn from the chain. Its memory pattern changes with it. The rules change on a schedule fixed at launch. No release, no vote. These are automatic schedule changes: they defeat a chip wired for one datapath and they need no human fork. Against a chip that stores the dataset every drawn parameter is firmware, and what meets that chip is the latency-shadow work (class v4) and the price per joule (the Horizon lane analysis, 6 October 2026, section 5.4; ledger M32). <strong>It waits on memory, not maths.</strong> Every hash is a chain of random reads into a table too big for a chip to carry. The wait is the same physics for everyone. <strong>Miners hold the switch.</strong> Spare defences are written into the rules, switched off. A miner signal turns one on, at the class-change threshold: miners signal three things at three thresholds, 60 percent of blue blocks over two weeks for a parameter genesis leaves open, 90 percent for an upgrade (new code), and 95 percent with a floor height for a class change. No fork.</p>
|
||||
<p>Three ideas carry the chip resistance. <strong>The hash rewrites itself.</strong> A new program every hour, drawn from the chain. Its memory pattern changes with it. The rules change on a schedule fixed at launch. No release, no vote. These are automatic schedule changes: they defeat a chip wired for one datapath and they need no human fork. Against a chip that stores the dataset every drawn parameter is firmware, and what meets that chip is the latency-shadow work (class v4) and the price per joule (the Horizon lane analysis, 6 October 2026, section 5.4; ledger M32). <strong>It waits on memory, not maths.</strong> Every hash is a chain of random reads into a table too big for a chip to carry. Measured (8 October 2026; lane D’s family harness at the acceptance rule’s own 2^20 sample over 4,900 drawn eras, and the chained-cache pass’s reading of the night before): every hash’s 128 dependent reads land across the whole dataset and the distinct-index floor holds at 0.995 on every accepted program; about half of epochs carry one load site whose address bit at the era’s stride rotation is biased, which prices about 1.6 percent of a hash’s reads to a chip storing half the dataset and nothing to a chip storing all of it; the next class folds the product’s low bits before the rotation, so no era lands a biased bit on an address bit. The wait is the same physics for everyone. <strong>Miners hold the switch.</strong> Spare defences are written into the rules, switched off. A miner signal turns one on, at the class-change threshold: miners signal three things at three thresholds, 60 percent of blue blocks over two weeks for a parameter genesis leaves open, 90 percent for an upgrade (new code), and 95 percent with a floor height for a class change. No fork.</p>
|
||||
<p><strong>The work that waits can grow.</strong> Class v4 adds a block of latency-shadow arithmetic to every hash, about 100,000 integer operations that run while the memory reads are in flight, so a chip that stores the whole dataset still has to pay for a core. That size sits on a ladder fixed at genesis, six rungs from about 100,000 to about 1,000,000 operations, and it moves one rung at a time only when 90 percent of blue blocks in each of seven consecutive days ask for it; it can never move two rungs inside a week and never past a rung the reference verifier cannot check under 10 ms with its sibling thread busy (measured on the build server, 6 October 2026: the first three rungs pass at 8.8, 8.9 and 9.2 ms, the fourth misses by 0.08 ms on a loaded box and stays out until a quiet re-measurement, the two doublings are out at 12.4 and 15.0 ms). What it buys, on the measured cards: against a dataset-storing chip whose core costs what an RTX 5090's does per operation, the chip's per-joule edge falls from 2.1x at the first rung to 1.3x at the third; against a core as good as the one Bitmain claimed for its withdrawn Antminer X9 (about 3x per joule over a desktop CPU, never measured), from 3.4x to 2.8x. What it costs, per rung, is measured too: the Apple tier gives up 3 points of rate at the first step and 6 more at the second, the RTX 5090 nothing until the second; so the miners who pay for a step are the ones who take it (<a href="/ledger#M34">ledger M34</a>).</p>
|
||||
<p><strong>The dataset is the chain.</strong> Class v5 builds each hour's dataset from the chain's own execution state at that hour's reference block: every account, every storage slot and every byte of contract code, hashed under the state root and folded into every item. A card that does not hold the state cannot build the dataset, and a card that builds it from stale state is wrong on every hash from the next refresh on, so a miner must keep following the chain to keep mining. The hash itself does not change, and neither does its speed: measured on an RTX 4090 on 7 October 2026, 63.06 against 63.07 million hashes a second, the hourly rebuild 0.2 ms longer at the devnet's state, a node's check 0.2 to 0.3 ms longer per block. What it buys is a floor under what mining means: a chip that recomputes items instead of storing them must now hold the state too, and a pool miner who today needs nothing but the date needs the state every hour. What it does not buy is stated as plainly: a pool or a farm with one node can ship the state to its cards each hour, 6 KB today and at most 2 GB on a used chain, so the claim is that every mining operation holds and follows the chain, not every card; and against a chip that stores the whole dataset it changes nothing, which is why it sits beside the latency-shadow work, not in its place. It ships switched off, behind the 95 percent class signal with a floor height (<a href="/ledger#M35">ledger M35</a>).</p>
|
||||
<h3 id="chip-model">The chip model</h3>
|
||||
|
|
@ -450,14 +469,14 @@ body.all .pager{display:none}
|
|||
<tr><td>When a stored-dataset chip pays for itself</td><td>at about USD 100 M of market cap in the first two years, not before</td><td>modelled, 7 October 2026</td></tr>
|
||||
<tr><td>The baseline the work started from: the same chip under class v3, without the shadow (the Ethash class)</td><td>5x to 9x (5.1x on GDDR7, 9.2x on eight HBM3 stacks; the Ethash chips of this class reached 2.1x to 4.8x)</td><td>modelled, 6 October 2026; the precedent measured by others, 2020 to 2022; never the launch state</td></tr>
|
||||
</tbody></table></div>
|
||||
<p>What a miner sees from this. Class v4 costs a 5090 145 W more unlocked, 88 W more at a 1,400 MHz core lock and 82 W at the best operating points (class v4 at 1,200 MHz, class v3 at 1,300; the knee is 1,300 MHz on both), for 0.2 percent more rate (measured, 7 October 2026; the 80 W read on 6 October was at the app's tuned cap); an M5 Max 16 W more for 1.5 percent, an RX 9070 XT and an RTX 4070 nothing (measured, 6 October 2026). The ladder that sets how much work rides in the shadow starts at rung 0 at genesis and climbs by miner signal; its third rung is inadmissible today because a server core verifies it in 10.85 ms, over the gate (measured, 7 October 2026). Devnet 3 runs class v4 from its first block (7 October 2026); the first devnet started on class v3 and reaches class v4 by miner signal at a published height. The next test of the model is an internal adversarial pass, not an independent review: three lanes that have never worked on the hash code attack the mixer, the chained cache and the acceptance rule with only what an outsider has (the public kit, the frozen object, the spec, the harnesses) and publish the break or the bound they reach. No outside review has run yet.</p>
|
||||
<p>No hash has stayed free of chips forever. Igneum does not claim to. It states the gain its own model finds, the response takes a week, and both are measured. The model is public: <a href="/bench#counter-asic-2-0-the-numbers">the numbers</a>; the claim is tested by the in-house adversarial pass and the public benchmark. Monero has run on RandomX since 2019 (approximate) with no chip shipped. Bitmain opened Antminer X9 pre-orders on 26 December 2025 for July 2026 delivery, then withdrew the product in mid-May 2026 and refunded buyers before any unit shipped; none has been independently benchmarked. A box with about a 2x per joule edge over the best CPUs, and about 3x over a desktop, was withdrawn rather than face a RandomX re-tune of 1.5x or more. That is the band Igneum’s class v4 model sits in (2.1x to 3.4x over an RTX 5090), and the defence that held was a maintained algorithm with a credible upgrade path, which is what the ladder is.</p>
|
||||
<p>What a miner sees from this. Class v4 costs a 5090 145 W more unlocked, 88 W more at a 1,400 MHz core lock and 82 W at the best operating points (class v4 at 1,200 MHz, class v3 at 1,300; the knee is 1,300 MHz on both), for 0.2 percent more rate (measured, 7 October 2026; the 80 W read on 6 October was at the app's tuned cap); an M5 Max 16 W more for 1.5 percent, an RX 9070 XT and an RTX 4070 nothing (measured, 6 October 2026). The ladder that sets how much work rides in the shadow starts at rung 0 at genesis and climbs by miner signal; its third rung is inadmissible today because a server core verifies it in 10.85 ms, over the gate (measured, 7 October 2026). Devnet 3 runs class v4 from its first block (7 October 2026); the first devnet started on class v3 and reaches class v4 by miner signal at a published height. Classes rotate on findings and at least yearly; a class change is a release activated by block height. Class v5 crosses on Devnet 3 by height; class v6 is the design in progress (opened 8 October 2026), with four layers as its spine: per-era draws of the parameters a release now fixes, a dataset whose size tracks the chain state, scheduled family epochs by height, and the acceptance floor generalised to every era’s draw. The next test of the model is an internal adversarial pass, not an independent review: three lanes that have never worked on the hash code attack the mixer, the chained cache and the acceptance rule with only what an outsider has (the public kit, the frozen object, the spec, the harnesses) and publish the break or the bound they reach. No outside review has run yet.</p>
|
||||
<p>No hash has stayed free of chips forever. Igneum does not claim to. It states the gain its own model finds, the response takes a week, and both are measured. The model is public: <a href="/bench#counter-asic-2-0-the-numbers">the numbers</a>; the claim is tested by the in-house adversarial pass and the public benchmark. Monero has run on RandomX since November 2019; one chip shipped against it, Bitmain’s Antminer X5 (September 2023), a board of RISC-V chips at 1.46x per joule over a desktop CPU, on silicon believed mining privately from about 2021; RandomX v2 was released on 25 March 2026 with its mainnet activation pending. Bitmain opened Antminer X9 pre-orders on 26 December 2025 for July 2026 delivery, then withdrew the product in mid-May 2026 and refunded buyers before any unit shipped; none has been independently benchmarked. A box with about a 2x per joule edge over the best CPUs, and about 3x over a desktop, was withdrawn rather than face a RandomX re-tune of 1.5x or more. That is the band Igneum’s class v4 model sits in (2.1x to 3.4x over an RTX 5090), and the defence that held was a maintained algorithm with a credible upgrade path, which is what the ladder is.</p>
|
||||
<p>One thing takes a person, here and on every chain that exists: writing new code. A chain cannot safely write its own generator, and it cannot safely tell a chip from a wave of honest new cards by hashrate alone. If the design above ever failed, anyone could publish a new generator and miners would switch it on by signalling, as Monero's community can fork. Igneum is built to make that day unlikely, and does not depend on avoiding it.</p>
|
||||
</section>
|
||||
|
||||
<section id="randomx">
|
||||
<h2>Monero's idea, finished for GPUs</h2>
|
||||
<p>RandomX has kept chips off Monero since 2019 (approximate) by making the mining program random, so the hardware that runs it well is the hardware everyone already owns. The one chip announced against it, Bitmain’s Antminer X9 (pre-orders from 26 December 2025 at 1 MH/s and 2,472 W, about USD 5,600), was withdrawn in mid-May 2026 before any unit shipped; RandomX 2.0 shipped on 25 March 2026 (monero-project/monero issue 10270). Igneum takes the same principle to graphics cards and adds what RandomX never had.</p>
|
||||
<p>RandomX has kept Monero on commodity hardware since 2019 by making the mining program random, so the hardware that runs it well is close to the hardware everyone already owns: the one chip that shipped, Bitmain’s Antminer X5 (September 2023), is a board of RISC-V chips at 1.46x per joule over a desktop CPU. The one chip announced against it, Bitmain’s Antminer X9 (pre-orders from 26 December 2025 at 1 MH/s and 2,472 W, about USD 5,600), was withdrawn in mid-May 2026 before any unit shipped; RandomX 2.0 shipped on 25 March 2026 with its mainnet activation pending (monero-project/monero issue 10270). Igneum takes the same principle to graphics cards and adds what RandomX never had.</p>
|
||||
<div class="tbl"><table>
|
||||
<thead><tr><th>Property</th><th>RandomX, Monero</th><th>Igneum</th></tr></thead>
|
||||
<tbody>
|
||||
|
|
@ -468,7 +487,7 @@ body.all .pager{display:none}
|
|||
<tr><td>Changes over time</td><td>None. A fixed design, unchanged for seven years</td><td>A new program every hour, its memory pattern with it; era draws and reserved families on a schedule fixed at genesis. Nobody touches it</td></tr>
|
||||
<tr><td>Seed grinding</td><td>Not applicable, the program comes from the hash input</td><td>Closed by a verifiable delay between seed and program</td></tr>
|
||||
<tr><td>Useful work</td><td>None. Hashing only</td><td>Every NVIDIA card from 8 GB proves; 12 GB and up mine and prove; 24 GB on the stock server (eleven rented cards, RTX 3060 to RTX 5090, 6 October 2026); they sell proofs to other chains. AMD and Apple cards mine, and a prover for them lands when a zkVM ships one</td></tr>
|
||||
<tr><td>Track record</td><td>About seven years without a shipped chip; the one announced, Bitmain’s Antminer X9, was withdrawn in May 2026 before launch</td><td>Zero years. Every number above is measured and logged with the commands that produced it. The specification, reference hash, test vectors and simulators are public now (git.igneum.network/igneum-network/spec). The node, the miner and the wallet follow to the same host as the repository is published</td></tr>
|
||||
<tr><td>Track record</td><td>About seven years with one shipped chip, Bitmain’s Antminer X5 (September 2023), at 1.46x per joule over a desktop CPU; the one announced beyond it, Bitmain’s Antminer X9, was withdrawn in May 2026 with zero units; RandomX v2 released 25 March 2026, activation pending</td><td>Zero years. Every number above is measured and logged with the commands that produced it. The specification, reference hash, test vectors and simulators are public now (git.igneum.network/igneum-network/spec). The node, the miner and the wallet follow to the same host as the repository is published</td></tr>
|
||||
</tbody>
|
||||
</table></div>
|
||||
<p>Measured so far: the same hourly program, generated on an Apple M5 Max, compiled by Apple's Metal and NVIDIA's CUDA on an RTX 5090, produced identical hashes on both, 192 of 192 across two programs. On a 1 GB dataset the 5090 ran at about 228 million hashes a second and the Mac at about 45 million, both bound by random memory access rather than arithmetic. Those are prototype figures, not mining rates. The first prototype dataset was a closed-form function, and a miner could compute items instead of loading them: measured 111x faster that way on the Mac. The 256 MB cache construction replaced it on 3 October 2026. With the cache, computing items on the fly runs 4.8x slower than loading them, measured on the Mac, and the honest rate is unchanged on both vendors. Open: the same shortcut ratio on NVIDIA and on a discrete AMD card, and the time-memory trade-off between the two measured points. Inside the 5090's 96 MB cache the same program ran nearly six times faster, which is why the dataset starts at 2 GB and grows. On 4 October 2026 the live devnet crossed an hourly program change on all three vendors with no pause and no rejected block: a Mac at 26.7 million hashes a second, an RTX 5090 at 123 million and an integrated AMD chip at 2.7 million, every hash doing 128 distinct reads of the memory-hard dataset.</p>
|
||||
|
|
@ -807,7 +826,7 @@ body.all .pager{display:none}
|
|||
<p>Here are the limits, stated before anyone else states them.</p>
|
||||
<ul>
|
||||
<li><strong>A proof in seconds.</strong> Not at launch. Proving a full block today needs a cluster of 100 to 200 consumer GPUs, approximate, so Igneum launches with proofs within about a minute and tightens as hardware improves. Users still see their transaction land in one second.</li>
|
||||
<li><strong>A chip is impossible.</strong> No. A chip wired for one program is a bad bet, because the program moves before it ships. A programmable chip is not stopped by the moving target: everything it needs is public at genesis and every drawn parameter is firmware to it (an address permute, a rotator, an immediate table), so the defence against it is the latency-shadow work (class v4) and the price per joule, not the schedule (the Horizon lane analysis, 6 October 2026, section 5.4; ledger M32). At launch the strongest chip in our public model reaches 2.1x per joule against an RTX 5090 with a core as good as a GPU lane and 3.4x with one three times better, under class v4 from the first block: a memory-controller chip that stores the whole dataset and carries a GPU-class datapath beside its memory for the 100,000 ops per hash in the shadow, the range running from a chip core as costly per operation as a GPU lane (k = 1, modelled on the 5090’s measured watts at its knee, 7 October 2026) to a core three times better per operation (k about 0.33); the withdrawn Antminer X9’s claimed figure is a ratio against a CPU core, not a GPU lane, so it does not stand for a chip core against us; the ladder’s second rung takes that bracket to about 2.8x (modelled, 7 October 2026). Class v5 then makes the dataset the chain’s own state, so a chip that stores it or recomputes it is wrong on every item (designed, 7 October 2026). The baseline the work started from, never the launch state: without class v4 the same stored-dataset chip would reach 1.2x per chip and 5x to 9x per joule in our model (6 October 2026); the Ethash chips of this class reached 2.1x to 4.8x (Linzhi Phoenix 2020, Jasminer X4 2021, Antminer E9 2022). The strongest recompute chip we can price, holding the whole 256 MiB cache on-die, reaches under 1x per chip against an RTX 5090 (the published model, 5 October 2026: 0.92x per unit of silicon with a 3x fixed-function allowance, approximate). Sources: the chip model analysis (6 October 2026); the ASIC history’s Ethash rows; Counter ASIC 3.0 item 8 (the chip’s per-joule edge over the RTX 5090 falls from 5.6x to 2.1x on GDDR7 at k = 1 and to 3.4x at a core three times better, the 5090 at 0.2% less rate; gates G1 to G6 passed, 6 October 2026). No hash has stayed free of chips forever; Igneum does not claim to. Monero’s RandomX has held for about seven years; the one chip announced against it, Bitmain’s Antminer X9, was withdrawn in mid-May 2026 before any unit shipped, its claimed core (k about 0.33) never measured. That record says nothing about the price of a chip with the 256 MB cache on its die; that price is a cost model, not a measurement.</li>
|
||||
<li><strong>A chip is impossible.</strong> No. A chip wired for one program is a bad bet, because the program moves before it ships. A programmable chip is not stopped by the moving target: everything it needs is public at genesis and every drawn parameter is firmware to it (an address permute, a rotator, an immediate table), so the defence against it is the latency-shadow work (class v4) and the price per joule, not the schedule (the Horizon lane analysis, 6 October 2026, section 5.4; ledger M32). At launch the strongest chip in our public model reaches 2.1x per joule against an RTX 5090 with a core as good as a GPU lane and 3.4x with one three times better, under class v4 from the first block: a memory-controller chip that stores the whole dataset and carries a GPU-class datapath beside its memory for the 100,000 ops per hash in the shadow, the range running from a chip core as costly per operation as a GPU lane (k = 1, modelled on the 5090’s measured watts at its knee, 7 October 2026) to a core three times better per operation (k about 0.33); the withdrawn Antminer X9’s claimed figure is a ratio against a CPU core, not a GPU lane, so it does not stand for a chip core against us; the ladder’s second rung takes that bracket to about 2.8x (modelled, 7 October 2026). Class v5 then makes the dataset the chain’s own state, so a chip that stores it or recomputes it is wrong on every item (designed, 7 October 2026). The baseline the work started from, never the launch state: without class v4 the same stored-dataset chip would reach 1.2x per chip and 5x to 9x per joule in our model (6 October 2026); the Ethash chips of this class reached 2.1x to 4.8x (Linzhi Phoenix 2020, Jasminer X4 2021, Antminer E9 2022). The strongest recompute chip we can price, holding the whole 256 MiB cache on-die, reaches under 1x per chip against an RTX 5090 (the published model, 5 October 2026: 0.92x per unit of silicon with a 3x fixed-function allowance, approximate). Sources: the chip model analysis (6 October 2026); the ASIC history’s Ethash rows; Counter ASIC 3.0 item 8 (the chip’s per-joule edge over the RTX 5090 falls from 5.6x to 2.1x on GDDR7 at k = 1 and to 3.4x at a core three times better, the 5090 at 0.2% less rate; gates G1 to G6 passed, 6 October 2026). No hash has stayed free of chips forever; Igneum does not claim to. Monero’s RandomX has held its miners on commodity hardware for about seven years: one chip shipped against it, Bitmain’s Antminer X5 (September 2023), at 1.46x per joule over a desktop CPU; the one announced beyond it, the Antminer X9, was withdrawn in mid-May 2026 before any unit shipped, its claimed core (k about 0.33) never measured; RandomX v2 was released on 25 March 2026 with its activation pending. That record says nothing about the price of a chip with the 256 MB cache on its die; that price is a cost model, not a measurement.</li>
|
||||
<li><strong>A guaranteed income floor.</strong> No. External proving is a small market today. Igneum's miners' electricity cost in it is close to power, but the price they must charge is the subsidy they forgo, which falls as one over network hash: an edge at scale and nothing more.</li>
|
||||
<li><strong>A memory-hard prototype on every vendor.</strong> Not yet. The 256 MB cache closed the shortcut on Apple silicon (computing items runs 4.8x slower than loading them, measured 3 October 2026). The same ratio on NVIDIA and on a discrete AMD card is Open.</li>
|
||||
<li><strong>Finality in the first month.</strong> No. No checkpoint locks until the 30-day window has 30 days of history. The first month of mainnet is proof of work with a 12-hour depth, and the text above says so wherever a day count appears.</li>
|
||||
|
|
@ -848,7 +867,7 @@ body.all .pager{display:none}
|
|||
<a href="/wallet">The wallet</a>
|
||||
<a href="/miners">GPU bench table</a>
|
||||
<a href="/dev-fee">The dev fee</a>
|
||||
<a href="/faucet">Testnet faucet</a>
|
||||
<a href="/faucet">Devnet faucet</a>
|
||||
<a href="/metamask">Add Igneum to MetaMask</a>
|
||||
</div></div>
|
||||
<div class="footer-column"><h4>Read</h4><div>
|
||||
|
|
@ -863,6 +882,9 @@ body.all .pager{display:none}
|
|||
<div class="footer-column"><h4>Explore</h4><div>
|
||||
<a href="/live">Live devnet</a>
|
||||
<a href="/explorer">Explorer</a>
|
||||
<a href="/build">Build on Igneum</a>
|
||||
<a href="/swap">Swap</a>
|
||||
<a href="/grants">Grants</a>
|
||||
<a href="/journey">Journey</a>
|
||||
<a href="/download">Downloads: devnet build</a>
|
||||
<a href="https://discord.gg/igneum" target="_blank" rel="noopener">Community Discord</a>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
/* Igneum DAG / Ember 2.0 (the EMBER 02 renderer pack, 7 Oct 2026). THE SHARED SOURCE: scene/live-dag.js; site/live-dag.js and
|
||||
* app/igneum-app/ui/live-dag.js are byte-equal copies written by tools/scene/sync.mjs (the gate refuses a drifted copy). Edit here.
|
||||
* 2.0.7 (8 Oct 2026): a chain block whose plan is known (block.number set, carried as plan on the normalised block) and empty reads
|
||||
* "no shards in this block"; the loading and late sentences stay for a plan the observer has not read; the fixed sentence of 2.0.5 is gone.
|
||||
* 2.0.6 (7 Oct 2026): IgneumDag.shardWords(block, nowMs) is the one shard sentence (tooltip, /live inspector, app inspector); the
|
||||
* empty case reads from the block's facts (loading, excluded, not yet ordered, off the chain) instead of one fixed sentence.
|
||||
* 2.0.5 (key-22, 7 Oct 2026): IgneumDag.legend({mine}) and renderLegend(el,{mine}) are the one key both pages render; the app's
|
||||
|
|
@ -46,14 +48,14 @@
|
|||
function cloneBlock(b) {
|
||||
return {hash:b.hash,ts:b.ts,blue_score:b.blue_score,blue:b.blue_score,daa:b.daa,
|
||||
parents:b.parents.slice(),chain:b.chain,color:b.color,miner:b.miner,locked:b.locked,
|
||||
final:b.final,proven:b.proven,shards:b.shards.map(function(s){return {state:s.state};})};
|
||||
final:b.final,proven:b.proven,plan:b.plan,shards:b.shards.map(function(s){return {state:s.state};})};
|
||||
}
|
||||
function normalize(b) {
|
||||
if (!b || typeof b.hash !== 'string' || !b.hash.length || b.hash.length>256 || !finite(b.ts) || b.ts<0) return null;
|
||||
return {hash:b.hash,ts:b.ts,blue_score:num(b.blue_score),daa:num(b.daa),
|
||||
parents:Array.isArray(b.parents)?Array.from(new Set(b.parents.filter(function(p){return typeof p==='string' && p!==b.hash;}))).slice(0,128):[],
|
||||
chain:b.chain===true,color:['blue','red','pending'].includes(b.color)?b.color:'pending',
|
||||
miner:typeof b.miner==='string'?b.miner.slice(0,256):'unknown',locked:b.locked===true,final:b.final===true,proven:b.proven===true,
|
||||
miner:typeof b.miner==='string'?b.miner.slice(0,256):'unknown',locked:b.locked===true,final:b.final===true,proven:b.proven===true,plan:finite(b.number),
|
||||
shards:Array.isArray(b.shards)?b.shards.slice(0,256).map(function(s){return {state:s && ['planned','proving','verified','paid'].includes(s.state)?s.state:'unknown'};}):[]};
|
||||
}
|
||||
function mount(canvas, opts) {
|
||||
|
|
@ -393,6 +395,7 @@
|
|||
if(b.color==='red')return {summary:'excluded, nothing to prove',items:[],state:'excluded'};
|
||||
if(b.color!=='blue')return {summary:'not yet ordered',items:[],state:'pending'};
|
||||
if(!b.chain)return {summary:'off the selected chain, no shards planned',items:[],state:'none'};
|
||||
if(b.plan===true)return {summary:'no shards in this block',items:[],state:'none'};
|
||||
if(age<10)return {summary:'shard plan loading',items:[],state:'loading'};
|
||||
return {summary:'no shard plan after '+ageWord(age),items:[],state:'late'};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -126,7 +126,7 @@
|
|||
.mstats .mv b{font:700 clamp(21px,2.2vw,29px)/1.1 var(--display);color:var(--bone);letter-spacing:-.04em}
|
||||
.mstats .mv b.own{color:var(--molten-text)}.mstats .mv b.dim{color:var(--ash)}
|
||||
.mstats .mv small{font:400 11px/1.4 var(--f-mono);color:var(--ash)}
|
||||
.mstats .mf{font:400 11px/1.4 var(--f-mono);color:var(--ash);overflow-wrap:anywhere}
|
||||
.mstats .mf{font:400 11px/1.4 var(--f-mono);color:var(--ash);overflow-wrap:anywhere}.mstats .mf.bad{color:var(--ember-text)}
|
||||
@media (max-width:900px){.mstats{grid-template-columns:repeat(2,minmax(0,1fr))}.mstats>div:nth-child(2){border-right:0}.mstats>div:nth-child(-n+2){border-bottom:var(--hair)}}
|
||||
.tabs{display:inline-flex;border:var(--hair);border-radius:6px;padding:3px;gap:2px;background:var(--graphite)}
|
||||
.tab{background:transparent;border:0;color:var(--ash);font:400 12px/1.2 var(--f-sans);padding:6px 10px;border-radius:4px;cursor:pointer}
|
||||
|
|
@ -227,6 +227,7 @@ details.tablebar summary{display:flex;align-items:center}
|
|||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-mine" data-group="mine" aria-expanded="false" aria-controls="nav-panel-mine" aria-haspopup="true">Mine<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-network" data-group="network" data-active aria-expanded="false" aria-controls="nav-panel-network" aria-haspopup="true">Network<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-learn" data-group="learn" aria-expanded="false" aria-controls="nav-panel-learn" aria-haspopup="true">Learn<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-build" data-group="build" aria-expanded="false" aria-controls="nav-panel-build" aria-haspopup="true">Build<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
</div>
|
||||
<div class="nav-controls">
|
||||
<button class="btn icon-btn" type="button" data-theme-toggle aria-label="Switch to light theme"><svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><circle cx="12" cy="12" r="4"/><path d="M12 2v2m0 16v2M2 12h2m16 0h2M5 5l1 1m12 12 1 1M5 19l1-1M18 6l1-1"/></svg></button>
|
||||
|
|
@ -244,7 +245,6 @@ details.tablebar summary{display:flex;align-items:center}
|
|||
<a href="/wallet" data-nav="wallet"><b>The wallet</b><span>Your coins. Final means final.</span></a>
|
||||
<a href="/miners" data-nav="miners"><b>GPU bench table</b><span>Measured rates, card by card.</span></a>
|
||||
<a href="/dev-fee" data-nav="dev-fee"><b>The dev fee</b><span>The optional one, in full view, off with one flag.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Testnet faucet</b><span>Test coin for an address, once a day.</span></a>
|
||||
<a href="/metamask" data-nav="metamask"><b>Add to MetaMask</b><span>Igneum as a network in your wallet.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -255,6 +255,9 @@ details.tablebar summary{display:flex;align-items:center}
|
|||
<a href="/journey" data-nav="journey"><b>The journey</b><span>Six phases, four gates, the log behind them.</span></a>
|
||||
<a href="/bench" data-nav="bench"><b>Engineering log</b><span>Every measurement, with the commands that made it.</span></a>
|
||||
<a href="/evidence" data-nav="evidence"><b>Evidence</b><span>Every claim and how far it is tested.</span></a>
|
||||
<a href="/light" data-nav="light"><b>Light wallet</b><span>A balance your browser proves, trusting no node.</span></a>
|
||||
<a href="/receipt" data-nav="receipt"><b>Payment receipt</b><span>A receipt any third party re-verifies offline.</span></a>
|
||||
<a href="/oracle" data-nav="oracle"><b>State oracle on Sepolia</b><span>Devnet 3 balances read from another chain.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-panel" id="nav-panel-learn" data-group="learn" role="region" aria-labelledby="nav-btn-learn" hidden>
|
||||
|
|
@ -267,6 +270,14 @@ details.tablebar summary{display:flex;align-items:center}
|
|||
<a href="/provenance" data-nav="provenance"><b>Built on the shoulders</b><span>Every borrowed part, credited.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-panel" id="nav-panel-build" data-group="build" role="region" aria-labelledby="nav-btn-build" hidden>
|
||||
<div class="panel-list">
|
||||
<a href="/build" data-nav="build"><b>Build on Igneum</b><span>Chain ids, RPC, a contract in five minutes.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Devnet faucet</b><span>10 IGN of devnet coin, once a day.</span></a>
|
||||
<a href="/swap" data-nav="swap"><b>Swap</b><span>Test tokens on Devnet 3; every swap is a proven block.</span></a>
|
||||
<a href="/grants" data-nav="grants"><b>Grants</b><span>Tooling, apps, infrastructure, research.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-sheet" id="nav-sheet" role="dialog" aria-modal="true" aria-label="Menu" hidden>
|
||||
|
|
@ -278,7 +289,6 @@ details.tablebar summary{display:flex;align-items:center}
|
|||
<a href="/wallet" data-nav="wallet"><b>The wallet</b><span>Your coins. Final means final.</span></a>
|
||||
<a href="/miners" data-nav="miners"><b>GPU bench table</b><span>Measured rates, card by card.</span></a>
|
||||
<a href="/dev-fee" data-nav="dev-fee"><b>The dev fee</b><span>The optional one, in full view, off with one flag.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Testnet faucet</b><span>Test coin for an address, once a day.</span></a>
|
||||
<a href="/metamask" data-nav="metamask"><b>Add to MetaMask</b><span>Igneum as a network in your wallet.</span></a>
|
||||
</div>
|
||||
<div class="sheet-group"><div class="sheet-head">Network</div>
|
||||
|
|
@ -287,6 +297,9 @@ details.tablebar summary{display:flex;align-items:center}
|
|||
<a href="/journey" data-nav="journey"><b>The journey</b><span>Six phases, four gates, the log behind them.</span></a>
|
||||
<a href="/bench" data-nav="bench"><b>Engineering log</b><span>Every measurement, with the commands that made it.</span></a>
|
||||
<a href="/evidence" data-nav="evidence"><b>Evidence</b><span>Every claim and how far it is tested.</span></a>
|
||||
<a href="/light" data-nav="light"><b>Light wallet</b><span>A balance your browser proves, trusting no node.</span></a>
|
||||
<a href="/receipt" data-nav="receipt"><b>Payment receipt</b><span>A receipt any third party re-verifies offline.</span></a>
|
||||
<a href="/oracle" data-nav="oracle"><b>State oracle on Sepolia</b><span>Devnet 3 balances read from another chain.</span></a>
|
||||
</div>
|
||||
<div class="sheet-group"><div class="sheet-head">Learn</div>
|
||||
<a href="/litepaper" data-nav="litepaper"><b>Litepaper</b><span>The design, as published.</span></a>
|
||||
|
|
@ -296,6 +309,12 @@ details.tablebar summary{display:flex;align-items:center}
|
|||
<a href="/randomx" data-nav="randomx"><b>Igneum vs RandomX</b><span>What was kept and what was rebuilt for GPUs.</span></a>
|
||||
<a href="/provenance" data-nav="provenance"><b>Built on the shoulders</b><span>Every borrowed part, credited.</span></a>
|
||||
</div>
|
||||
<div class="sheet-group"><div class="sheet-head">Build</div>
|
||||
<a href="/build" data-nav="build"><b>Build on Igneum</b><span>Chain ids, RPC, a contract in five minutes.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Devnet faucet</b><span>10 IGN of devnet coin, once a day.</span></a>
|
||||
<a href="/swap" data-nav="swap"><b>Swap</b><span>Test tokens on Devnet 3; every swap is a proven block.</span></a>
|
||||
<a href="/grants" data-nav="grants"><b>Grants</b><span>Tooling, apps, infrastructure, research.</span></a>
|
||||
</div>
|
||||
<div class="sheet-foot">
|
||||
<a href="/download" class="btn primary big" data-nav="download">Download</a>
|
||||
<div class="sheet-social"><a href="https://discord.gg/igneum" target="_blank" rel="noopener">Discord</a><a href="https://git.igneum.network/igneum-network/spec" target="_blank" rel="noopener">Source</a><a href="https://www.reddit.com/user/Igneum_network/" target="_blank" rel="noopener">Reddit</a></div>
|
||||
|
|
@ -376,7 +395,7 @@ details.tablebar summary{display:flex;align-items:center}
|
|||
<section class="panel" aria-label="The block graph">
|
||||
<div class="mstats">
|
||||
<div><div class="mk">Blocks in window</div><div class="mv"><b id="m-blocks">0</b><small id="m-win">last 90 s</small></div><div class="mf" id="m-keys">waiting for the observer</div></div>
|
||||
<div><div class="mk">Proven blocks</div><div class="mv"><b id="m-proven">0</b><small id="m-proven-pct">reading</small></div><div class="mf">of the last 10 minutes, every shard verified or paid</div></div>
|
||||
<div><div class="mk">Proven blocks</div><div class="mv"><b id="m-proven">0</b><small id="m-proven-pct">reading</small></div><div class="mf" id="m-proven-note">of the last 10 minutes, every shard verified or paid</div></div>
|
||||
<div><div class="mk">Latest checkpoint</div><div class="mv"><b id="m-cp">None</b><small id="m-cp-w"></small></div><div class="mf" id="m-cp-note">no checkpoint in the reply</div></div>
|
||||
</div>
|
||||
<div class="toolbar">
|
||||
|
|
@ -510,7 +529,7 @@ details.tablebar summary{display:flex;align-items:center}
|
|||
<a href="/wallet">The wallet</a>
|
||||
<a href="/miners">GPU bench table</a>
|
||||
<a href="/dev-fee">The dev fee</a>
|
||||
<a href="/faucet">Testnet faucet</a>
|
||||
<a href="/faucet">Devnet faucet</a>
|
||||
<a href="/metamask">Add Igneum to MetaMask</a>
|
||||
</div></div>
|
||||
<div class="footer-column"><h4>Read</h4><div>
|
||||
|
|
@ -525,6 +544,9 @@ details.tablebar summary{display:flex;align-items:center}
|
|||
<div class="footer-column"><h4>Explore</h4><div>
|
||||
<a href="/live">Live devnet</a>
|
||||
<a href="/explorer">Explorer</a>
|
||||
<a href="/build">Build on Igneum</a>
|
||||
<a href="/swap">Swap</a>
|
||||
<a href="/grants">Grants</a>
|
||||
<a href="/journey">Journey</a>
|
||||
<a href="/download">Downloads: devnet build</a>
|
||||
<a href="https://discord.gg/igneum" target="_blank" rel="noopener">Community Discord</a>
|
||||
|
|
@ -622,7 +644,7 @@ details.tablebar summary{display:flex;align-items:center}
|
|||
$('i-hash').textContent=b.hash+(b.number?' · #'+fmtN(b.number):'');
|
||||
var sh=b.shards||[],done=sh.filter(function(x){return x.state==='verified'||x.state==='paid';}).length;
|
||||
var sw=window.IgneumDag&&IgneumDag.shardWords?IgneumDag.shardWords(b,Date.now()):{summary:sh.length?'':'no shard plan',items:sh.map(function(x){return {word:x.state};})},cap=function(s){return s.replace(/^./,function(c){return c.toUpperCase();});};
|
||||
$('i-shard-count').textContent=sh.length?done+' / '+sh.length+' complete':sw.summary;$('i-track').innerHTML=sh.map(function(x){return '<i class="'+esc(x.state)+'"></i>';}).join('');
|
||||
$('i-shard-count').textContent=(sh.length?done+' / '+sh.length+' complete':sw.summary)+(lastD&&lastD.proving&&lastD.proving.stale?' \u00b7 feed stale':'');$('i-track').innerHTML=sh.map(function(x){return '<i class="'+esc(x.state)+'"></i>';}).join('');
|
||||
$('i-shards').innerHTML=sh.length?sh.map(function(x,i){return '<li class="'+esc(x.state)+'"><span>Shard '+String(i+1).padStart(2,'0')+'</span><span>'+esc(cap(sw.items[i]?sw.items[i].word:x.state))+'</span></li>';}).join(''):'<li class="muted">'+esc(cap(sw.summary))+'.</li>';
|
||||
$('i-incl').textContent=(b.color==='blue'?'Included':b.color==='red'?'Excluded':'Pending')+(b.chain?' / selected chain':'');
|
||||
$('i-miner').textContent=b.miner+(mineB?' (you)':'');$('i-blue').textContent=fmtN(b.blue_score);$('i-daa').textContent=fmtN(b.daa);
|
||||
|
|
@ -655,7 +677,9 @@ details.tablebar summary{display:flex;align-items:center}
|
|||
function feed(d){if(!dag)return;dag.push(d);}
|
||||
if(window.IgneumDag)mountDag();else{var ms=document.querySelector('script[src="/live-dag.js"]');if(ms)ms.addEventListener('load',mountDag);}
|
||||
// the Proven tile: a 600 s window of its own, read every 10 s, so the number is never zero by the proof lag alone
|
||||
function provenTile(){fetch('/api/live?window=600&summary=1',{cache:'no-store'}).then(function(r){return r.json();}).then(function(d){if(!d||!d.ok)return;$('m-proven').textContent=fmtN(d.proven);$('m-proven-pct').textContent=d.chain?Math.round(d.proven/d.chain*100)+'% of '+fmtN(d.chain)+' chain blocks':'no chain blocks';}).catch(function(){});}
|
||||
function provenTile(){fetch('/api/live?window=600&summary=1',{cache:'no-store'}).then(function(r){return r.json();}).then(function(d){if(!d||!d.ok)return;$('m-proven').textContent=fmtN(d.proven);$('m-proven-pct').textContent=d.chain?Math.round(d.proven/d.chain*100)+'% of '+fmtN(d.chain)+' chain blocks':'no chain blocks';
|
||||
// the proving feed's own health (8 October 2026, /api/live proving.stale): a frozen paid total never reads as fresh
|
||||
var pvh=d.proving||{},pn=$('m-proven-note');if(pn){pn.textContent=pvh.supported===false?'proving feed off: '+(pvh.reason||'no proving layer reported'):pvh.stale?'proving feed stale: '+(pvh.stale_reason||'the observer\u2019s node is not crediting shards'):'of the last 10 minutes, every shard verified or paid'+(pvh.last_change_at?' \u00b7 last credit '+rel(Date.now()-new Date(pvh.last_change_at).getTime()):'');pn.classList.toggle('bad',!!(pvh.stale||pvh.supported===false));}}).catch(function(){});}
|
||||
provenTile();setInterval(provenTile,10000);
|
||||
if(!window.IgneumProof){var ps=document.querySelector('script[src="/proof-core.js"]');if(ps)ps.addEventListener('load',function(){if(dag&&!proof)proof=IgneumProof.mount($('proof'));});}
|
||||
document.querySelectorAll('.tab[data-filter]').forEach(function(t){t.addEventListener('click',function(){document.querySelectorAll('.tab[data-filter]').forEach(function(x){x.classList.toggle('on',x===t);x.setAttribute('aria-pressed',x===t?'true':'false');});if(dag)dag.setFilter(t.getAttribute('data-filter'));});});
|
||||
|
|
|
|||
|
|
@ -88,6 +88,7 @@ ol{margin:0 0 14px;padding-left:22px}li{margin-bottom:6px}
|
|||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-mine" data-group="mine" data-active aria-expanded="false" aria-controls="nav-panel-mine" aria-haspopup="true">Mine<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-network" data-group="network" aria-expanded="false" aria-controls="nav-panel-network" aria-haspopup="true">Network<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-learn" data-group="learn" aria-expanded="false" aria-controls="nav-panel-learn" aria-haspopup="true">Learn<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-build" data-group="build" aria-expanded="false" aria-controls="nav-panel-build" aria-haspopup="true">Build<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
</div>
|
||||
<div class="nav-controls">
|
||||
<button class="btn icon-btn" type="button" data-theme-toggle aria-label="Switch to light theme"><svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><circle cx="12" cy="12" r="4"/><path d="M12 2v2m0 16v2M2 12h2m16 0h2M5 5l1 1m12 12 1 1M5 19l1-1M18 6l1-1"/></svg></button>
|
||||
|
|
@ -105,7 +106,6 @@ ol{margin:0 0 14px;padding-left:22px}li{margin-bottom:6px}
|
|||
<a href="/wallet" data-nav="wallet"><b>The wallet</b><span>Your coins. Final means final.</span></a>
|
||||
<a href="/miners" data-nav="miners"><b>GPU bench table</b><span>Measured rates, card by card.</span></a>
|
||||
<a href="/dev-fee" data-nav="dev-fee"><b>The dev fee</b><span>The optional one, in full view, off with one flag.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Testnet faucet</b><span>Test coin for an address, once a day.</span></a>
|
||||
<a href="/metamask" data-nav="metamask" aria-current="page"><b>Add to MetaMask</b><span>Igneum as a network in your wallet.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -116,6 +116,9 @@ ol{margin:0 0 14px;padding-left:22px}li{margin-bottom:6px}
|
|||
<a href="/journey" data-nav="journey"><b>The journey</b><span>Six phases, four gates, the log behind them.</span></a>
|
||||
<a href="/bench" data-nav="bench"><b>Engineering log</b><span>Every measurement, with the commands that made it.</span></a>
|
||||
<a href="/evidence" data-nav="evidence"><b>Evidence</b><span>Every claim and how far it is tested.</span></a>
|
||||
<a href="/light" data-nav="light"><b>Light wallet</b><span>A balance your browser proves, trusting no node.</span></a>
|
||||
<a href="/receipt" data-nav="receipt"><b>Payment receipt</b><span>A receipt any third party re-verifies offline.</span></a>
|
||||
<a href="/oracle" data-nav="oracle"><b>State oracle on Sepolia</b><span>Devnet 3 balances read from another chain.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-panel" id="nav-panel-learn" data-group="learn" role="region" aria-labelledby="nav-btn-learn" hidden>
|
||||
|
|
@ -128,6 +131,14 @@ ol{margin:0 0 14px;padding-left:22px}li{margin-bottom:6px}
|
|||
<a href="/provenance" data-nav="provenance"><b>Built on the shoulders</b><span>Every borrowed part, credited.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-panel" id="nav-panel-build" data-group="build" role="region" aria-labelledby="nav-btn-build" hidden>
|
||||
<div class="panel-list">
|
||||
<a href="/build" data-nav="build"><b>Build on Igneum</b><span>Chain ids, RPC, a contract in five minutes.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Devnet faucet</b><span>10 IGN of devnet coin, once a day.</span></a>
|
||||
<a href="/swap" data-nav="swap"><b>Swap</b><span>Test tokens on Devnet 3; every swap is a proven block.</span></a>
|
||||
<a href="/grants" data-nav="grants"><b>Grants</b><span>Tooling, apps, infrastructure, research.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-sheet" id="nav-sheet" role="dialog" aria-modal="true" aria-label="Menu" hidden>
|
||||
|
|
@ -139,7 +150,6 @@ ol{margin:0 0 14px;padding-left:22px}li{margin-bottom:6px}
|
|||
<a href="/wallet" data-nav="wallet"><b>The wallet</b><span>Your coins. Final means final.</span></a>
|
||||
<a href="/miners" data-nav="miners"><b>GPU bench table</b><span>Measured rates, card by card.</span></a>
|
||||
<a href="/dev-fee" data-nav="dev-fee"><b>The dev fee</b><span>The optional one, in full view, off with one flag.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Testnet faucet</b><span>Test coin for an address, once a day.</span></a>
|
||||
<a href="/metamask" data-nav="metamask" aria-current="page"><b>Add to MetaMask</b><span>Igneum as a network in your wallet.</span></a>
|
||||
</div>
|
||||
<div class="sheet-group"><div class="sheet-head">Network</div>
|
||||
|
|
@ -148,6 +158,9 @@ ol{margin:0 0 14px;padding-left:22px}li{margin-bottom:6px}
|
|||
<a href="/journey" data-nav="journey"><b>The journey</b><span>Six phases, four gates, the log behind them.</span></a>
|
||||
<a href="/bench" data-nav="bench"><b>Engineering log</b><span>Every measurement, with the commands that made it.</span></a>
|
||||
<a href="/evidence" data-nav="evidence"><b>Evidence</b><span>Every claim and how far it is tested.</span></a>
|
||||
<a href="/light" data-nav="light"><b>Light wallet</b><span>A balance your browser proves, trusting no node.</span></a>
|
||||
<a href="/receipt" data-nav="receipt"><b>Payment receipt</b><span>A receipt any third party re-verifies offline.</span></a>
|
||||
<a href="/oracle" data-nav="oracle"><b>State oracle on Sepolia</b><span>Devnet 3 balances read from another chain.</span></a>
|
||||
</div>
|
||||
<div class="sheet-group"><div class="sheet-head">Learn</div>
|
||||
<a href="/litepaper" data-nav="litepaper"><b>Litepaper</b><span>The design, as published.</span></a>
|
||||
|
|
@ -157,6 +170,12 @@ ol{margin:0 0 14px;padding-left:22px}li{margin-bottom:6px}
|
|||
<a href="/randomx" data-nav="randomx"><b>Igneum vs RandomX</b><span>What was kept and what was rebuilt for GPUs.</span></a>
|
||||
<a href="/provenance" data-nav="provenance"><b>Built on the shoulders</b><span>Every borrowed part, credited.</span></a>
|
||||
</div>
|
||||
<div class="sheet-group"><div class="sheet-head">Build</div>
|
||||
<a href="/build" data-nav="build"><b>Build on Igneum</b><span>Chain ids, RPC, a contract in five minutes.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Devnet faucet</b><span>10 IGN of devnet coin, once a day.</span></a>
|
||||
<a href="/swap" data-nav="swap"><b>Swap</b><span>Test tokens on Devnet 3; every swap is a proven block.</span></a>
|
||||
<a href="/grants" data-nav="grants"><b>Grants</b><span>Tooling, apps, infrastructure, research.</span></a>
|
||||
</div>
|
||||
<div class="sheet-foot">
|
||||
<a href="/download" class="btn primary big" data-nav="download">Download</a>
|
||||
<div class="sheet-social"><a href="https://discord.gg/igneum" target="_blank" rel="noopener">Discord</a><a href="https://git.igneum.network/igneum-network/spec" target="_blank" rel="noopener">Source</a><a href="https://www.reddit.com/user/Igneum_network/" target="_blank" rel="noopener">Reddit</a></div>
|
||||
|
|
@ -301,7 +320,7 @@ ol{margin:0 0 14px;padding-left:22px}li{margin-bottom:6px}
|
|||
<a href="/wallet">The wallet</a>
|
||||
<a href="/miners">GPU bench table</a>
|
||||
<a href="/dev-fee">The dev fee</a>
|
||||
<a href="/faucet">Testnet faucet</a>
|
||||
<a href="/faucet">Devnet faucet</a>
|
||||
<a href="/metamask">Add Igneum to MetaMask</a>
|
||||
</div></div>
|
||||
<div class="footer-column"><h4>Read</h4><div>
|
||||
|
|
@ -316,6 +335,9 @@ ol{margin:0 0 14px;padding-left:22px}li{margin-bottom:6px}
|
|||
<div class="footer-column"><h4>Explore</h4><div>
|
||||
<a href="/live">Live devnet</a>
|
||||
<a href="/explorer">Explorer</a>
|
||||
<a href="/build">Build on Igneum</a>
|
||||
<a href="/swap">Swap</a>
|
||||
<a href="/grants">Grants</a>
|
||||
<a href="/journey">Journey</a>
|
||||
<a href="/download">Downloads: devnet build</a>
|
||||
<a href="https://discord.gg/igneum" target="_blank" rel="noopener">Community Discord</a>
|
||||
|
|
|
|||
|
|
@ -259,7 +259,7 @@
|
|||
"date": "2026-10-07",
|
||||
"source": "bench log: 7 October 2026, the Intel Arc B580 (eGPU equals slot)",
|
||||
"by": "measured by the team",
|
||||
"note": "the same rate in the Thunderbolt enclosure and the slot; watts not read on this run",
|
||||
"note": "the same rate in the Thunderbolt enclosure and the slot; watts not read on this run. Re-read 8 October 2026: the installed 0.3.21 OpenCL worker on this card passes its own self-test with the devnet pack (96 of 96 vector lanes) and mined 54 CPU-re-checked blocks at 10.58 MH/s, so the row stands; a kit build from a branch without the Intel rotate-fold rewrite failed its self-test on this card the same morning, a build fault and not an Arc result",
|
||||
"v4_cost": "0.1 percent of rate, measured 7 October 2026",
|
||||
"tuned": "stock, bench only",
|
||||
"driver_os": "Intel driver, Windows 11",
|
||||
|
|
@ -281,7 +281,7 @@
|
|||
"date": "2026-10-07",
|
||||
"source": "bench log: 7 October 2026, every rentable card on the hash (the fleet's sweep, a rented card)",
|
||||
"by": "measured by the fleet",
|
||||
"note": "424.0 W maximum; 98 percent of its random-read ceiling like the 5090; 1.78x the 5090's hash at 1.15x the tuned 5090's hash per watt and a third of the hash per rented dollar",
|
||||
"note": "424.0 W maximum; 98 percent of its random-read ceiling like the 5090; 1.78x the 5090's hash at 1.15x the tuned 5090's hash per watt and a third of the hash per rented dollar. Watts are class v3 (read 8 October 2026, 11:4x UK): the fleet's bench pack was the class v3 program (program_class v3, generator 3, load_class mx8-erad810f22d), so this row's watts and MH per watt are class v3 figures; the rate holds under class v4 (memory-bound: a 5070 Ti measured 78.7 MH/s at 141 W on class v3 and 78.8 at 224 W on class v4). The class v4 watts rerun on the same models lands with its date, the v3 watts kept beside as the shadow premium per card",
|
||||
"v4_cost": "not measured",
|
||||
"tuned": "stock, bench only (rented, not tuned)",
|
||||
"driver_os": "NVIDIA driver 580.126.09, Ubuntu 24.04",
|
||||
|
|
@ -291,7 +291,9 @@
|
|||
"pl_w": null,
|
||||
"label": "stock (no measured tune point; the 5080 and 9070 XT passes and the class v4 efficiency pass land theirs when read)"
|
||||
},
|
||||
"group": "datacentre"
|
||||
"group": "datacentre",
|
||||
"watts_class": "v3",
|
||||
"watts_display": "385.6 (class v3)"
|
||||
},
|
||||
{
|
||||
"card": "NVIDIA RTX 5080 (16 GB)",
|
||||
|
|
@ -328,7 +330,7 @@
|
|||
"date": "2026-10-07",
|
||||
"source": "bench log: 7 October 2026, every rentable card on the hash (the fleet's sweep on rented cards; hive package 0.3.20, Ubuntu 24.04)",
|
||||
"by": "measured by the fleet",
|
||||
"note": "",
|
||||
"note": ". Watts are class v3 (read 8 October 2026, 11:4x UK): the fleet's bench pack was the class v3 program (program_class v3, generator 3, load_class mx8-erad810f22d), so this row's watts and MH per watt are class v3 figures; the rate holds under class v4 (memory-bound: a 5070 Ti measured 78.7 MH/s at 141 W on class v3 and 78.8 at 224 W on class v4). The class v4 watts rerun on the same models lands with its date, the v3 watts kept beside as the shadow premium per card",
|
||||
"v4_cost": "not measured (class v4 program only)",
|
||||
"tuned": "stock, bench only (rented, not tuned)",
|
||||
"driver_os": "NVIDIA driver 595.71.05, Ubuntu 24.04",
|
||||
|
|
@ -338,7 +340,9 @@
|
|||
"pl_w": null,
|
||||
"label": "stock (no measured tune point; the 5080 and 9070 XT passes and the class v4 efficiency pass land theirs when read)"
|
||||
},
|
||||
"group": "buy"
|
||||
"group": "buy",
|
||||
"watts_class": "v3",
|
||||
"watts_display": "178.3 (class v3)"
|
||||
},
|
||||
{
|
||||
"card": "NVIDIA RTX 3070 (8 GB)",
|
||||
|
|
@ -394,7 +398,7 @@
|
|||
"date": "2026-10-07",
|
||||
"source": "bench log: 7 October 2026, every rentable card on the hash (the fleet's sweep on rented cards; hive package 0.3.20, Ubuntu 24.04)",
|
||||
"by": "measured by the fleet",
|
||||
"note": "283.0 W maximum",
|
||||
"note": "283.0 W maximum. Watts are class v3 (read 8 October 2026, 11:4x UK): the fleet's bench pack was the class v3 program (program_class v3, generator 3, load_class mx8-erad810f22d), so this row's watts and MH per watt are class v3 figures; the rate holds under class v4 (memory-bound: a 5070 Ti measured 78.7 MH/s at 141 W on class v3 and 78.8 at 224 W on class v4). The class v4 watts rerun on the same models lands with its date, the v3 watts kept beside as the shadow premium per card",
|
||||
"v4_cost": "not measured (class v4 program only)",
|
||||
"tuned": "stock, bench only (rented, not tuned)",
|
||||
"driver_os": "NVIDIA driver 580.65.06, Ubuntu 24.04",
|
||||
|
|
@ -404,7 +408,9 @@
|
|||
"pl_w": null,
|
||||
"label": "stock (no measured tune point; the 5080 and 9070 XT passes and the class v4 efficiency pass land theirs when read)"
|
||||
},
|
||||
"group": "buy"
|
||||
"group": "buy",
|
||||
"watts_class": "v3",
|
||||
"watts_display": "267.3 (class v3)"
|
||||
},
|
||||
{
|
||||
"card": "NVIDIA RTX 3090 (24 GB)",
|
||||
|
|
@ -438,7 +444,7 @@
|
|||
"date": "2026-10-07",
|
||||
"source": "bench log: 7 October 2026, every rentable card on the hash (the fleet's sweep on rented cards; hive package 0.3.20, Ubuntu 24.04)",
|
||||
"by": "measured by the fleet",
|
||||
"note": "",
|
||||
"note": ". Watts are class v3 (read 8 October 2026, 11:4x UK): the fleet's bench pack was the class v3 program (program_class v3, generator 3, load_class mx8-erad810f22d), so this row's watts and MH per watt are class v3 figures; the rate holds under class v4 (memory-bound: a 5070 Ti measured 78.7 MH/s at 141 W on class v3 and 78.8 at 224 W on class v4). The class v4 watts rerun on the same models lands with its date, the v3 watts kept beside as the shadow premium per card",
|
||||
"v4_cost": "not measured (class v4 program only)",
|
||||
"tuned": "stock, bench only (rented, not tuned)",
|
||||
"driver_os": "NVIDIA driver 580.65.06, Ubuntu 24.04",
|
||||
|
|
@ -448,7 +454,9 @@
|
|||
"pl_w": null,
|
||||
"label": "stock (no measured tune point; the 5080 and 9070 XT passes and the class v4 efficiency pass land theirs when read)"
|
||||
},
|
||||
"group": "buy"
|
||||
"group": "buy",
|
||||
"watts_class": "v3",
|
||||
"watts_display": "249.5 (class v3)"
|
||||
},
|
||||
{
|
||||
"card": "NVIDIA RTX 4090 (24 GB)",
|
||||
|
|
@ -482,7 +490,7 @@
|
|||
"date": "2026-10-07",
|
||||
"source": "bench log: 7 October 2026, every rentable card on the hash (the fleet's sweep on rented cards; hive package 0.3.20, Ubuntu 24.04)",
|
||||
"by": "measured by the fleet",
|
||||
"note": "114.5 W maximum; the Devnet 3 boxes read 23.7 to 25.7 MH/s beside their nodes",
|
||||
"note": "114.5 W maximum; the Devnet 3 boxes read 23.7 to 25.7 MH/s beside their nodes. Watts are class v3 (read 8 October 2026, 11:4x UK): the fleet's bench pack was the class v3 program (program_class v3, generator 3, load_class mx8-erad810f22d), so this row's watts and MH per watt are class v3 figures; the rate holds under class v4 (memory-bound: a 5070 Ti measured 78.7 MH/s at 141 W on class v3 and 78.8 at 224 W on class v4). The class v4 watts rerun on the same models lands with its date, the v3 watts kept beside as the shadow premium per card",
|
||||
"v4_cost": "not measured (class v4 program only)",
|
||||
"tuned": "stock, bench only (rented, not tuned)",
|
||||
"driver_os": "NVIDIA driver 580.126.09, Ubuntu 24.04",
|
||||
|
|
@ -492,7 +500,9 @@
|
|||
"pl_w": null,
|
||||
"label": "stock (no measured tune point; the 5080 and 9070 XT passes and the class v4 efficiency pass land theirs when read)"
|
||||
},
|
||||
"group": "buy"
|
||||
"group": "buy",
|
||||
"watts_class": "v3",
|
||||
"watts_display": "111.6 (class v3)"
|
||||
},
|
||||
{
|
||||
"card": "NVIDIA RTX 3060 Ti (8 GB)",
|
||||
|
|
@ -504,7 +514,7 @@
|
|||
"date": "2026-10-07",
|
||||
"source": "bench log: 7 October 2026, every rentable card on the hash (the fleet's sweep on rented cards; hive package 0.3.20, Ubuntu 24.04)",
|
||||
"by": "measured by the fleet",
|
||||
"note": "",
|
||||
"note": ". Watts are class v3 (read 8 October 2026, 11:4x UK): the fleet's bench pack was the class v3 program (program_class v3, generator 3, load_class mx8-erad810f22d), so this row's watts and MH per watt are class v3 figures; the rate holds under class v4 (memory-bound: a 5070 Ti measured 78.7 MH/s at 141 W on class v3 and 78.8 at 224 W on class v4). The class v4 watts rerun on the same models lands with its date, the v3 watts kept beside as the shadow premium per card",
|
||||
"v4_cost": "not measured (class v4 program only)",
|
||||
"tuned": "stock, bench only (rented, not tuned)",
|
||||
"driver_os": "NVIDIA driver 580, Ubuntu 24.04",
|
||||
|
|
@ -514,7 +524,9 @@
|
|||
"pl_w": null,
|
||||
"label": "stock (no measured tune point; the 5080 and 9070 XT passes and the class v4 efficiency pass land theirs when read)"
|
||||
},
|
||||
"group": "buy"
|
||||
"group": "buy",
|
||||
"watts_class": "v3",
|
||||
"watts_display": "129.5 (class v3)"
|
||||
},
|
||||
{
|
||||
"card": "NVIDIA RTX 4060 Ti (8 GB)",
|
||||
|
|
@ -526,7 +538,7 @@
|
|||
"date": "2026-10-07",
|
||||
"source": "bench log: 7 October 2026, every rentable card on the hash (the fleet's sweep on rented cards; hive package 0.3.20, Ubuntu 24.04)",
|
||||
"by": "measured by the fleet",
|
||||
"note": "",
|
||||
"note": ". Watts are class v3 (read 8 October 2026, 11:4x UK): the fleet's bench pack was the class v3 program (program_class v3, generator 3, load_class mx8-erad810f22d), so this row's watts and MH per watt are class v3 figures; the rate holds under class v4 (memory-bound: a 5070 Ti measured 78.7 MH/s at 141 W on class v3 and 78.8 at 224 W on class v4). The class v4 watts rerun on the same models lands with its date, the v3 watts kept beside as the shadow premium per card",
|
||||
"v4_cost": "not measured (class v4 program only)",
|
||||
"tuned": "stock, bench only (rented, not tuned)",
|
||||
"driver_os": "NVIDIA driver 580, Ubuntu 24.04",
|
||||
|
|
@ -536,7 +548,9 @@
|
|||
"pl_w": null,
|
||||
"label": "stock (no measured tune point; the 5080 and 9070 XT passes and the class v4 efficiency pass land theirs when read)"
|
||||
},
|
||||
"group": "buy"
|
||||
"group": "buy",
|
||||
"watts_class": "v3",
|
||||
"watts_display": "77.5 (class v3)"
|
||||
},
|
||||
{
|
||||
"card": "NVIDIA RTX 4070 Ti (12 GB)",
|
||||
|
|
@ -548,7 +562,7 @@
|
|||
"date": "2026-10-07",
|
||||
"source": "bench log: 7 October 2026, every rentable card on the hash (the fleet's sweep on rented cards; hive package 0.3.20, Ubuntu 24.04)",
|
||||
"by": "measured by the fleet",
|
||||
"note": "",
|
||||
"note": ". Watts are class v3 (read 8 October 2026, 11:4x UK): the fleet's bench pack was the class v3 program (program_class v3, generator 3, load_class mx8-erad810f22d), so this row's watts and MH per watt are class v3 figures; the rate holds under class v4 (memory-bound: a 5070 Ti measured 78.7 MH/s at 141 W on class v3 and 78.8 at 224 W on class v4). The class v4 watts rerun on the same models lands with its date, the v3 watts kept beside as the shadow premium per card",
|
||||
"v4_cost": "not measured (class v4 program only)",
|
||||
"tuned": "stock, bench only (rented, not tuned)",
|
||||
"driver_os": "NVIDIA driver 580, Ubuntu 24.04",
|
||||
|
|
@ -558,7 +572,9 @@
|
|||
"pl_w": null,
|
||||
"label": "stock (no measured tune point; the 5080 and 9070 XT passes and the class v4 efficiency pass land theirs when read)"
|
||||
},
|
||||
"group": "buy"
|
||||
"group": "buy",
|
||||
"watts_class": "v3",
|
||||
"watts_display": "107.3 (class v3)"
|
||||
},
|
||||
{
|
||||
"card": "NVIDIA RTX 5060 (8 GB)",
|
||||
|
|
@ -570,7 +586,7 @@
|
|||
"date": "2026-10-07",
|
||||
"source": "bench log: 7 October 2026, every rentable card on the hash (the fleet's sweep on rented cards; hive package 0.3.20, Ubuntu 24.04)",
|
||||
"by": "measured by the fleet",
|
||||
"note": "",
|
||||
"note": ". Watts are class v3 (read 8 October 2026, 11:4x UK): the fleet's bench pack was the class v3 program (program_class v3, generator 3, load_class mx8-erad810f22d), so this row's watts and MH per watt are class v3 figures; the rate holds under class v4 (memory-bound: a 5070 Ti measured 78.7 MH/s at 141 W on class v3 and 78.8 at 224 W on class v4). The class v4 watts rerun on the same models lands with its date, the v3 watts kept beside as the shadow premium per card",
|
||||
"v4_cost": "not measured (class v4 program only)",
|
||||
"tuned": "stock, bench only (rented, not tuned)",
|
||||
"driver_os": "NVIDIA driver 580, Ubuntu 24.04",
|
||||
|
|
@ -580,7 +596,9 @@
|
|||
"pl_w": null,
|
||||
"label": "stock (no measured tune point; the 5080 and 9070 XT passes and the class v4 efficiency pass land theirs when read)"
|
||||
},
|
||||
"group": "buy"
|
||||
"group": "buy",
|
||||
"watts_class": "v3",
|
||||
"watts_display": "75.4 (class v3)"
|
||||
},
|
||||
{
|
||||
"card": "NVIDIA RTX 5070 (12 GB)",
|
||||
|
|
@ -592,7 +610,7 @@
|
|||
"date": "2026-10-07",
|
||||
"source": "bench log: 7 October 2026, every rentable card on the hash (the fleet's sweep on rented cards; hive package 0.3.20, Ubuntu 24.04)",
|
||||
"by": "measured by the fleet",
|
||||
"note": "",
|
||||
"note": ". Watts are class v3 (read 8 October 2026, 11:4x UK): the fleet's bench pack was the class v3 program (program_class v3, generator 3, load_class mx8-erad810f22d), so this row's watts and MH per watt are class v3 figures; the rate holds under class v4 (memory-bound: a 5070 Ti measured 78.7 MH/s at 141 W on class v3 and 78.8 at 224 W on class v4). The class v4 watts rerun on the same models lands with its date, the v3 watts kept beside as the shadow premium per card",
|
||||
"v4_cost": "not measured (class v4 program only)",
|
||||
"tuned": "stock, bench only (rented, not tuned)",
|
||||
"driver_os": "NVIDIA driver 580, Ubuntu 24.04",
|
||||
|
|
@ -602,7 +620,9 @@
|
|||
"pl_w": null,
|
||||
"label": "stock (no measured tune point; the 5080 and 9070 XT passes and the class v4 efficiency pass land theirs when read)"
|
||||
},
|
||||
"group": "buy"
|
||||
"group": "buy",
|
||||
"watts_class": "v3",
|
||||
"watts_display": "102.8 (class v3)"
|
||||
},
|
||||
{
|
||||
"card": "NVIDIA RTX 5070 Ti (16 GB)",
|
||||
|
|
@ -614,7 +634,7 @@
|
|||
"date": "2026-10-07",
|
||||
"source": "bench log: 7 October 2026, every rentable card on the hash (the fleet's sweep on rented cards; hive package 0.3.20, Ubuntu 24.04)",
|
||||
"by": "measured by the fleet",
|
||||
"note": "",
|
||||
"note": ". Watts are class v3 (read 8 October 2026, 11:4x UK): the fleet's bench pack was the class v3 program (program_class v3, generator 3, load_class mx8-erad810f22d), so this row's watts and MH per watt are class v3 figures; the rate holds under class v4 (memory-bound: a 5070 Ti measured 78.7 MH/s at 141 W on class v3 and 78.8 at 224 W on class v4). The class v4 watts rerun on the same models lands with its date, the v3 watts kept beside as the shadow premium per card",
|
||||
"v4_cost": "not measured (class v4 program only)",
|
||||
"tuned": "stock, bench only (rented, not tuned)",
|
||||
"driver_os": "NVIDIA driver 580, Ubuntu 24.04",
|
||||
|
|
@ -624,7 +644,9 @@
|
|||
"pl_w": null,
|
||||
"label": "stock (no measured tune point; the 5080 and 9070 XT passes and the class v4 efficiency pass land theirs when read)"
|
||||
},
|
||||
"group": "buy"
|
||||
"group": "buy",
|
||||
"watts_class": "v3",
|
||||
"watts_display": "145.6 (class v3)"
|
||||
},
|
||||
{
|
||||
"card": "NVIDIA RTX A5000 (24 GB)",
|
||||
|
|
@ -658,7 +680,7 @@
|
|||
"date": "2026-10-07",
|
||||
"source": "bench log: 7 October 2026, every rentable card on the hash (the fleet's sweep on rented cards; hive package 0.3.20, Ubuntu 24.04)",
|
||||
"by": "measured by the fleet",
|
||||
"note": "",
|
||||
"note": ". Watts are class v3 (read 8 October 2026, 11:4x UK): the fleet's bench pack was the class v3 program (program_class v3, generator 3, load_class mx8-erad810f22d), so this row's watts and MH per watt are class v3 figures; the rate holds under class v4 (memory-bound: a 5070 Ti measured 78.7 MH/s at 141 W on class v3 and 78.8 at 224 W on class v4). The class v4 watts rerun on the same models lands with its date, the v3 watts kept beside as the shadow premium per card",
|
||||
"v4_cost": "not measured (class v4 program only)",
|
||||
"tuned": "stock, bench only (rented, not tuned)",
|
||||
"driver_os": "NVIDIA driver 580, Ubuntu 24.04",
|
||||
|
|
@ -668,7 +690,9 @@
|
|||
"pl_w": null,
|
||||
"label": "stock (no measured tune point; the 5080 and 9070 XT passes and the class v4 efficiency pass land theirs when read)"
|
||||
},
|
||||
"group": "datacentre"
|
||||
"group": "datacentre",
|
||||
"watts_class": "v3",
|
||||
"watts_display": "240.7 (class v3)"
|
||||
},
|
||||
{
|
||||
"card": "NVIDIA A100 PCIe (80 GB)",
|
||||
|
|
@ -680,7 +704,7 @@
|
|||
"date": "2026-10-07",
|
||||
"source": "bench log: 7 October 2026, every rentable card on the hash (the fleet's sweep on rented cards; hive package 0.3.20, Ubuntu 24.04)",
|
||||
"by": "measured by the fleet",
|
||||
"note": "",
|
||||
"note": ". Watts are class v3 (read 8 October 2026, 11:4x UK): the fleet's bench pack was the class v3 program (program_class v3, generator 3, load_class mx8-erad810f22d), so this row's watts and MH per watt are class v3 figures; the rate holds under class v4 (memory-bound: a 5070 Ti measured 78.7 MH/s at 141 W on class v3 and 78.8 at 224 W on class v4). The class v4 watts rerun on the same models lands with its date, the v3 watts kept beside as the shadow premium per card",
|
||||
"v4_cost": "not measured (class v4 program only)",
|
||||
"tuned": "stock, bench only (rented, not tuned)",
|
||||
"driver_os": "NVIDIA driver 580, Ubuntu 24.04",
|
||||
|
|
@ -690,7 +714,9 @@
|
|||
"pl_w": null,
|
||||
"label": "stock (no measured tune point; the 5080 and 9070 XT passes and the class v4 efficiency pass land theirs when read)"
|
||||
},
|
||||
"group": "datacentre"
|
||||
"group": "datacentre",
|
||||
"watts_class": "v3",
|
||||
"watts_display": "299.6 (class v3)"
|
||||
},
|
||||
{
|
||||
"card": "NVIDIA A100 SXM (80 GB)",
|
||||
|
|
@ -702,7 +728,7 @@
|
|||
"date": "2026-10-07",
|
||||
"source": "bench log: 7 October 2026, every rentable card on the hash (the fleet's sweep on rented cards; hive package 0.3.20, Ubuntu 24.04)",
|
||||
"by": "measured by the fleet",
|
||||
"note": "",
|
||||
"note": ". Watts are class v3 (read 8 October 2026, 11:4x UK): the fleet's bench pack was the class v3 program (program_class v3, generator 3, load_class mx8-erad810f22d), so this row's watts and MH per watt are class v3 figures; the rate holds under class v4 (memory-bound: a 5070 Ti measured 78.7 MH/s at 141 W on class v3 and 78.8 at 224 W on class v4). The class v4 watts rerun on the same models lands with its date, the v3 watts kept beside as the shadow premium per card",
|
||||
"v4_cost": "not measured (class v4 program only)",
|
||||
"tuned": "stock, bench only (rented, not tuned)",
|
||||
"driver_os": "NVIDIA driver 580, Ubuntu 24.04",
|
||||
|
|
@ -712,7 +738,9 @@
|
|||
"pl_w": null,
|
||||
"label": "stock (no measured tune point; the 5080 and 9070 XT passes and the class v4 efficiency pass land theirs when read)"
|
||||
},
|
||||
"group": "datacentre"
|
||||
"group": "datacentre",
|
||||
"watts_class": "v3",
|
||||
"watts_display": "266.3 (class v3)"
|
||||
},
|
||||
{
|
||||
"card": "NVIDIA H200 SXM (141 GB)",
|
||||
|
|
@ -724,7 +752,7 @@
|
|||
"date": "2026-10-07",
|
||||
"source": "bench log: 7 October 2026, every rentable card on the hash (the fleet's sweep on rented cards; hive package 0.3.20, Ubuntu 24.04)",
|
||||
"by": "measured by the fleet",
|
||||
"note": "",
|
||||
"note": ". Watts are class v3 (read 8 October 2026, 11:4x UK): the fleet's bench pack was the class v3 program (program_class v3, generator 3, load_class mx8-erad810f22d), so this row's watts and MH per watt are class v3 figures; the rate holds under class v4 (memory-bound: a 5070 Ti measured 78.7 MH/s at 141 W on class v3 and 78.8 at 224 W on class v4). The class v4 watts rerun on the same models lands with its date, the v3 watts kept beside as the shadow premium per card",
|
||||
"v4_cost": "not measured (class v4 program only)",
|
||||
"tuned": "stock, bench only (rented, not tuned)",
|
||||
"driver_os": "NVIDIA driver 580, Ubuntu 24.04",
|
||||
|
|
@ -734,7 +762,9 @@
|
|||
"pl_w": null,
|
||||
"label": "stock (no measured tune point; the 5080 and 9070 XT passes and the class v4 efficiency pass land theirs when read)"
|
||||
},
|
||||
"group": "datacentre"
|
||||
"group": "datacentre",
|
||||
"watts_class": "v3",
|
||||
"watts_display": "432.9 (class v3)"
|
||||
},
|
||||
{
|
||||
"card": "NVIDIA B200 (180 GB)",
|
||||
|
|
@ -746,7 +776,7 @@
|
|||
"date": "2026-10-07",
|
||||
"source": "bench log: 7 October 2026, every rentable card on the hash (the fleet's sweep on rented cards; hive package 0.3.20, Ubuntu 24.04)",
|
||||
"by": "measured by the fleet",
|
||||
"note": "",
|
||||
"note": ". Watts are class v3 (read 8 October 2026, 11:4x UK): the fleet's bench pack was the class v3 program (program_class v3, generator 3, load_class mx8-erad810f22d), so this row's watts and MH per watt are class v3 figures; the rate holds under class v4 (memory-bound: a 5070 Ti measured 78.7 MH/s at 141 W on class v3 and 78.8 at 224 W on class v4). The class v4 watts rerun on the same models lands with its date, the v3 watts kept beside as the shadow premium per card",
|
||||
"v4_cost": "not measured (class v4 program only)",
|
||||
"tuned": "stock, bench only (rented, not tuned)",
|
||||
"driver_os": "NVIDIA driver 580, Ubuntu 24.04",
|
||||
|
|
@ -756,7 +786,9 @@
|
|||
"pl_w": null,
|
||||
"label": "stock (no measured tune point; the 5080 and 9070 XT passes and the class v4 efficiency pass land theirs when read)"
|
||||
},
|
||||
"group": "datacentre"
|
||||
"group": "datacentre",
|
||||
"watts_class": "v3",
|
||||
"watts_display": "855.6 (class v3)"
|
||||
},
|
||||
{
|
||||
"card": "NVIDIA RTX PRO 6000 Blackwell (96 GB)",
|
||||
|
|
@ -768,7 +800,7 @@
|
|||
"date": "2026-10-07",
|
||||
"source": "bench log: 7 October 2026, every rentable card on the hash (the fleet's sweep on rented cards; hive package 0.3.20, Ubuntu 24.04)",
|
||||
"by": "measured by the fleet",
|
||||
"note": "",
|
||||
"note": ". Watts are class v3 (read 8 October 2026, 11:4x UK): the fleet's bench pack was the class v3 program (program_class v3, generator 3, load_class mx8-erad810f22d), so this row's watts and MH per watt are class v3 figures; the rate holds under class v4 (memory-bound: a 5070 Ti measured 78.7 MH/s at 141 W on class v3 and 78.8 at 224 W on class v4). The class v4 watts rerun on the same models lands with its date, the v3 watts kept beside as the shadow premium per card",
|
||||
"v4_cost": "not measured (class v4 program only)",
|
||||
"tuned": "stock, bench only (rented, not tuned)",
|
||||
"driver_os": "NVIDIA driver 580, Ubuntu 24.04",
|
||||
|
|
@ -778,7 +810,529 @@
|
|||
"pl_w": null,
|
||||
"label": "stock (no measured tune point; the 5080 and 9070 XT passes and the class v4 efficiency pass land theirs when read)"
|
||||
},
|
||||
"group": "datacentre"
|
||||
"group": "datacentre",
|
||||
"watts_class": "v3",
|
||||
"watts_display": "288.7 (class v3)"
|
||||
},
|
||||
{
|
||||
"card": "NVIDIA RTX 5070 Ti (16 GB)",
|
||||
"generator": "v2",
|
||||
"mh_s": 78.45,
|
||||
"mh_per_w": 0.577,
|
||||
"watts": 135.9,
|
||||
"miner": "bench pack, igneum-worker-cuda, class v4 program (3 x 300 dispatches of 2^22)",
|
||||
"date": "2026-10-08",
|
||||
"source": "model sweep 2026-10-08, row 1 (a rented card, result cb2-rtx-5070-ti-16-gb-7324-result.json; 09:23Z)",
|
||||
"by": "measured by the fleet",
|
||||
"note": "rented single-card host, 0.06 h; power.draw mean 135.9 W (instant 139.0, max 140.0, limit 300 W), SM 2,795 MHz mean, memory 13,801 MHz, 47 C, no throttle reason; self-test PASS (96 of 96 vector lanes); the class v5 kit holds the same rate on this card (78.72 MH/s, fingerprint matched); read ceiling 79.6 MH/s, so the hash runs at 0.99 of it. Watts are class v3 (read 8 October 2026, 11:4x UK): the fleet's bench pack was the class v3 program (program_class v3, generator 3, load_class mx8-erad810f22d), so this row's watts and MH per watt are class v3 figures; the rate holds under class v4 (memory-bound: a 5070 Ti measured 78.7 MH/s at 141 W on class v3 and 78.8 at 224 W on class v4). The class v4 watts rerun on the same models lands with its date, the v3 watts kept beside as the shadow premium per card",
|
||||
"v4_cost": "not measured (class v4 program only)",
|
||||
"tuned": "stock, bench only (rented, no clock control on the host)",
|
||||
"driver_os": "NVIDIA driver 595.84, Ubuntu 24.04 (CUDA 12.8.1 image)",
|
||||
"hive": {
|
||||
"core_mhz": null,
|
||||
"mem_mhz": null,
|
||||
"pl_w": null,
|
||||
"label": "stock (rented card, no clock control on the host; no measured tune point)"
|
||||
},
|
||||
"group": "buy",
|
||||
"watts_class": "v3",
|
||||
"watts_display": "135.9 (class v3)"
|
||||
},
|
||||
{
|
||||
"generator": "v2",
|
||||
"miner": "bench pack, igneum-worker-cuda, class v4 program (3 x 300 dispatches of 2^22)",
|
||||
"date": "2026-10-08",
|
||||
"by": "measured by the fleet",
|
||||
"v4_cost": "not measured (class v4 program only)",
|
||||
"tuned": "stock, bench only (rented, no clock control on the host)",
|
||||
"hive": {
|
||||
"core_mhz": null,
|
||||
"mem_mhz": null,
|
||||
"pl_w": null,
|
||||
"label": "stock (rented card, no clock control on the host; no measured tune point)"
|
||||
},
|
||||
"group": "buy",
|
||||
"card": "NVIDIA RTX 4070 Ti Super (16 GB)",
|
||||
"mh_s": 41.24,
|
||||
"watts": 137.8,
|
||||
"mh_per_w": 0.268,
|
||||
"driver_os": "NVIDIA driver 615.71.09, Ubuntu 24.04 (CUDA 12.8.1 image)",
|
||||
"source": "model sweep 2026-10-08, row 2 (a rented card, result cb2-rtx-4070-ti-super-7325-result.json; 09:26Z); the class v4 watts rerun, 8 October 2026 (result cb4-rtx-4070-ti-super-5733-result.json, the v4-devnet-epoch0 pack, sub-version 3, three runs of about 30 s, the class v3 pack paired on the same host)",
|
||||
"note": "rented single-card host, 0.10 h; power.draw mean 142.6 W (max 145.2, limit 285 W), SM 2,885 MHz mean, memory 10,251 MHz, 47 C, the SW thermal bit set with no rate effect (three runs within 0.02 percent); self-test PASS (96 of 96 vector lanes); the class v5 kit holds the rate (41.37 MH/s, fingerprint matched); read ceiling 41.6 MH/s, the hash at 0.99 of it. The Ada 192-bit bus class: the same MH per watt as the 4070 Ti; the extra 4 GB buys headroom, not rate. Class v4 watts (8 October 2026, the rerun on the frozen v4-devnet-epoch0 pack, self-test PASS): 137.8 W at 36.93 MH/s, 0.268 MH per watt; the class v3 pack on the same host read 102.3 W at the same rate, so the shadow premium on this card is +34.7 percent of watts for no rate (the class is memory-bound). this host is a 210 W, 2,400 MHz board at 36.9 MH/s on both classes against the morning board's 41.2, so the rate reads as a range with the host noted; the premium is smaller than the 5070's because this board sits nearer its cap",
|
||||
"watts_display": "137.8 (class v4)",
|
||||
"mh_s_display": "37 to 41 by board (36.93 on this host)"
|
||||
},
|
||||
{
|
||||
"generator": "v2",
|
||||
"miner": "bench pack, igneum-worker-cuda, class v4 program (3 x 300 dispatches of 2^22)",
|
||||
"date": "2026-10-08",
|
||||
"by": "measured by the fleet",
|
||||
"v4_cost": "not measured (class v4 program only)",
|
||||
"tuned": "stock, bench only (rented, no clock control on the host)",
|
||||
"hive": {
|
||||
"core_mhz": null,
|
||||
"mem_mhz": null,
|
||||
"pl_w": null,
|
||||
"label": "stock (rented card, no clock control on the host; no measured tune point)"
|
||||
},
|
||||
"group": "buy",
|
||||
"card": "NVIDIA RTX 3080 Ti (12 GB)",
|
||||
"mh_s": 58.86,
|
||||
"watts": 293.5,
|
||||
"mh_per_w": 0.201,
|
||||
"driver_os": "NVIDIA driver 580.65.06, Ubuntu 24.04 (CUDA 12.8.1 image)",
|
||||
"source": "model sweep 2026-10-08, row 3 (a rented card, result cb2-rtx-3080-ti-12-gb-efll-result.json; 09:28Z)",
|
||||
"note": "rented single-card host, 0.04 h; power.draw mean 293.5 W (max 299.6, limit 320 W), SM 1,936 MHz mean, memory 9,251 MHz, 74 C, the SW power-cap bit set 26 W under the limit; self-test PASS (96 of 96 vector lanes); the class v5 kit runs 2.5 percent faster on this card (60.38 MH/s, fingerprint matched); read ceiling 58.9 MH/s, the hash at 1.00 of it. Matches the 7 October row (58.95 MH/s) across hosts; the worst MH per watt of the sweep and the cheapest MH per rented hour, so a buyer on a power bill prefers the 5070 Ti and a renter this card. Class v4 pair (8 October 2026, result cb4-rtx-3080-ti-12-gb-7647-result.json, a different and deep-capped board: 220 W host cap on a 350 W card, the SM clock collapsed to 749 MHz): 42.24 MH/s mean at 216.2 W under class v4 against 44.93 MH/s at 166.2 W under class v3 on that board, the shadow premium +30.1 percent of watts and, on this cap, 5 percent of rate: the first cap that costs rate (a cap near 63 percent of stock on a 350 W GDDR6X card starves the SM clock the memory loop needs, where the 4070 Super at half its 220 W and the 3070 at 88 percent held full rate). The uncapped morning rate (58.86 MH/s) stands as this card's rate; its class v4 watts on an uncapped board are not yet measured and would read about 380 W by this pair's ratio (an estimate). The rule from the pairs so far: a power cap holds the rate until the SM clock falls below roughly 1.8 GHz on Ampere and 2.4 GHz on Ada",
|
||||
"watts_class": "v3",
|
||||
"watts_display": "293.5 (class v3, uncapped board)"
|
||||
},
|
||||
{
|
||||
"generator": "v2",
|
||||
"miner": "bench pack, igneum-worker-cuda, class v4 program (3 x 300 dispatches of 2^22)",
|
||||
"date": "2026-10-08",
|
||||
"by": "measured by the fleet",
|
||||
"v4_cost": "not measured (class v4 program only)",
|
||||
"tuned": "stock, bench only (rented, no clock control on the host)",
|
||||
"hive": {
|
||||
"core_mhz": null,
|
||||
"mem_mhz": null,
|
||||
"pl_w": null,
|
||||
"label": "stock (rented card, no clock control on the host; no measured tune point)"
|
||||
},
|
||||
"group": "buy",
|
||||
"card": "NVIDIA RTX 4080 (16 GB)",
|
||||
"mh_s": 40.71,
|
||||
"watts": 185.6,
|
||||
"mh_per_w": 0.219,
|
||||
"driver_os": "NVIDIA driver 595.84, Ubuntu 24.04 (CUDA 12.8.1 image)",
|
||||
"source": "model sweep 2026-10-08, row 4 (a rented card, result cb2-rtx-4080-16-gb-7347-result.json; 09:28Z); the class v4 watts rerun, 8 October 2026 (result cb4-rtx-4080-16-gb-7107-result.json, the v4-devnet-epoch0 pack, sub-version 3, three runs of about 30 s, the class v3 pack paired on the same host)",
|
||||
"note": "rented single-card host, 0.15 h; power.draw mean 128.6 W (max 130.5, limit 320 W), SM 2,776 MHz mean, memory 10,801 MHz, 38 C, no throttle reason; self-test PASS (96 of 96 vector lanes); the class v5 kit holds the rate (40.80 MH/s, fingerprint matched); read ceiling 41.0 MH/s, the hash at 0.99 of it. One percent under the 4070 Ti Super at 14 W less: the Ada 16 GB tier is a 41 MH/s tier whichever card. Class v4 watts (8 October 2026, the rerun on the frozen v4-devnet-epoch0 pack, self-test PASS): 185.6 W at 40.73 MH/s, 0.219 MH per watt; the class v3 pack on the same host read 128.1 W at the same rate, so the shadow premium on this card is +44.9 percent of watts for no rate (the class is memory-bound). the same board as the morning row (offer 54551253; the v3 draw repeats to half a watt); the 256-bit board's premium sits above the 192-bit cards' third",
|
||||
"watts_display": "185.6 (class v4)"
|
||||
},
|
||||
{
|
||||
"generator": "v2",
|
||||
"miner": "bench pack, igneum-worker-cuda, class v4 program (3 x 300 dispatches of 2^22)",
|
||||
"date": "2026-10-08",
|
||||
"by": "measured by the fleet",
|
||||
"v4_cost": "not measured (class v4 program only)",
|
||||
"tuned": "stock, bench only (rented, no clock control on the host)",
|
||||
"group": "buy",
|
||||
"card": "NVIDIA RTX 3070 (8 GB)",
|
||||
"mh_s": 37.09,
|
||||
"watts": 196.4,
|
||||
"mh_per_w": 0.189,
|
||||
"driver_os": "NVIDIA driver 580.65.06, Ubuntu 24.04 (CUDA 12.8.1 image)",
|
||||
"source": "model sweep 2026-10-08, row 5 (a rented card, result cb2-rtx-3070-8-gb-qh9j-result.json; 09:32Z); the class v4 watts rerun, 8 October 2026 (result cb4-rtx-3070-8-gb-l6mu-result.json, the v4-devnet-epoch0 pack, sub-version 3, three runs of about 30 s, the class v3 pack paired on the same host)",
|
||||
"note": "rented single-card host, 0.06 h; power.draw mean 142.3 W (max 146.7, limit 225 W), SM 2,002 MHz mean, memory 6,801 MHz, 57 C, no throttle reason; self-test PASS (96 of 96 vector lanes); the class v5 kit holds the rate (37.14 MH/s, fingerprint matched); read ceiling 37.2 MH/s, the hash at 1.00 of it. Against the 3070 Ti: 5 percent less rate for 25 percent less power, the better owner card of the two; 8 GB holds the class v4 set with room. Class v4 watts (8 October 2026, the rerun, self-test PASS): 196.4 W at 37.11 MH/s, 0.189 MH per watt; the class v3 pack on the same host read 153.4 W at the same rate, so the shadow premium on this card is +28 percent of watts for no rate. this board is capped at 193 W by the host (stock 220) and the class v4 draw sits on the cap with the power-cap bit set while the rate holds, the same shape as the capped 4070 Super; the first Ampere pair",
|
||||
"hive": {
|
||||
"core_mhz": null,
|
||||
"mem_mhz": null,
|
||||
"pl_w": null,
|
||||
"label": "stock (rented card, no clock control on the host; no measured tune point)"
|
||||
},
|
||||
"watts_display": "196.4 (class v4)"
|
||||
},
|
||||
{
|
||||
"generator": "v2",
|
||||
"miner": "bench pack, igneum-worker-cuda, class v4 program (3 x 300 dispatches of 2^22)",
|
||||
"date": "2026-10-08",
|
||||
"by": "measured by the fleet",
|
||||
"v4_cost": "not measured (class v4 program only)",
|
||||
"tuned": "stock, bench only (rented, no clock control on the host)",
|
||||
"group": "buy",
|
||||
"card": "NVIDIA RTX 3070 Ti (8 GB)",
|
||||
"mh_s": 38.98,
|
||||
"watts": 267.6,
|
||||
"mh_per_w": 0.146,
|
||||
"driver_os": "NVIDIA driver 595.71.05, Ubuntu 24.04 (CUDA 12.8.1 image)",
|
||||
"source": "model sweep 2026-10-08, row 6 (a rented card, result cb2-rtx-3070-ti-8-gb-8528-result.json; 09:33Z); the class v4 watts rerun, 8 October 2026 (result cb4-rtx-3070-ti-8-gb-7705-result.json, the v4-devnet-epoch0 pack, sub-version 3, three runs of about 30 s, the class v3 pack paired on the same host)",
|
||||
"note": "rented single-card host, 0.07 h; power.draw mean 177.1 W (max 183.6, limit 290 W), SM 1,955 MHz mean, memory 9,251 MHz, 67 C, no throttle reason; self-test PASS (96 of 96 vector lanes); the class v5 kit holds the rate (39.12 MH/s, fingerprint matched); read ceiling 39.1 MH/s, the hash at 1.00 of it. Repeats the 7 October row on another host (38.98 then, 38.98 now; 178 then 177 W), so the class v4 number is host-independent to 0.1 percent. Class v4 watts (8 October 2026, the rerun, self-test PASS): 267.6 W at 39.1 MH/s, 0.146 MH per watt; the class v3 pack on the same host read 180.4 W at the same rate, so the shadow premium on this card is +48.3 percent of watts for no rate. the same board as the 7 October row (offer 36538839), uncapped (a 310 W AIB); the uncapped GDDR6X Ampere premium sits with the 4080's and the 5070's rather than the 192-bit Ada third, so the premium scales with the SM the board had idle under class v3",
|
||||
"hive": {
|
||||
"core_mhz": null,
|
||||
"mem_mhz": null,
|
||||
"pl_w": null,
|
||||
"label": "stock (rented card, no clock control on the host; no measured tune point)"
|
||||
},
|
||||
"watts_display": "267.6 (class v4)"
|
||||
},
|
||||
{
|
||||
"generator": "v2",
|
||||
"miner": "bench pack, igneum-worker-cuda, class v4 program (3 x 300 dispatches of 2^22)",
|
||||
"date": "2026-10-08",
|
||||
"by": "measured by the fleet",
|
||||
"v4_cost": "not measured (class v4 program only)",
|
||||
"tuned": "stock, bench only (rented, no clock control on the host)",
|
||||
"group": "buy",
|
||||
"card": "NVIDIA RTX 4060 Ti (16 GB)",
|
||||
"mh_s": 20.07,
|
||||
"watts": 102.3,
|
||||
"mh_per_w": 0.196,
|
||||
"driver_os": "NVIDIA driver 595.71.05, Ubuntu 24.04 (CUDA 12.8.1 image)",
|
||||
"source": "model sweep 2026-10-08, row 7 (a rented card, result cb2-rtx-4060-ti-16-gb-7364-result.json; 09:33Z); the class v4 watts rerun, 8 October 2026 (result cb4-rtx-4060-ti-16-gb-6679-result.json, the v4-devnet-epoch0 pack, sub-version 3, three runs of about 30 s, the class v3 pack paired on the same host)",
|
||||
"note": "rented single-card host, 0.22 h; power.draw mean 79.2 W (max 86.2, limit 165 W), SM 2,836 MHz mean, memory 8,751 MHz, 63 C, no throttle reason; self-test PASS (96 of 96 vector lanes); the class v5 kit holds the rate (20.10 MH/s, fingerprint matched). Repeats the 7 October number (20.10 then, 20.07 now); the one card of the sweep well under its probed read ceiling (0.65 of 30.9 MH/s: the 128-bit bus with the large L2 makes the chase probe optimistic), so 20 MH/s at 79 W is the card's rate; 16 GB holds any class with room. Class v4 watts (8 October 2026, the rerun on the frozen v4-devnet-epoch0 pack, self-test PASS): 102.3 W at 20.1 MH/s, 0.196 MH per watt; the class v3 pack on the same host read 76.6 W at the same rate, so the shadow premium on this card is +33.6 percent of watts for no rate (the class is memory-bound). the same board as the 7 October row (offer 47543124); the rate is the same on every 4060 Ti host and both classes (20.07 to 20.10)",
|
||||
"hive": {
|
||||
"core_mhz": null,
|
||||
"mem_mhz": null,
|
||||
"pl_w": null,
|
||||
"label": "stock (rented card, no clock control on the host; no measured tune point)"
|
||||
},
|
||||
"watts_display": "102.3 (class v4)"
|
||||
},
|
||||
{
|
||||
"generator": "v2",
|
||||
"miner": "bench pack, igneum-worker-cuda, class v4 program (3 x 300 dispatches of 2^22)",
|
||||
"date": "2026-10-08",
|
||||
"by": "measured by the fleet",
|
||||
"v4_cost": "not measured (class v4 program only)",
|
||||
"tuned": "stock, bench only (rented, no clock control on the host)",
|
||||
"group": "buy",
|
||||
"card": "NVIDIA RTX 5070 (12 GB)",
|
||||
"mh_s": 51.81,
|
||||
"watts": 176.1,
|
||||
"mh_per_w": 0.334,
|
||||
"driver_os": "NVIDIA driver 580.173.02, Ubuntu 24.04 (CUDA 12.8.1 image)",
|
||||
"source": "model sweep 2026-10-08, row 8 (a rented card, result cb2-rtx-5070-12-gb-8750-result.json; 09:35Z); the class v4 watts rerun, 8 October 2026 (result cb4-rtx-5070-12-gb-5732-result.json, the v4-devnet-epoch0 pack, sub-version 3, three runs of about 30 s, the class v3 pack paired on the same host)",
|
||||
"note": "rented single-card host, 0.09 h; power.draw mean 110.8 W (max 112.0, limit 250 W), SM 2,851 MHz mean, memory 13,801 MHz, 60 C, no throttle reason; self-test PASS (96 of 96 vector lanes); the class v5 kit holds the rate (51.98 MH/s, fingerprint matched); read ceiling 52.3 MH/s, the hash at 0.99 of it. Repeats the 7 October row (52.01 then, 51.82 now) at 8 W more on this host; second to the 5070 Ti in MH per watt among consumer cards (GDDR7 lifts Blackwell here, not SM count); 12 GB holds the class v4 set with 10 GB spare. Class v4 watts (8 October 2026, the rerun on the frozen v4-devnet-epoch0 pack, self-test PASS): 176.1 W at 58.89 MH/s, 0.334 MH per watt; the class v3 pack on the same host read 113.1 W at the same rate, so the shadow premium on this card is +55.7 percent of watts for no rate (the class is memory-bound). board-to-board spread: this host 58.9 MH/s on both classes, the morning host 51.8 (GDDR7 memory clocks differ by board), so the rate reads as a range with the host noted",
|
||||
"hive": {
|
||||
"core_mhz": null,
|
||||
"mem_mhz": null,
|
||||
"pl_w": null,
|
||||
"label": "stock (rented card, no clock control on the host; no measured tune point)"
|
||||
},
|
||||
"watts_display": "176.1 (class v4)",
|
||||
"mh_s_display": "52 to 59 by board (58.89 on this host)"
|
||||
},
|
||||
{
|
||||
"generator": "v2",
|
||||
"miner": "bench pack, igneum-worker-cuda, class v4 program (3 x 300 dispatches of 2^22)",
|
||||
"date": "2026-10-08",
|
||||
"by": "measured by the fleet",
|
||||
"v4_cost": "not measured (class v4 program only)",
|
||||
"tuned": "stock, bench only (rented, no clock control on the host)",
|
||||
"group": "buy",
|
||||
"card": "NVIDIA RTX 4070 Super (12 GB)",
|
||||
"mh_s": 31.24,
|
||||
"watts": 108.4,
|
||||
"mh_per_w": 0.288,
|
||||
"driver_os": "NVIDIA driver 580.178.04, Ubuntu 24.04 (CUDA 12.8.1 image)",
|
||||
"source": "model sweep 2026-10-08, row 9 (a rented card, result cb2-rtx-4070-super-12--8582-result.json; 09:36Z); the class v4 watts rerun, 8 October 2026 (result cb4-rtx-4070-super-12--6238-result.json, the v4-devnet-epoch0 pack, sub-version 3, three runs of about 30 s, the class v3 pack paired on the same host)",
|
||||
"note": "rented single-card host, 0.13 h; power.draw mean 100.2 W (max 103.9) under a 110 W host cap (stock 220 W), SM 2,764 MHz mean, memory 10,251 MHz, 53 C, no throttle reason; self-test PASS (96 of 96 vector lanes); the class v5 kit holds the rate (31.29 MH/s, fingerprint matched); read ceiling 34.4 MH/s, the hash at 0.91 of it. Lands on the 4070 Ti's number (31.26 on 7 October) at 7 W less (the same 192-bit 21 Gbps bus); the host's 110 W cap cost no rate, a tune-down reading in itself: an owner can cap a 4070 Super at half its stock power and lose nothing on class v4. Class v4 watts (8 October 2026, the rerun on the frozen v4-devnet-epoch0 pack, self-test PASS): 108.4 W at 31.25 MH/s, 0.288 MH per watt; the class v3 pack on the same host read 99.2 W at the same rate, so the shadow premium on this card is +9.3 percent of watts for no rate (the class is memory-bound). the same board as the morning row (host offer 51485188), capped at 110 W by the host (stock 220) with the SW power-cap bit set the whole run: the cap absorbs the class v4 stage's extra draw (the SM clock drops 10 percent, the rate does not move), so the premium is 9 percent here against a third on uncapped Ada boards; a power cap near half stock costs a 192-bit Ada card nothing on class v4",
|
||||
"hive": {
|
||||
"core_mhz": null,
|
||||
"mem_mhz": null,
|
||||
"pl_w": null,
|
||||
"label": "stock (rented card, no clock control on the host; no measured tune point)"
|
||||
},
|
||||
"watts_display": "108.4 (class v4)"
|
||||
},
|
||||
{
|
||||
"generator": "v2",
|
||||
"miner": "bench pack, igneum-worker-cuda, class v4 program (3 x 300 dispatches of 2^22)",
|
||||
"date": "2026-10-08",
|
||||
"by": "measured by the fleet",
|
||||
"v4_cost": "not measured (class v4 program only)",
|
||||
"tuned": "stock, bench only (rented, no clock control on the host)",
|
||||
"group": "buy",
|
||||
"card": "NVIDIA RTX 3060 Ti (8 GB)",
|
||||
"mh_s": 31.7,
|
||||
"watts": 100.4,
|
||||
"mh_per_w": 0.316,
|
||||
"driver_os": "NVIDIA driver 595.91.07, Ubuntu 24.04 (CUDA 12.8.1 image)",
|
||||
"source": "model sweep 2026-10-08, row 10 (a rented card, result cb2-rtx-3060-ti-8-gb-8771-result.json; 09:37Z)",
|
||||
"note": "rented single-card host, 0.12 h; power.draw mean 100.4 W (max 104.7, limit 180 W), SM 1,560 MHz mean, memory 5,001 MHz on this host (below the 7,000 MHz GDDR6 stock), 61 C, no throttle reason; self-test PASS (96 of 96 vector lanes); the class v5 kit holds the rate (31.75 MH/s, fingerprint matched); read ceiling 31.8 MH/s, the hash at 1.00 of it. Four percent under the 7 October 3060 Ti row (33.1 on another host), consistent with this host's lower memory clock; the best MH per watt of the Ampere cards. Watts are class v3 (read 8 October 2026, 11:4x UK): the fleet's bench pack was the class v3 program (program_class v3, generator 3, load_class mx8-erad810f22d), so this row's watts and MH per watt are class v3 figures; the rate holds under class v4 (memory-bound: a 5070 Ti measured 78.7 MH/s at 141 W on class v3 and 78.8 at 224 W on class v4). The class v4 watts rerun on the same models lands with its date, the v3 watts kept beside as the shadow premium per card",
|
||||
"hive": {
|
||||
"core_mhz": null,
|
||||
"mem_mhz": null,
|
||||
"pl_w": null,
|
||||
"label": "stock (rented card, no clock control on the host; no measured tune point)"
|
||||
},
|
||||
"watts_class": "v3",
|
||||
"watts_display": "100.4 (class v3)"
|
||||
},
|
||||
{
|
||||
"generator": "v2",
|
||||
"miner": "bench pack, igneum-worker-cuda, class v4 program (3 x 300 dispatches of 2^22)",
|
||||
"date": "2026-10-08",
|
||||
"by": "measured by the fleet",
|
||||
"v4_cost": "not measured (class v4 program only)",
|
||||
"tuned": "stock, bench only (rented, no clock control on the host)",
|
||||
"card": "NVIDIA RTX 2080 Ti (11 GB)",
|
||||
"group": "buy",
|
||||
"mh_s": 26.01,
|
||||
"watts": 224.6,
|
||||
"mh_per_w": 0.116,
|
||||
"driver_os": "NVIDIA driver 580.159.03, Ubuntu 24.04 (CUDA 12.8.1 image)",
|
||||
"source": "model sweep 2026-10-08, row 11 (a rented card, result cb2-rtx-2080-ti-9077-result.json; 09:40Z)",
|
||||
"note": "rented single-card host, 0.13 h; power.draw mean 224.6 W (max 234.7, limit 300 W; the driver reports no power average on Turing), SM 1,914 MHz mean, memory 6,802 MHz, 72 C, no throttle reason; self-test PASS (96 of 96 vector lanes); the class v5 kit holds the rate (26.04 MH/s, fingerprint matched); read ceiling 29.9 MH/s, the hash at 0.87 of it. The first Turing row: the 7 October 2080 Ti pod that left no result was a host fault, not the card. The worst MH per watt measured on any card (the Titan RTX, the same silicon, read 28.3 MH/s at 226 W on 7 October): an owner mines at a loss on any real power price; 11 GB holds the set. Watts are class v3 (read 8 October 2026, 11:4x UK): the fleet's bench pack was the class v3 program (program_class v3, generator 3, load_class mx8-erad810f22d), so this row's watts and MH per watt are class v3 figures; the rate holds under class v4 (memory-bound: a 5070 Ti measured 78.7 MH/s at 141 W on class v3 and 78.8 at 224 W on class v4). The class v4 watts rerun on the same models lands with its date, the v3 watts kept beside as the shadow premium per card",
|
||||
"hive": {
|
||||
"core_mhz": null,
|
||||
"mem_mhz": null,
|
||||
"pl_w": null,
|
||||
"label": "stock (rented card, no clock control on the host; no measured tune point)"
|
||||
},
|
||||
"watts_class": "v3",
|
||||
"watts_display": "224.6 (class v3)"
|
||||
},
|
||||
{
|
||||
"generator": "v2",
|
||||
"miner": "bench pack, igneum-worker-cuda, class v4 program (3 x 300 dispatches of 2^22)",
|
||||
"date": "2026-10-08",
|
||||
"by": "measured by the fleet",
|
||||
"v4_cost": "not measured (class v4 program only)",
|
||||
"tuned": "stock, bench only (rented, no clock control on the host)",
|
||||
"card": "NVIDIA RTX 2070 Super (8 GB)",
|
||||
"group": "buy",
|
||||
"mh_s": 19.09,
|
||||
"watts": 166,
|
||||
"mh_per_w": 0.115,
|
||||
"driver_os": "NVIDIA driver 575.57.08, Ubuntu 24.04 (CUDA 12.8.1 image)",
|
||||
"source": "model sweep 2026-10-08, row 12 (a rented card, result cb2-rtx-2070-super-8-g-9129-result.json; 09:41Z)",
|
||||
"note": "rented single-card host, 0.15 h; power.draw mean 166.0 W (max 167.8, limit 215 W; no power average on Turing), SM 1,955 MHz mean, memory 6,802 MHz, 64 C, no throttle reason; self-test PASS (96 of 96 vector lanes); the class v5 kit holds the rate (19.12 MH/s, fingerprint matched); read ceiling 30.1 MH/s, the hash at 0.63 of it: Turing does not overlap the independent reads the hash needs (its indep probe 2.45 G loads/s binds). The Turing per-watt floor: a 4060's rate at twice the power. Watts are class v3 (read 8 October 2026, 11:4x UK): the fleet's bench pack was the class v3 program (program_class v3, generator 3, load_class mx8-erad810f22d), so this row's watts and MH per watt are class v3 figures; the rate holds under class v4 (memory-bound: a 5070 Ti measured 78.7 MH/s at 141 W on class v3 and 78.8 at 224 W on class v4). The class v4 watts rerun on the same models lands with its date, the v3 watts kept beside as the shadow premium per card",
|
||||
"hive": {
|
||||
"core_mhz": null,
|
||||
"mem_mhz": null,
|
||||
"pl_w": null,
|
||||
"label": "stock (rented card, no clock control on the host; no measured tune point)"
|
||||
},
|
||||
"watts_class": "v3",
|
||||
"watts_display": "166 (class v3)"
|
||||
},
|
||||
{
|
||||
"generator": "v2",
|
||||
"miner": "bench pack, igneum-worker-cuda, class v4 program (3 x 300 dispatches of 2^22)",
|
||||
"date": "2026-10-08",
|
||||
"by": "measured by the fleet",
|
||||
"v4_cost": "not measured (class v4 program only)",
|
||||
"tuned": "stock, bench only (rented, no clock control on the host)",
|
||||
"card": "NVIDIA A100 SXM4 (80 GB)",
|
||||
"group": "datacentre",
|
||||
"mh_s": 138.1,
|
||||
"watts": 268.6,
|
||||
"mh_per_w": 0.515,
|
||||
"driver_os": "NVIDIA driver 595.71.05, Ubuntu 24.04 (CUDA 12.8.1 image)",
|
||||
"source": "model sweep 2026-10-08, row 13 (a rented card, result cb2-a100-80-gb-j79g-result.json; 09:43Z)",
|
||||
"note": "rented single-card host, 0.04 h; power.draw mean 268.6 W (max 274.1, limit 400 W; no power average on this host), SM 1,410 MHz, HBM2e 1,593 MHz, 44 C, no throttle reason; self-test PASS (96 of 96 vector lanes); the class v5 kit reads 136.48 MH/s, 1.3 percent under class v4 (fingerprint matched), the first card where v5 is not level with v4; read ceiling 138.6 MH/s, the hash at 1.00 of it. Repeats the three 7 October readings (138.39, 138.74, 138.76) to 0.3 percent on a fourth host; datacentre-class per watt, a third of a 3080 Ti's MH per rented dollar. Watts are class v3 (read 8 October 2026, 11:4x UK): the fleet's bench pack was the class v3 program (program_class v3, generator 3, load_class mx8-erad810f22d), so this row's watts and MH per watt are class v3 figures; the rate holds under class v4 (memory-bound: a 5070 Ti measured 78.7 MH/s at 141 W on class v3 and 78.8 at 224 W on class v4). The class v4 watts rerun on the same models lands with its date, the v3 watts kept beside as the shadow premium per card",
|
||||
"hive": {
|
||||
"core_mhz": null,
|
||||
"mem_mhz": null,
|
||||
"pl_w": null,
|
||||
"label": "stock (rented card, no clock control on the host; no measured tune point)"
|
||||
},
|
||||
"watts_class": "v3",
|
||||
"watts_display": "268.6 (class v3)"
|
||||
},
|
||||
{
|
||||
"generator": "v2",
|
||||
"miner": "bench pack, igneum-worker-cuda, class v4 program (3 x 300 dispatches of 2^22)",
|
||||
"date": "2026-10-08",
|
||||
"by": "measured by the fleet",
|
||||
"v4_cost": "not measured (class v4 program only)",
|
||||
"tuned": "stock, bench only (rented, no clock control on the host)",
|
||||
"card": "NVIDIA H100 SXM (80 GB HBM3)",
|
||||
"group": "datacentre",
|
||||
"mh_s": 248.3,
|
||||
"watts": 411.7,
|
||||
"mh_per_w": 0.605,
|
||||
"driver_os": "NVIDIA driver 580.126.09, Ubuntu 24.04 (CUDA 12.8.1 image)",
|
||||
"source": "model sweep 2026-10-08, row 14 (a rented card, result cb2-h100-80-gb-rs3d-result.json; 09:43Z)",
|
||||
"note": "rented single-card host, 0.03 h; power.draw mean 411.7 W (instant 434.1, the largest gap between the two fields in the sweep, 22 W; max 437.1, limit 700 W), SM 1,980 MHz, HBM3 2,619 MHz, 36 C, no throttle reason; self-test PASS (96 of 96 vector lanes); the class v5 kit reads 252.64 MH/s, 1.5 percent over class v4 (fingerprint matched); read ceiling 252.4 MH/s, the hash at 0.99 of it. Repeats the 7 October rows (248.70, 248.21) on a third host; the best per-watt figure of the sweep on power.draw (0.573 on the instant field) and the worst MH per rented dollar: an owner's card on cheap power, never a renter's. Watts are class v3 (read 8 October 2026, 11:4x UK): the fleet's bench pack was the class v3 program (program_class v3, generator 3, load_class mx8-erad810f22d), so this row's watts and MH per watt are class v3 figures; the rate holds under class v4 (memory-bound: a 5070 Ti measured 78.7 MH/s at 141 W on class v3 and 78.8 at 224 W on class v4). The class v4 watts rerun on the same models lands with its date, the v3 watts kept beside as the shadow premium per card",
|
||||
"hive": {
|
||||
"core_mhz": null,
|
||||
"mem_mhz": null,
|
||||
"pl_w": null,
|
||||
"label": "stock (rented card, no clock control on the host; no measured tune point)"
|
||||
},
|
||||
"watts_class": "v3",
|
||||
"watts_display": "411.7 (class v3)"
|
||||
},
|
||||
{
|
||||
"generator": "v2",
|
||||
"miner": "bench pack, igneum-worker-cuda, class v4 program (3 x 300 dispatches of 2^22)",
|
||||
"date": "2026-10-08",
|
||||
"by": "measured by the fleet",
|
||||
"v4_cost": "not measured (class v4 program only)",
|
||||
"tuned": "stock, bench only (rented, no clock control on the host)",
|
||||
"card": "NVIDIA RTX A4000 (16 GB)",
|
||||
"group": "datacentre",
|
||||
"mh_s": 31.41,
|
||||
"watts": 112.8,
|
||||
"mh_per_w": 0.279,
|
||||
"driver_os": "NVIDIA driver 595.91.07, Ubuntu 24.04 (CUDA 12.8.1 image)",
|
||||
"source": "model sweep 2026-10-08, row 15 (a rented card, result cb2-rtx-a4000-16-gb-9473-result.json; 09:45Z)",
|
||||
"note": "rented single-card host, 0.16 h; power.draw mean 112.8 W on a host that caps the card at 114 W (stock 140 W; the SW power-cap bit set the whole run), SM 1,562 MHz mean, memory 6,501 MHz, 81 C; self-test PASS (96 of 96 vector lanes); read ceiling 31.6 MH/s, the hash at 0.99 of it. Class v4 repeats the 7 October row (31.45 then, 31.41 now) under the cap. The class v5 kit's reading on this capped host is held off the page until an uncapped A4000 confirms it. Watts are class v3 (read 8 October 2026, 11:4x UK): the fleet's bench pack was the class v3 program (program_class v3, generator 3, load_class mx8-erad810f22d), so this row's watts and MH per watt are class v3 figures; the rate holds under class v4 (memory-bound: a 5070 Ti measured 78.7 MH/s at 141 W on class v3 and 78.8 at 224 W on class v4). The class v4 watts rerun on the same models lands with its date, the v3 watts kept beside as the shadow premium per card",
|
||||
"hive": {
|
||||
"core_mhz": null,
|
||||
"mem_mhz": null,
|
||||
"pl_w": null,
|
||||
"label": "stock (rented card, no clock control on the host; no measured tune point)"
|
||||
},
|
||||
"watts_class": "v3",
|
||||
"watts_display": "112.8 (class v3)"
|
||||
},
|
||||
{
|
||||
"generator": "v2",
|
||||
"miner": "bench pack, igneum-worker-cuda, class v4 program (3 x 300 dispatches of 2^22)",
|
||||
"date": "2026-10-08",
|
||||
"by": "measured by the fleet",
|
||||
"v4_cost": "not measured (class v4 program only)",
|
||||
"tuned": "stock, bench only (rented, no clock control on the host)",
|
||||
"card": "NVIDIA RTX A6000 (48 GB)",
|
||||
"group": "datacentre",
|
||||
"mh_s": 53.64,
|
||||
"watts": 239.1,
|
||||
"mh_per_w": 0.224,
|
||||
"driver_os": "NVIDIA driver 595.84, Ubuntu 24.04 (CUDA 12.8.1 image)",
|
||||
"source": "model sweep 2026-10-08, row 16 (a rented card, result cb2-rtx-a6000-48-gb-9600-result.json; 09:46Z)",
|
||||
"note": "rented single-card host, 0.15 h; power.draw mean 239.1 W (max 251.0, limit 300 W), SM 1,913 MHz mean, memory 7,601 MHz, 65 C, no throttle reason; self-test PASS (96 of 96 vector lanes); the class v5 kit holds the rate (53.82 MH/s, fingerprint matched), so on an uncapped sm_86 card v5 is level with v4 and the A4000's v5 reading narrows to its power cap; read ceiling 53.8 MH/s, the hash at 1.00 of it. Repeats the 7 October row (53.66 then, 53.64 now) at 43 W less on this host; a 3090-class rate at a 3090-class draw. Watts are class v3 (read 8 October 2026, 11:4x UK): the fleet's bench pack was the class v3 program (program_class v3, generator 3, load_class mx8-erad810f22d), so this row's watts and MH per watt are class v3 figures; the rate holds under class v4 (memory-bound: a 5070 Ti measured 78.7 MH/s at 141 W on class v3 and 78.8 at 224 W on class v4). The class v4 watts rerun on the same models lands with its date, the v3 watts kept beside as the shadow premium per card",
|
||||
"hive": {
|
||||
"core_mhz": null,
|
||||
"mem_mhz": null,
|
||||
"pl_w": null,
|
||||
"label": "stock (rented card, no clock control on the host; no measured tune point)"
|
||||
},
|
||||
"watts_class": "v3",
|
||||
"watts_display": "239.1 (class v3)"
|
||||
},
|
||||
{
|
||||
"generator": "v2",
|
||||
"miner": "bench pack, igneum-worker-cuda, class v4 program (3 x 300 dispatches of 2^22)",
|
||||
"date": "2026-10-08",
|
||||
"by": "measured by the fleet",
|
||||
"v4_cost": "not measured (class v4 program only)",
|
||||
"tuned": "stock, bench only (rented; Pascal has no clock lock on any host)",
|
||||
"card": "NVIDIA GTX 1080 Ti (11 GB)",
|
||||
"group": "buy",
|
||||
"mh_s": 16.26,
|
||||
"watts": 124.3,
|
||||
"mh_per_w": 0.131,
|
||||
"driver_os": "NVIDIA driver 580.173.02, Ubuntu 24.04 (CUDA 12.8.1 image)",
|
||||
"source": "model sweep 2026-10-08, rows 17 and 22 (two rented hosts, results cb2-gtx-1080-ti-11-gb-0377-result.json and cb2-gtx-1080-ti-11-gb-1452-result.json; 09:49Z and 10:02Z)",
|
||||
"note": "the mean of the first host's two clean runs (16.26 MH/s at 124.3 W, the card uncapped at a 280 W limit); a second host read 16.29 MH/s at 129.4 W under a 130 W host cap with five of five self-tests passing, so the first host's one-in-three cache self-test failure was that host's VRAM and not Pascal, and the flag is cleared. Power.draw on the first host max 125.5 W (no power average on Pascal), SM 1,936 MHz mean, memory 5,005 MHz, 59 C; the class v5 kit held the rate on the uncapped host (16.27 MH/s) and read 13.27 MH/s on the 130 W-capped one (fingerprint matched on both); read ceiling 16.3 MH/s, the hash at 1.00 of it. The first Pascal row: a 2017 card that runs the class at its own ceiling. Watts are class v3 (read 8 October 2026, 11:4x UK): the fleet's bench pack was the class v3 program (program_class v3, generator 3, load_class mx8-erad810f22d), so this row's watts and MH per watt are class v3 figures; the rate holds under class v4 (memory-bound: a 5070 Ti measured 78.7 MH/s at 141 W on class v3 and 78.8 at 224 W on class v4). The class v4 watts rerun on the same models lands with its date, the v3 watts kept beside as the shadow premium per card",
|
||||
"hive": {
|
||||
"core_mhz": null,
|
||||
"mem_mhz": null,
|
||||
"pl_w": null,
|
||||
"label": "stock (rented card; Pascal has no clock lock; no measured tune point)"
|
||||
},
|
||||
"watts_class": "v3",
|
||||
"watts_display": "124.3 (class v3)"
|
||||
},
|
||||
{
|
||||
"generator": "v2",
|
||||
"miner": "bench pack, igneum-worker-cuda, class v4 program (3 x 300 dispatches of 2^22)",
|
||||
"date": "2026-10-08",
|
||||
"by": "measured by the fleet",
|
||||
"v4_cost": "not measured (class v4 program only)",
|
||||
"tuned": "stock, bench only (rented, no clock control on the host)",
|
||||
"card": "NVIDIA RTX 4060 (8 GB)",
|
||||
"group": "buy",
|
||||
"mh_s": 19.09,
|
||||
"watts": null,
|
||||
"mh_per_w": null,
|
||||
"driver_os": "NVIDIA driver 595.91.07, Ubuntu 24.04 (CUDA 12.8.1 image)",
|
||||
"source": "model sweep 2026-10-08, row 18 (a rented card, result cb2-rtx-4060-8-gb-0672-result.json; 09:53Z); the class v4 rerun, 8 October 2026 (result cb4-rtx-4060-8-gb-7165-result.json: the rate on both classes, no watts)",
|
||||
"note": "watts not reported by any rented host (four 4060 boards across 7 and 8 October, one machine family, every power field absent; two other hosts never answered ssh); the class v4 rerun on 8 October read the same rate on both classes (19.09 MH/s class v4, 19.094 class v3) and still no watts; by the 4060 Ti pair on the same silicon (+33.6 percent) the class v4 draw is about 80 to 90 W from a class v3 draw of about 60 to 70 W under the 115 W limit, an estimate until an owner measures at the wall.12 h; SM 2,732 MHz mean, memory 8,251 MHz, 57 C, no throttle reason; self-test PASS (96 of 96 vector lanes); the class v5 kit holds the rate (19.11 MH/s, fingerprint matched); read ceiling 30.2 MH/s, the hash at 0.63 of it (the 128-bit bus: the independent-read line binds, as on the 2070 Super). Repeats the 7 October row (19.09 then, 19.10 now)",
|
||||
"hive": {
|
||||
"core_mhz": null,
|
||||
"mem_mhz": null,
|
||||
"pl_w": null,
|
||||
"label": "stock (rented card, no clock control on the host; no measured tune point)"
|
||||
}
|
||||
},
|
||||
{
|
||||
"generator": "v2",
|
||||
"miner": "bench pack, igneum-worker-cuda, class v4 program (3 x 300 dispatches of 2^22)",
|
||||
"date": "2026-10-08",
|
||||
"by": "measured by the fleet",
|
||||
"v4_cost": "not measured (class v4 program only)",
|
||||
"tuned": "stock, bench only (rented, no clock control on the host)",
|
||||
"card": "NVIDIA RTX 2060 (6 GB)",
|
||||
"group": "buy",
|
||||
"mh_s": 14.13,
|
||||
"watts": 120.6,
|
||||
"mh_per_w": 0.117,
|
||||
"driver_os": "NVIDIA driver 580.159.03, Ubuntu 24.04 (CUDA 12.8.1 image)",
|
||||
"source": "model sweep 2026-10-08, row 19 (a rented card, result cb2-rtx-2060-0673-result.json; 09:55Z)",
|
||||
"note": "rented single-card host, 0.15 h; power.draw mean 120.6 W (max 124.6, limit 160 W; no power average on Turing), SM 1,948 MHz mean, memory 6,801 MHz, 69 C, no throttle reason; self-test PASS (96 of 96 vector lanes); the class v5 kit holds the rate (14.14 MH/s, fingerprint matched); read ceiling 16.1 MH/s, the hash at 0.88 of it. The floor of the list and the smallest card on it: the class v4 set fits with 4.6 GB spare; the same Turing per-watt floor as the 2070 Super and the 2080 Ti, so every Turing card earns the same per watt and only the absolute rate differs. Watts are class v3 (read 8 October 2026, 11:4x UK): the fleet's bench pack was the class v3 program (program_class v3, generator 3, load_class mx8-erad810f22d), so this row's watts and MH per watt are class v3 figures; the rate holds under class v4 (memory-bound: a 5070 Ti measured 78.7 MH/s at 141 W on class v3 and 78.8 at 224 W on class v4). The class v4 watts rerun on the same models lands with its date, the v3 watts kept beside as the shadow premium per card",
|
||||
"hive": {
|
||||
"core_mhz": null,
|
||||
"mem_mhz": null,
|
||||
"pl_w": null,
|
||||
"label": "stock (rented card, no clock control on the host; no measured tune point)"
|
||||
},
|
||||
"watts_class": "v3",
|
||||
"watts_display": "120.6 (class v3)"
|
||||
},
|
||||
{
|
||||
"generator": "v2",
|
||||
"miner": "bench pack, igneum-worker-cuda, class v4 program (3 x 300 dispatches of 2^22)",
|
||||
"date": "2026-10-08",
|
||||
"by": "measured by the fleet",
|
||||
"v4_cost": "not measured (class v4 program only)",
|
||||
"tuned": "stock, bench only (rented, no clock control on the host)",
|
||||
"card": "NVIDIA RTX 4070 Ti (12 GB)",
|
||||
"group": "buy",
|
||||
"mh_s": 31.24,
|
||||
"watts": 155.3,
|
||||
"mh_per_w": 0.201,
|
||||
"driver_os": "NVIDIA driver 580.126.09, Ubuntu 24.04 (CUDA 12.8.1 image)",
|
||||
"source": "model sweep 2026-10-08, row 20 (a rented card, result cb2-rtx-4070-ti-12-gb-0695-result.json; 09:57Z); the class v4 watts rerun, 8 October 2026 (result cb4-rtx-4070-ti-12-gb-5744-result.json, the v4-devnet-epoch0 pack, sub-version 3, three runs of about 30 s, the class v3 pack paired on the same host)",
|
||||
"note": "rented single-card host, 0.18 h; power.draw mean 95.4 W (max 96.7, limit 285 W), SM 2,825 MHz mean, memory 10,251 MHz, 49 C, no throttle reason; self-test PASS (96 of 96 vector lanes); the class v5 kit holds the rate (31.28 MH/s, fingerprint matched); read ceiling 31.7 MH/s, the hash at 0.99 of it. Repeats the 7 October rate to 0.07 percent on another provider at 12 W less; the 192-bit Ada pair (4070 Ti, 4070 Super) land on one number, 31.2 MH/s under 100 W. Class v4 watts (8 October 2026, the rerun on the frozen v4-devnet-epoch0 pack, self-test PASS): 155.3 W at 31.26 MH/s, 0.201 MH per watt; the class v3 pack on the same host read 113.8 W at the same rate, so the shadow premium on this card is +36.5 percent of watts for no rate (the class is memory-bound). the rate matches the morning and 7 October rows on a third host (no host spread on this card); driver 570.169 ran the class v4 pack clean",
|
||||
"hive": {
|
||||
"core_mhz": null,
|
||||
"mem_mhz": null,
|
||||
"pl_w": null,
|
||||
"label": "stock (rented card, no clock control on the host; no measured tune point)"
|
||||
},
|
||||
"watts_display": "155.3 (class v4)"
|
||||
},
|
||||
{
|
||||
"generator": "v2",
|
||||
"miner": "bench pack, igneum-worker-cuda, class v4 program (3 x 300 dispatches of 2^22)",
|
||||
"date": "2026-10-08",
|
||||
"by": "measured by the fleet",
|
||||
"v4_cost": "not measured (class v4 program only)",
|
||||
"tuned": "stock, bench only (rented, no clock control on the host)",
|
||||
"card": "NVIDIA L40S (48 GB)",
|
||||
"group": "datacentre",
|
||||
"mh_s": 56.41,
|
||||
"watts": 220.7,
|
||||
"mh_per_w": 0.256,
|
||||
"driver_os": "NVIDIA driver 570.133.20, Ubuntu 24.04 (CUDA 12.8.1 image)",
|
||||
"source": "model sweep 2026-10-08, row 21 (a rented card, result cb2-l40s-48-gb-0890-result.json; 09:57Z)",
|
||||
"note": "rented single-card host, 0.17 h; power.draw mean 220.7 W (max 227.2, limit 350 W), SM 2,520 MHz, memory 9,001 MHz, 45 C, no throttle reason; self-test PASS (96 of 96 vector lanes); the class v5 kit holds the rate (56.51 MH/s, fingerprint matched); read ceiling 57.8 MH/s, the hash at 0.98 of it. Repeats the 7 October row (56.36 then, 56.41 now) at 20 W less on this host; a 384-bit GDDR6 card that lands where the 3090 Ti and the A6000 do at a datacentre price. Driver 570.133, the oldest of the sweep, ran the CUDA 12.8 worker clean: 570 is a safe floor. Watts are class v3 (read 8 October 2026, 11:4x UK): the fleet's bench pack was the class v3 program (program_class v3, generator 3, load_class mx8-erad810f22d), so this row's watts and MH per watt are class v3 figures; the rate holds under class v4 (memory-bound: a 5070 Ti measured 78.7 MH/s at 141 W on class v3 and 78.8 at 224 W on class v4). The class v4 watts rerun on the same models lands with its date, the v3 watts kept beside as the shadow premium per card",
|
||||
"hive": {
|
||||
"core_mhz": null,
|
||||
"mem_mhz": null,
|
||||
"pl_w": null,
|
||||
"label": "stock (rented card, no clock control on the host; no measured tune point)"
|
||||
},
|
||||
"watts_class": "v3",
|
||||
"watts_display": "220.7 (class v3)"
|
||||
},
|
||||
{
|
||||
"generator": "v2",
|
||||
"miner": "bench pack, igneum-worker-cuda, class v4 program (3 x 300 dispatches of 2^22)",
|
||||
"date": "2026-10-08",
|
||||
"by": "measured by the fleet",
|
||||
"v4_cost": "not measured (class v4 program only)",
|
||||
"tuned": "stock, bench only (rented, no clock control on the host)",
|
||||
"card": "NVIDIA RTX 4080 Super (16 GB)",
|
||||
"group": "buy",
|
||||
"mh_s": 42.6,
|
||||
"watts": 134.9,
|
||||
"mh_per_w": 0.316,
|
||||
"driver_os": "NVIDIA driver 580.126.09, Ubuntu 24.04 (CUDA 12.8.1 image)",
|
||||
"source": "model sweep 2026-10-08, row 23 (a rented card, result cb2-rtx-4080-super-16-g-2453-result.json; 10:03Z)",
|
||||
"note": "rented single-card host, 0.12 h; power.draw mean 134.9 W (max 138.4, limit 320 W), SM 2,740 MHz mean, memory 11,254 MHz, 51 C, no throttle reason; self-test PASS (96 of 96 vector lanes); the class v5 kit holds the rate (42.68 MH/s, fingerprint matched); read ceiling 43.1 MH/s, the hash at 0.99 of it. The 23 Gbps GDDR6X gives it 4.6 percent over the 4080 for 6 W more at the same MH per watt: the Ada 256-bit tier is 41 to 43 MH/s whichever card. Watts are class v3 (read 8 October 2026, 11:4x UK): the fleet's bench pack was the class v3 program (program_class v3, generator 3, load_class mx8-erad810f22d), so this row's watts and MH per watt are class v3 figures; the rate holds under class v4 (memory-bound: a 5070 Ti measured 78.7 MH/s at 141 W on class v3 and 78.8 at 224 W on class v4). The class v4 watts rerun on the same models lands with its date, the v3 watts kept beside as the shadow premium per card",
|
||||
"hive": {
|
||||
"core_mhz": null,
|
||||
"mem_mhz": null,
|
||||
"pl_w": null,
|
||||
"label": "stock (rented card, no clock control on the host; no measured tune point)"
|
||||
},
|
||||
"watts_class": "v3",
|
||||
"watts_display": "134.9 (class v3)"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -83,6 +83,7 @@ pre b{color:var(--molten-text);font-weight:500}
|
|||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-mine" data-group="mine" data-active aria-expanded="false" aria-controls="nav-panel-mine" aria-haspopup="true">Mine<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-network" data-group="network" aria-expanded="false" aria-controls="nav-panel-network" aria-haspopup="true">Network<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-learn" data-group="learn" aria-expanded="false" aria-controls="nav-panel-learn" aria-haspopup="true">Learn<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-build" data-group="build" aria-expanded="false" aria-controls="nav-panel-build" aria-haspopup="true">Build<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
</div>
|
||||
<div class="nav-controls">
|
||||
<button class="btn icon-btn" type="button" data-theme-toggle aria-label="Switch to light theme"><svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><circle cx="12" cy="12" r="4"/><path d="M12 2v2m0 16v2M2 12h2m16 0h2M5 5l1 1m12 12 1 1M5 19l1-1M18 6l1-1"/></svg></button>
|
||||
|
|
@ -100,7 +101,6 @@ pre b{color:var(--molten-text);font-weight:500}
|
|||
<a href="/wallet" data-nav="wallet"><b>The wallet</b><span>Your coins. Final means final.</span></a>
|
||||
<a href="/miners" data-nav="miners"><b>GPU bench table</b><span>Measured rates, card by card.</span></a>
|
||||
<a href="/dev-fee" data-nav="dev-fee"><b>The dev fee</b><span>The optional one, in full view, off with one flag.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Testnet faucet</b><span>Test coin for an address, once a day.</span></a>
|
||||
<a href="/metamask" data-nav="metamask"><b>Add to MetaMask</b><span>Igneum as a network in your wallet.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -111,6 +111,9 @@ pre b{color:var(--molten-text);font-weight:500}
|
|||
<a href="/journey" data-nav="journey"><b>The journey</b><span>Six phases, four gates, the log behind them.</span></a>
|
||||
<a href="/bench" data-nav="bench"><b>Engineering log</b><span>Every measurement, with the commands that made it.</span></a>
|
||||
<a href="/evidence" data-nav="evidence"><b>Evidence</b><span>Every claim and how far it is tested.</span></a>
|
||||
<a href="/light" data-nav="light"><b>Light wallet</b><span>A balance your browser proves, trusting no node.</span></a>
|
||||
<a href="/receipt" data-nav="receipt"><b>Payment receipt</b><span>A receipt any third party re-verifies offline.</span></a>
|
||||
<a href="/oracle" data-nav="oracle"><b>State oracle on Sepolia</b><span>Devnet 3 balances read from another chain.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-panel" id="nav-panel-learn" data-group="learn" role="region" aria-labelledby="nav-btn-learn" hidden>
|
||||
|
|
@ -123,6 +126,14 @@ pre b{color:var(--molten-text);font-weight:500}
|
|||
<a href="/provenance" data-nav="provenance"><b>Built on the shoulders</b><span>Every borrowed part, credited.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-panel" id="nav-panel-build" data-group="build" role="region" aria-labelledby="nav-btn-build" hidden>
|
||||
<div class="panel-list">
|
||||
<a href="/build" data-nav="build"><b>Build on Igneum</b><span>Chain ids, RPC, a contract in five minutes.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Devnet faucet</b><span>10 IGN of devnet coin, once a day.</span></a>
|
||||
<a href="/swap" data-nav="swap"><b>Swap</b><span>Test tokens on Devnet 3; every swap is a proven block.</span></a>
|
||||
<a href="/grants" data-nav="grants"><b>Grants</b><span>Tooling, apps, infrastructure, research.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-sheet" id="nav-sheet" role="dialog" aria-modal="true" aria-label="Menu" hidden>
|
||||
|
|
@ -134,7 +145,6 @@ pre b{color:var(--molten-text);font-weight:500}
|
|||
<a href="/wallet" data-nav="wallet"><b>The wallet</b><span>Your coins. Final means final.</span></a>
|
||||
<a href="/miners" data-nav="miners"><b>GPU bench table</b><span>Measured rates, card by card.</span></a>
|
||||
<a href="/dev-fee" data-nav="dev-fee"><b>The dev fee</b><span>The optional one, in full view, off with one flag.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Testnet faucet</b><span>Test coin for an address, once a day.</span></a>
|
||||
<a href="/metamask" data-nav="metamask"><b>Add to MetaMask</b><span>Igneum as a network in your wallet.</span></a>
|
||||
</div>
|
||||
<div class="sheet-group"><div class="sheet-head">Network</div>
|
||||
|
|
@ -143,6 +153,9 @@ pre b{color:var(--molten-text);font-weight:500}
|
|||
<a href="/journey" data-nav="journey"><b>The journey</b><span>Six phases, four gates, the log behind them.</span></a>
|
||||
<a href="/bench" data-nav="bench"><b>Engineering log</b><span>Every measurement, with the commands that made it.</span></a>
|
||||
<a href="/evidence" data-nav="evidence"><b>Evidence</b><span>Every claim and how far it is tested.</span></a>
|
||||
<a href="/light" data-nav="light"><b>Light wallet</b><span>A balance your browser proves, trusting no node.</span></a>
|
||||
<a href="/receipt" data-nav="receipt"><b>Payment receipt</b><span>A receipt any third party re-verifies offline.</span></a>
|
||||
<a href="/oracle" data-nav="oracle"><b>State oracle on Sepolia</b><span>Devnet 3 balances read from another chain.</span></a>
|
||||
</div>
|
||||
<div class="sheet-group"><div class="sheet-head">Learn</div>
|
||||
<a href="/litepaper" data-nav="litepaper"><b>Litepaper</b><span>The design, as published.</span></a>
|
||||
|
|
@ -152,6 +165,12 @@ pre b{color:var(--molten-text);font-weight:500}
|
|||
<a href="/randomx" data-nav="randomx"><b>Igneum vs RandomX</b><span>What was kept and what was rebuilt for GPUs.</span></a>
|
||||
<a href="/provenance" data-nav="provenance"><b>Built on the shoulders</b><span>Every borrowed part, credited.</span></a>
|
||||
</div>
|
||||
<div class="sheet-group"><div class="sheet-head">Build</div>
|
||||
<a href="/build" data-nav="build"><b>Build on Igneum</b><span>Chain ids, RPC, a contract in five minutes.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Devnet faucet</b><span>10 IGN of devnet coin, once a day.</span></a>
|
||||
<a href="/swap" data-nav="swap"><b>Swap</b><span>Test tokens on Devnet 3; every swap is a proven block.</span></a>
|
||||
<a href="/grants" data-nav="grants"><b>Grants</b><span>Tooling, apps, infrastructure, research.</span></a>
|
||||
</div>
|
||||
<div class="sheet-foot">
|
||||
<a href="/download" class="btn primary big" data-nav="download">Download</a>
|
||||
<div class="sheet-social"><a href="https://discord.gg/igneum" target="_blank" rel="noopener">Discord</a><a href="https://git.igneum.network/igneum-network/spec" target="_blank" rel="noopener">Source</a><a href="https://www.reddit.com/user/Igneum_network/" target="_blank" rel="noopener">Reddit</a></div>
|
||||
|
|
@ -268,9 +287,9 @@ pre b{color:var(--molten-text);font-weight:500}
|
|||
<div class="platform-body" id="panel-hive" role="tabpanel" aria-labelledby="tab-hive" data-platform-panel="hive" hidden>
|
||||
<div class="download-platform"><span class="osmark" data-os="hive" title="HiveOS"><svg viewBox="0 0 24 24" width="22" height="22" aria-hidden="true" focusable="false" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linejoin="round" stroke-linecap="round"><path d="M12 2.6 20.2 7.3v9.4L12 21.4 3.8 16.7V7.3z"/><path d="M12 7.4 16 9.7v4.6L12 16.6 8 14.3V9.7z"/><path d="M12 7.4V2.6M16 9.7l4.2-2.4M16 14.3l4.2 2.4M12 16.6v4.8M8 14.3l-4.2 2.4M8 9.7 3.8 7.3"/></svg></span><div><h3>Ember for Linux and HiveOS</h3><p>a tarball for rigs and Hive flight sheets</p></div></div>
|
||||
<p class="download-note">For the rig people. One tarball, the miner and the node inside, the same signed manifest as the desktop apps.</p>
|
||||
<a data-dl="miner-hive" href="https://dl.igneum.network/public/igneum-miner-hive.tar.gz" class="btn primary"><svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="M12 3v12m-5-5 5 5 5-5M5 16v4h14v-4"/></svg>Download the tarball <span data-dl-meta="miner-hive" style="font-weight:400;opacity:.85">v0.3.23 · 28.8 MB</span></a>
|
||||
<div class="hive-sheet" id="hive"><b>HiveOS Flight Sheet.</b> Miner: <b>Custom</b>. Installation URL: <code data-dl-url="miner-hive">https://dl.igneum.network/dl/public/igneum-hive-0.3.23.tar.gz</code>. Miner name <code>igneum</code>, wallet and worker <code>0x<your 40-hex payout address>.%WORKER_NAME%</code>. Hive itself is untested on our side: tell us what breaks.</div>
|
||||
<p class="sha">sha256 <span data-dl-sha="miner-hive">0d716ed92560b6b2eccb63ca1bd7a4d9eb64c9b334e8370e1263f0344cee294e</span></p>
|
||||
<a data-dl="miner-hive" href="https://dl.igneum.network/public/igneum-miner-hive.tar.gz" class="btn primary"><svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="M12 3v12m-5-5 5 5 5-5M5 16v4h14v-4"/></svg>Download the tarball <span data-dl-meta="miner-hive" style="font-weight:400;opacity:.85">v0.3.22 · 28.8 MB</span></a>
|
||||
<div class="hive-sheet" id="hive"><b>HiveOS Flight Sheet.</b> Miner: <b>Custom</b>. Installation URL: <code data-dl-url="miner-hive">https://dl.igneum.network/dl/public/igneum-hive-0.3.22.tar.gz</code>. Miner name <code>igneum</code>, wallet and worker <code>0x<your 40-hex payout address>.%WORKER_NAME%</code>. Hive itself is untested on our side: tell us what breaks.</div>
|
||||
<p class="sha">sha256 <span data-dl-sha="miner-hive">8ad6dcef9edc57dcd33e8d5a97cbef5cdda0e384a6e56d3f62f8903029c4c764</span></p>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
|
|
@ -453,7 +472,7 @@ pre b{color:var(--molten-text);font-weight:500}
|
|||
<a href="/wallet">The wallet</a>
|
||||
<a href="/miners">GPU bench table</a>
|
||||
<a href="/dev-fee">The dev fee</a>
|
||||
<a href="/faucet">Testnet faucet</a>
|
||||
<a href="/faucet">Devnet faucet</a>
|
||||
<a href="/metamask">Add Igneum to MetaMask</a>
|
||||
</div></div>
|
||||
<div class="footer-column"><h4>Read</h4><div>
|
||||
|
|
@ -468,6 +487,9 @@ pre b{color:var(--molten-text);font-weight:500}
|
|||
<div class="footer-column"><h4>Explore</h4><div>
|
||||
<a href="/live">Live devnet</a>
|
||||
<a href="/explorer">Explorer</a>
|
||||
<a href="/build">Build on Igneum</a>
|
||||
<a href="/swap">Swap</a>
|
||||
<a href="/grants">Grants</a>
|
||||
<a href="/journey">Journey</a>
|
||||
<a href="/download">Downloads: devnet build</a>
|
||||
<a href="https://discord.gg/igneum" target="_blank" rel="noopener">Community Discord</a>
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
361
site/oracle.html
Normal file
361
site/oracle.html
Normal file
|
|
@ -0,0 +1,361 @@
|
|||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
|
||||
<title>Igneum state oracle on Sepolia</title>
|
||||
<meta name="description" content="A Sepolia contract that stores Devnet 3 finality certificates and proven state roots so other contracts read a Devnet 3 balance. Devnet 3, no value.">
|
||||
<link rel="canonical" href="https://igneum.network/oracle">
|
||||
<meta name="theme-color" content="#0C0C0E">
|
||||
<meta property="og:type" content="website">
|
||||
<meta property="og:site_name" content="Igneum">
|
||||
<meta property="og:title" content="Igneum state oracle on Sepolia">
|
||||
<meta property="og:description" content="A Sepolia contract that stores Devnet 3 finality certificates and proven state roots so other contracts read a Devnet 3 balance. Devnet 3, no value.">
|
||||
<meta property="og:url" content="https://igneum.network/oracle">
|
||||
<meta property="og:image" content="https://igneum.network/og.png?v=3">
|
||||
<meta property="og:image:width" content="1200">
|
||||
<meta property="og:image:height" content="630">
|
||||
<meta property="og:image:alt" content="Igneum. Mined by GPUs. Proven by fire.">
|
||||
<meta name="twitter:card" content="summary_large_image">
|
||||
<meta name="twitter:title" content="Igneum state oracle on Sepolia">
|
||||
<meta name="twitter:description" content="A Sepolia contract that stores Devnet 3 finality certificates and proven state roots so other contracts read a Devnet 3 balance. Devnet 3, no value.">
|
||||
<meta name="twitter:image" content="https://igneum.network/og.png?v=3">
|
||||
<meta name="twitter:image:alt" content="Igneum. Mined by GPUs. Proven by fire.">
|
||||
<link rel="icon" href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1024 1024'%3E%3Crect width='1024' height='1024' fill='%230C0C0E'/%3E%3Cg transform='translate(166.95 166.95) scale(6.901)'%3E%3Cpolygon points='50,4 74,34 67,58 80,54 61,96 39,96 20,54 33,58 26,34' fill='%23F2541B'/%3E%3Cpolygon points='50,42 59,58 50,82 41,58' fill='%230C0C0E'/%3E%3C/g%3E%3C/svg%3E" type="image/svg+xml">
|
||||
<link rel="icon" href="/favicon.ico" sizes="48x48">
|
||||
<link rel="icon" href="/favicon-32.png" type="image/png" sizes="32x32">
|
||||
<link rel="icon" href="/icon-192.png" type="image/png" sizes="192x192">
|
||||
<link rel="icon" href="/icon-512.png" type="image/png" sizes="512x512">
|
||||
<link rel="apple-touch-icon" href="/apple-touch-icon.png" sizes="180x180">
|
||||
<link rel="manifest" href="/site.webmanifest">
|
||||
<!-- head:start -->
|
||||
<link rel="preload" href="/fonts/unbounded-900.woff2" as="font" type="font/woff2" crossorigin>
|
||||
<link rel="preload" href="/fonts/plex-sans-400.woff2" as="font" type="font/woff2" crossorigin>
|
||||
<meta name="color-scheme" content="dark light">
|
||||
<link rel="stylesheet" href="/site.css">
|
||||
<style>
|
||||
/* Shared by every page: the head partial, injected by the build between the head markers. Edit the partial, not the page. */
|
||||
/* Fonts, self-hosted (latin subsets, OFL): Unbounded 500/700/900, IBM Plex Sans 400/500/600, IBM Plex Mono 400/500. Fallbacks carry size and ascent overrides so the swap does not move the layout. The tokens, type and components are in /site.css (docs/plans/site-ui-3.md). */
|
||||
@font-face{font-family:'Unbounded';font-style:normal;font-weight:500;font-display:swap;src:url(/fonts/unbounded-500.woff2) format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
|
||||
@font-face{font-family:'Unbounded';font-style:normal;font-weight:700;font-display:swap;src:url(/fonts/unbounded-700.woff2) format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
|
||||
@font-face{font-family:'Unbounded';font-style:normal;font-weight:900;font-display:swap;src:url(/fonts/unbounded-900.woff2) format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
|
||||
@font-face{font-family:'IBM Plex Sans';font-style:normal;font-weight:400;font-display:swap;src:url(/fonts/plex-sans-400.woff2) format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
|
||||
@font-face{font-family:'IBM Plex Sans';font-style:normal;font-weight:500;font-display:swap;src:url(/fonts/plex-sans-500.woff2) format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
|
||||
@font-face{font-family:'IBM Plex Sans';font-style:normal;font-weight:600;font-display:swap;src:url(/fonts/plex-sans-600.woff2) format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
|
||||
@font-face{font-family:'IBM Plex Mono';font-style:normal;font-weight:400;font-display:swap;src:url(/fonts/plex-mono-400.woff2) format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
|
||||
@font-face{font-family:'IBM Plex Mono';font-style:normal;font-weight:500;font-display:swap;src:url(/fonts/plex-mono-500.woff2) format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
|
||||
@font-face{font-family:'Unbounded Fallback';src:local('Arial Black'),local('Arial-Black'),local('Impact');size-adjust:114%;ascent-override:87.5%;descent-override:21.5%;line-gap-override:0%}
|
||||
@font-face{font-family:'Plex Sans Fallback';src:local('Arial'),local('Helvetica Neue'),local('Helvetica');size-adjust:100.5%;ascent-override:102%;descent-override:27.4%;line-gap-override:0%}
|
||||
@font-face{font-family:'Plex Mono Fallback';src:local('Courier New'),local('Menlo');size-adjust:100%;ascent-override:102.5%;descent-override:27.5%;line-gap-override:0%}
|
||||
</style>
|
||||
<script>
|
||||
/* theme before first paint: ?theme=light|dark for one view (the capture tool), else the stored choice under igneum-theme, else the system setting; ?motion=off marks the page data-motion=off so every .reveal is drawn at once (a headless render never scrolls) */
|
||||
(function(){var t=null;try{t=new URLSearchParams(location.search).get("theme");}catch(e){}if(t!=="light"&&t!=="dark"){try{t=localStorage.getItem("igneum-theme");}catch(e){t=null;}}if(t!=="light"&&t!=="dark")t=window.matchMedia&&window.matchMedia("(prefers-color-scheme: light)").matches?"light":"dark";document.documentElement.setAttribute("data-theme",t);try{if(new URLSearchParams(location.search).get("motion")==="off")document.documentElement.setAttribute("data-motion","off");}catch(e){}})();
|
||||
</script>
|
||||
<!-- head:end -->
|
||||
<style>
|
||||
/* reference apps (8 Oct 2026): the verify form, the proven headline, the step list; tokens and components are in /site.css */
|
||||
.vform{display:grid;gap:10px;margin:0}
|
||||
.vform label{font:500 var(--t-sm)/1.4 var(--f-mono);letter-spacing:.08em;text-transform:uppercase;color:var(--ash)}
|
||||
.vform .row{display:flex;gap:10px;flex-wrap:wrap}.vform input{flex:1 1 320px;font-family:var(--f-mono);font-size:14px}
|
||||
.vstatus{font:400 13px/1.5 var(--f-mono);color:var(--ash);min-height:20px}.vstatus[data-kind="ok"]{color:var(--ember-text)}.vstatus[data-kind="bad"]{color:var(--molten-text)}
|
||||
.headline{background:var(--graphite);border:1px solid var(--line);border-radius:var(--r-card);padding:var(--s-5);margin:var(--s-5) 0 var(--s-4)}
|
||||
.headline.bad{border-color:var(--molten)}
|
||||
.headline .big{font:900 clamp(32px,6vw,56px)/1.05 var(--f-display);color:var(--bone);margin:10px 0 8px;overflow-wrap:anywhere}.headline .big span{font-size:.45em;color:var(--ash);font-weight:700}
|
||||
.headline .kv{margin-top:var(--s-3)}.headline .kv small{color:var(--ash);display:block}.headline .mono{font-family:var(--f-mono);font-size:13px;overflow-wrap:anywhere}
|
||||
.kv>div{min-width:0;overflow-wrap:anywhere}.card .kv .mono{font-family:var(--f-mono);font-size:13px}
|
||||
@media (max-width:640px){.kv{grid-template-columns:1fr}.kv>div{padding:6px 0}.kv .k{padding-top:10px;border-top:1px solid var(--line)}.kv>div:not(.k){border-top:0}}
|
||||
.neg{border-left:2px solid var(--ember);background:var(--row);border-radius:0 var(--r-row) var(--r-row) 0;padding:12px var(--s-4);margin:0 0 var(--s-3);font-size:14px;color:var(--ink-2)}
|
||||
.neg b{font:500 11px/1 var(--f-mono);letter-spacing:.12em;text-transform:uppercase;color:var(--ember-text);margin-right:8px}.neg.wrong{border-color:var(--molten)}.neg.wrong b{color:var(--molten-text)}
|
||||
.neg small{display:block;color:var(--ash);font-family:var(--f-mono);font-size:12px;margin-top:4px;overflow-wrap:anywhere}
|
||||
.steps{list-style:none;margin:0;padding:0;display:grid;gap:8px}
|
||||
.steps li{display:grid;grid-template-columns:84px 1fr;gap:4px 12px;background:var(--row);border:1px solid var(--line);border-radius:var(--r-row);padding:10px 14px;font-size:14px;color:var(--ink-2)}
|
||||
.steps li b{font:500 11px/1.6 var(--f-mono);letter-spacing:.12em;text-transform:uppercase;color:var(--ember-text)}.steps li.bad b{color:var(--molten-text)}
|
||||
.steps li small{grid-column:2;color:var(--ash);font-family:var(--f-mono);font-size:12px;overflow-wrap:anywhere}
|
||||
.why{border:1px solid var(--line-2);border-radius:var(--r-card);padding:var(--s-4) var(--s-5);background:var(--obsidian);margin:var(--s-5) 0}
|
||||
.why p{margin:0;font-size:15px;color:var(--ink-2)}.why p+p{margin-top:8px}
|
||||
.meta{display:grid;gap:6px;font:400 13px/1.6 var(--f-mono);color:var(--ash);margin:var(--s-4) 0 0}.meta code{overflow-wrap:anywhere}
|
||||
@media (max-width:640px){.steps li{grid-template-columns:1fr}.steps li small{grid-column:1}}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<!-- nav:start -->
|
||||
<a class="skip" href="#main">Skip to content</a>
|
||||
<nav class="nav" aria-label="Main" data-nav-version="5">
|
||||
<div class="container nav-row">
|
||||
<a href="/" class="logo" aria-label="Igneum home">
|
||||
<svg class="brand-mark" viewBox="0 0 1024 1024" aria-hidden="true"><rect width="1024" height="1024" rx="160" fill="#0C0C0E"></rect><g transform="translate(166.95 166.95) scale(6.901)"><polygon points="50,4 74,34 67,58 80,54 61,96 39,96 20,54 33,58 26,34" fill="#F2541B"></polygon><polygon points="50,42 59,58 50,82 41,58" fill="#0C0C0E"></polygon></g></svg>
|
||||
<span class="word">IGNEUM</span>
|
||||
</a>
|
||||
<span class="devnet" id="nav-devnet" title="igneum-devnet-3, chain id 4463. Coins have no value. The chain may reset."><span class="dot off" id="foot-dot"></span><span id="foot-state">devnet</span></span>
|
||||
<div class="nav-groups" id="nav-groups" role="list">
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-mine" data-group="mine" aria-expanded="false" aria-controls="nav-panel-mine" aria-haspopup="true">Mine<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-network" data-group="network" data-active aria-expanded="false" aria-controls="nav-panel-network" aria-haspopup="true">Network<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-learn" data-group="learn" aria-expanded="false" aria-controls="nav-panel-learn" aria-haspopup="true">Learn<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-build" data-group="build" aria-expanded="false" aria-controls="nav-panel-build" aria-haspopup="true">Build<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
</div>
|
||||
<div class="nav-controls">
|
||||
<button class="btn icon-btn" type="button" data-theme-toggle aria-label="Switch to light theme"><svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><circle cx="12" cy="12" r="4"/><path d="M12 2v2m0 16v2M2 12h2m16 0h2M5 5l1 1m12 12 1 1M5 19l1-1M18 6l1-1"/></svg></button>
|
||||
<a href="/download" class="btn primary small cta" data-nav="download">Download</a>
|
||||
<button class="burger" id="nav-burger" type="button" aria-expanded="false" aria-controls="nav-sheet" aria-label="Open the menu" aria-haspopup="true"><svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path class="bars" d="M4 6h16M4 12h16M4 18h16"/><path class="cross" d="m6 6 12 12M6 18 18 6"/></svg></button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="panels" id="nav-panels">
|
||||
<div class="panel-wrap container">
|
||||
<div class="nav-panel" id="nav-panel-mine" data-group="mine" role="region" aria-labelledby="nav-btn-mine" hidden>
|
||||
<div class="panel-list">
|
||||
<a href="/miner" data-nav="miner"><b>Ember, the miner</b><span>One click installs the node, the miner and the prover.</span></a>
|
||||
<a href="/download" data-nav="download"><b>Download</b><span>Windows, macOS, Linux and HiveOS.</span></a>
|
||||
<a href="/app" data-nav="app"><b>The app</b><span>What you see while the card mines.</span></a>
|
||||
<a href="/wallet" data-nav="wallet"><b>The wallet</b><span>Your coins. Final means final.</span></a>
|
||||
<a href="/miners" data-nav="miners"><b>GPU bench table</b><span>Measured rates, card by card.</span></a>
|
||||
<a href="/dev-fee" data-nav="dev-fee"><b>The dev fee</b><span>The optional one, in full view, off with one flag.</span></a>
|
||||
<a href="/metamask" data-nav="metamask"><b>Add to MetaMask</b><span>Igneum as a network in your wallet.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-panel" id="nav-panel-network" data-group="network" role="region" aria-labelledby="nav-btn-network" hidden>
|
||||
<div class="panel-list">
|
||||
<a href="/live" data-nav="live"><b>Live devnet</b><span>The chain as it grows, one lane per miner.</span></a>
|
||||
<a href="/explorer" data-nav="explorer"><b>Explorer</b><span>Look a block or an address up.</span></a>
|
||||
<a href="/journey" data-nav="journey"><b>The journey</b><span>Six phases, four gates, the log behind them.</span></a>
|
||||
<a href="/bench" data-nav="bench"><b>Engineering log</b><span>Every measurement, with the commands that made it.</span></a>
|
||||
<a href="/evidence" data-nav="evidence"><b>Evidence</b><span>Every claim and how far it is tested.</span></a>
|
||||
<a href="/light" data-nav="light"><b>Light wallet</b><span>A balance your browser proves, trusting no node.</span></a>
|
||||
<a href="/receipt" data-nav="receipt"><b>Payment receipt</b><span>A receipt any third party re-verifies offline.</span></a>
|
||||
<a href="/oracle" data-nav="oracle" aria-current="page"><b>State oracle on Sepolia</b><span>Devnet 3 balances read from another chain.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-panel" id="nav-panel-learn" data-group="learn" role="region" aria-labelledby="nav-btn-learn" hidden>
|
||||
<div class="panel-list">
|
||||
<a href="/litepaper" data-nav="litepaper"><b>Litepaper</b><span>The design, as published.</span></a>
|
||||
<a href="/income" data-nav="income"><b>Income per tier</b><span>IGN a day per card at three network sizes, and the electricity.</span></a>
|
||||
<a href="/ledger" data-nav="ledger"><b>Ledger</b><span>Every criticism, answered or conceded.</span></a>
|
||||
<a href="/claims" data-nav="claims"><b>What Igneum does not claim</b><span>The limits, stated first.</span></a>
|
||||
<a href="/randomx" data-nav="randomx"><b>Igneum vs RandomX</b><span>What was kept and what was rebuilt for GPUs.</span></a>
|
||||
<a href="/provenance" data-nav="provenance"><b>Built on the shoulders</b><span>Every borrowed part, credited.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-panel" id="nav-panel-build" data-group="build" role="region" aria-labelledby="nav-btn-build" hidden>
|
||||
<div class="panel-list">
|
||||
<a href="/build" data-nav="build"><b>Build on Igneum</b><span>Chain ids, RPC, a contract in five minutes.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Devnet faucet</b><span>10 IGN of devnet coin, once a day.</span></a>
|
||||
<a href="/swap" data-nav="swap"><b>Swap</b><span>Test tokens on Devnet 3; every swap is a proven block.</span></a>
|
||||
<a href="/grants" data-nav="grants"><b>Grants</b><span>Tooling, apps, infrastructure, research.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-sheet" id="nav-sheet" role="dialog" aria-modal="true" aria-label="Menu" hidden>
|
||||
<div class="sheet-scroll">
|
||||
<div class="sheet-group"><div class="sheet-head">Mine</div>
|
||||
<a href="/miner" data-nav="miner"><b>Ember, the miner</b><span>One click installs the node, the miner and the prover.</span></a>
|
||||
<a href="/download" data-nav="download"><b>Download</b><span>Windows, macOS, Linux and HiveOS.</span></a>
|
||||
<a href="/app" data-nav="app"><b>The app</b><span>What you see while the card mines.</span></a>
|
||||
<a href="/wallet" data-nav="wallet"><b>The wallet</b><span>Your coins. Final means final.</span></a>
|
||||
<a href="/miners" data-nav="miners"><b>GPU bench table</b><span>Measured rates, card by card.</span></a>
|
||||
<a href="/dev-fee" data-nav="dev-fee"><b>The dev fee</b><span>The optional one, in full view, off with one flag.</span></a>
|
||||
<a href="/metamask" data-nav="metamask"><b>Add to MetaMask</b><span>Igneum as a network in your wallet.</span></a>
|
||||
</div>
|
||||
<div class="sheet-group"><div class="sheet-head">Network</div>
|
||||
<a href="/live" data-nav="live"><b>Live devnet</b><span>The chain as it grows, one lane per miner.</span></a>
|
||||
<a href="/explorer" data-nav="explorer"><b>Explorer</b><span>Look a block or an address up.</span></a>
|
||||
<a href="/journey" data-nav="journey"><b>The journey</b><span>Six phases, four gates, the log behind them.</span></a>
|
||||
<a href="/bench" data-nav="bench"><b>Engineering log</b><span>Every measurement, with the commands that made it.</span></a>
|
||||
<a href="/evidence" data-nav="evidence"><b>Evidence</b><span>Every claim and how far it is tested.</span></a>
|
||||
<a href="/light" data-nav="light"><b>Light wallet</b><span>A balance your browser proves, trusting no node.</span></a>
|
||||
<a href="/receipt" data-nav="receipt"><b>Payment receipt</b><span>A receipt any third party re-verifies offline.</span></a>
|
||||
<a href="/oracle" data-nav="oracle" aria-current="page"><b>State oracle on Sepolia</b><span>Devnet 3 balances read from another chain.</span></a>
|
||||
</div>
|
||||
<div class="sheet-group"><div class="sheet-head">Learn</div>
|
||||
<a href="/litepaper" data-nav="litepaper"><b>Litepaper</b><span>The design, as published.</span></a>
|
||||
<a href="/income" data-nav="income"><b>Income per tier</b><span>IGN a day per card at three network sizes, and the electricity.</span></a>
|
||||
<a href="/ledger" data-nav="ledger"><b>Ledger</b><span>Every criticism, answered or conceded.</span></a>
|
||||
<a href="/claims" data-nav="claims"><b>What Igneum does not claim</b><span>The limits, stated first.</span></a>
|
||||
<a href="/randomx" data-nav="randomx"><b>Igneum vs RandomX</b><span>What was kept and what was rebuilt for GPUs.</span></a>
|
||||
<a href="/provenance" data-nav="provenance"><b>Built on the shoulders</b><span>Every borrowed part, credited.</span></a>
|
||||
</div>
|
||||
<div class="sheet-group"><div class="sheet-head">Build</div>
|
||||
<a href="/build" data-nav="build"><b>Build on Igneum</b><span>Chain ids, RPC, a contract in five minutes.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Devnet faucet</b><span>10 IGN of devnet coin, once a day.</span></a>
|
||||
<a href="/swap" data-nav="swap"><b>Swap</b><span>Test tokens on Devnet 3; every swap is a proven block.</span></a>
|
||||
<a href="/grants" data-nav="grants"><b>Grants</b><span>Tooling, apps, infrastructure, research.</span></a>
|
||||
</div>
|
||||
<div class="sheet-foot">
|
||||
<a href="/download" class="btn primary big" data-nav="download">Download</a>
|
||||
<div class="sheet-social"><a href="https://discord.gg/igneum" target="_blank" rel="noopener">Discord</a><a href="https://git.igneum.network/igneum-network/spec" target="_blank" rel="noopener">Source</a><a href="https://www.reddit.com/user/Igneum_network/" target="_blank" rel="noopener">Reddit</a></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
<script>
|
||||
(function(){
|
||||
// the slim bar (site-ui-5, 7 Oct 2026): three group buttons open one panel each; the burger opens the sheet on phones.
|
||||
// Keyboard: Enter or Space opens a group, Escape closes it and returns focus to its button, arrows move between the
|
||||
// group buttons, Tab walks the open panel's links, a click outside closes. The theme toggle flips data-theme and stores it.
|
||||
var n=document.querySelector('.nav');if(!n)return;
|
||||
var btns=[].slice.call(n.querySelectorAll('.group-btn')),panels=[].slice.call(n.querySelectorAll('.nav-panel')),wrap=n.querySelector('.panels');
|
||||
var burger=document.getElementById('nav-burger'),sheet=document.getElementById('nav-sheet');
|
||||
function panelOf(g){return panels.filter(function(p){return p.getAttribute('data-group')===g;})[0];}
|
||||
function closeAll(focusBack){var was=null;btns.forEach(function(b){if(b.getAttribute('aria-expanded')==='true')was=b;b.setAttribute('aria-expanded','false');});panels.forEach(function(p){p.hidden=true;});n.classList.remove('panel-open');if(focusBack&&was)was.focus();}
|
||||
function open(g){closeAll(false);var b=btns.filter(function(x){return x.getAttribute('data-group')===g;})[0],p=panelOf(g);if(!b||!p)return;b.setAttribute('aria-expanded','true');p.hidden=false;n.classList.add('panel-open');anchor(b,p);}
|
||||
// the panel sits under its button; a panel that would run past the container's right edge aligns its right edge to the button's right edge instead (never past the viewport)
|
||||
function anchor(b,p){var pw=n.querySelector('.panel-wrap');if(!pw)return;var cr=pw.getBoundingClientRect(),br=b.getBoundingClientRect(),w=p.offsetWidth,left=br.left-cr.left;if(left+w>cr.width)left=(br.right-cr.left)-w;if(left<0)left=0;p.style.setProperty('--panel-left',Math.round(left)+'px');}
|
||||
window.addEventListener('resize',function(){var o=btns.filter(function(x){return x.getAttribute('aria-expanded')==='true';})[0];if(o)anchor(o,panelOf(o.getAttribute('data-group')));}); btns.forEach(function(b,i){
|
||||
b.addEventListener('click',function(){var on=b.getAttribute('aria-expanded')==='true';if(on)closeAll(false);else open(b.getAttribute('data-group'));});
|
||||
b.addEventListener('keydown',function(e){
|
||||
var k=e.key;
|
||||
if(k==='ArrowRight'||k==='ArrowLeft'){e.preventDefault();var j=(i+(k==='ArrowRight'?1:btns.length-1))%btns.length;btns[j].focus();if(n.classList.contains('panel-open'))open(btns[j].getAttribute('data-group'));}
|
||||
else if(k==='ArrowDown'){e.preventDefault();open(b.getAttribute('data-group'));var f=panelOf(b.getAttribute('data-group')).querySelector('a');if(f)f.focus();}
|
||||
else if(k==='Escape'){closeAll(true);}
|
||||
});
|
||||
});
|
||||
if(wrap)wrap.addEventListener('keydown',function(e){if(e.key==='Escape'){e.stopPropagation();closeAll(true);}});
|
||||
document.addEventListener('click',function(e){if(!n.classList.contains('panel-open'))return;if(e.target.closest('.group-btn')||e.target.closest('.nav-panel'))return;closeAll(false);});
|
||||
document.addEventListener('focusin',function(e){if(!n.classList.contains('panel-open'))return;if(n.contains(e.target))return;closeAll(false);});
|
||||
document.addEventListener('keydown',function(e){if(e.key==='Escape'&&n.classList.contains('panel-open'))closeAll(true);});
|
||||
// the sheet on phones
|
||||
function setSheet(o){if(!burger||!sheet)return;n.classList.toggle('open',o);sheet.hidden=!o;burger.setAttribute('aria-expanded',o?'true':'false');burger.setAttribute('aria-label',o?'Close the menu':'Open the menu');document.documentElement.classList.toggle('nav-locked',o);if(o){var f=sheet.querySelector('a');if(f)f.focus();}}
|
||||
if(burger&&sheet){
|
||||
burger.addEventListener('click',function(){setSheet(!n.classList.contains('open'));});
|
||||
sheet.addEventListener('click',function(e){if(e.target.closest('a'))setSheet(false);});
|
||||
sheet.addEventListener('keydown',function(e){
|
||||
if(e.key==='Escape'){setSheet(false);burger.focus();return;}
|
||||
if(e.key!=='Tab')return;var f=sheet.querySelectorAll('a,button');if(!f.length)return;var first=f[0],last=f[f.length-1];
|
||||
if(e.shiftKey&&document.activeElement===first){e.preventDefault();burger.focus();}else if(!e.shiftKey&&document.activeElement===last){e.preventDefault();burger.focus();}
|
||||
});
|
||||
burger.addEventListener('keydown',function(e){if(e.key==='Tab'&&!e.shiftKey&&n.classList.contains('open')){e.preventDefault();var f=sheet.querySelector('a');if(f)f.focus();}});
|
||||
var mq=window.matchMedia('(min-width:861px)');if(mq.addEventListener)mq.addEventListener('change',function(){setSheet(false);});
|
||||
}
|
||||
// the theme toggle
|
||||
var t=n.querySelector('[data-theme-toggle]');
|
||||
function paintToggle(){var dark=document.documentElement.getAttribute('data-theme')!=='light';t.setAttribute('aria-label',dark?'Switch to light theme':'Switch to dark theme');t.innerHTML=dark?'<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><circle cx="12" cy="12" r="4"/><path d="M12 2v2m0 16v2M2 12h2m16 0h2M5 5l1 1m12 12 1 1M5 19l1-1M18 6l1-1"/></svg>':'<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="M20.7 13.3A8.5 8.5 0 0 1 10.7 3.3 8.5 8.5 0 1 0 20.7 13.3Z"/></svg>';}
|
||||
if(t){t.addEventListener('click',function(){var v=document.documentElement.getAttribute('data-theme')==='light'?'dark':'light';document.documentElement.setAttribute('data-theme',v);try{localStorage.setItem('igneum-theme',v);}catch(e){}document.dispatchEvent(new CustomEvent('igneum-theme'));});paintToggle();document.addEventListener('igneum-theme',paintToggle);}
|
||||
})();
|
||||
</script>
|
||||
<!-- nav:end -->
|
||||
<main id="main" class="wrap">
|
||||
<div class="head">
|
||||
<div class="breadcrumb"><a href="/">Igneum</a><span>/</span><span>State oracle on Sepolia</span></div>
|
||||
<div class="eyebrow"><span class="line"></span>Reference app 3 · Devnet 3, no value</div>
|
||||
<h1>Devnet 3 balances, read from Sepolia<span class="accent">.</span></h1>
|
||||
</div>
|
||||
<p class="note">A contract on Ethereum Sepolia stores Igneum Devnet 3 finality certificates that anyone submits, checked by a shared certificate verifier, and state roots bound to those checkpoints through the header chain, the coinbase and the segment record. Other contracts then read a proven Devnet 3 balance or storage slot with an ordinary Merkle Patricia proof. No relayer is trusted: a wrong certificate or a wrong proof reverts.</p>
|
||||
|
||||
<div class="why">
|
||||
<p><b>Why this only works on a proven chain.</b> Another chain can only use Igneum state if a contract can check it without running an Igneum node: a weighted certificate over a checkpoint and a state root proven under it are small enough to verify in a few hundred thousand gas. A chain whose state is only "what most nodes say" has nothing a contract can check.</p>
|
||||
<p>Source: <code>tools/reference-apps/oracle/contracts/</code> (IgneumStateOracle.sol and its libraries), <code>tools/reference-apps/oracle/demo.mjs</code> (the demo that reads a Devnet 3 balance from Sepolia), <code>tools/reference-apps/oracle/test.mjs</code> (the negative cases through eth_call). The shared certificate verifier is the DEX lane's <code>contracts/bridge/src/IgneumCertificateVerifier.sol</code>.</p>
|
||||
</div>
|
||||
|
||||
<section class="card" aria-labelledby="deployed">
|
||||
<h2 id="deployed">On Sepolia</h2>
|
||||
<div class="kv" data-oracle-kv>
|
||||
<div class="k">Oracle</div><div class="mono" data-oracle-address>0xefe9879de29c401eeff195d5bf71c86b9caaa1b2 <small>IgneumStateOracle, deployed 8 October 2026 (tx 0xb8650f5b…d644, block 11869608)</small></div>
|
||||
<div class="k">Verifier</div><div class="mono" data-verifier-address>0xa197ef31d5d5613125779179668e2482ac69a6f6 <small>StubCertificateVerifier, the stand-in: it records any well-formed certificate and does not check the BLS signature; the shared IgneumCertificateVerifier replaces it through setVerifier the day it lands</small></div>
|
||||
<div class="k">Chain</div><div>Sepolia, chain id 11155111; Devnet 3 (igneum-devnet-3), no value</div>
|
||||
<div class="k">First proven root</div><div class="mono">Devnet 3 chain block 26631, post_root 0xf567a84f…a82fd, stored 8 October 2026 (tx 0xf360e54c…224b, 404,376 gas); provenBalance read 92.029323 IGN for 0x636de2dc…44ea on Sepolia, equal to the Devnet 3 node's eth_getProof</div>
|
||||
</div>
|
||||
<p class="note">How to read a balance from another contract: <code>IIgneumStateOracle(oracle).provenBalance(number, account, accountProof)</code>, where <code>number</code> is a Devnet 3 chain block whose state root the oracle holds and <code>accountProof</code> is the <code>eth_getProof</code> account proof at that block. A storage slot: <code>provenStorage(number, account, slot, accountProof, storageProof)</code>. Both revert on any mismatch.</p>
|
||||
</section>
|
||||
|
||||
<h2 id="checked">What the contract checks</h2>
|
||||
<ol>
|
||||
<li>The certificate, through the shared verifier: the aggregate BLS signature over the checkpoint under the installed voter table and the weight rule.</li>
|
||||
<li>The header path from the carrier block up to the certified checkpoint: BLAKE2b-256 keyed BlockHash through the precompile, every parent link.</li>
|
||||
<li>The coinbase transaction under the carrier's <code>hash_merkle_root</code>, and the segment record parsed out of its extra data: the record's <code>post_root</code> for its block is stored under the certificate's index.</li>
|
||||
<li>Every read: a keccak-keyed Merkle Patricia proof against the stored root, verified on chain.</li>
|
||||
</ol>
|
||||
<p class="note">Said plainly, on the contract too (<code>trust()</code>): the aggregator's BLS signature on the record is not checked on chain in this slice, and while the stand-in verifier is installed no certificate signature is checked on chain either; the voter table the shared verifier holds is installed by its deployer. Gas on Sepolia, measured 8 October 2026: a 62-header path 13.3 million (about 215,000 per header, 15 precompile blocks each), a 10-header path about 2.2 million, the state-root store 177,000, a balance read 153,000. The negative cases in <code>test.mjs</code> are a flipped proof node, a wrong block number, a header removed from the path, a merkle sibling altered, a record with its <code>post_root</code> altered, a header with its nonce altered: each reverts.</p>
|
||||
<p class="asof">Devnet 3, no value. Sepolia, no value. A demonstration of the verification path, not a product.</p>
|
||||
</main>
|
||||
<!-- footer:start -->
|
||||
<footer class="site-footer">
|
||||
<div class="container">
|
||||
<div class="footer-grid">
|
||||
<div class="footer-brand">
|
||||
<a href="/" class="logo" aria-label="Igneum home"><svg class="brand-mark" viewBox="0 0 1024 1024" aria-hidden="true"><rect width="1024" height="1024" rx="160" fill="#0C0C0E"></rect><g transform="translate(166.95 166.95) scale(6.901)"><polygon points="50,4 74,34 67,58 80,54 61,96 39,96 20,54 33,58 26,34" fill="#F2541B"></polygon><polygon points="50,42 59,58 50,82 41,58" fill="#0C0C0E"></polygon></g></svg><span class="word">IGNEUM</span><span class="stop">.</span></a>
|
||||
<p>Mined by GPUs. Proven by fire.</p>
|
||||
<div class="social" aria-label="Igneum elsewhere">
|
||||
<a href="https://git.igneum.network/igneum-network/spec" target="_blank" rel="noopener" aria-label="Igneum source: the spec, the vectors and the issues"><svg viewBox="0 0 24 24" width="22" height="22" fill="currentColor" aria-hidden="true"><path d="M8.6 17.6 3 12l5.6-5.6 1.4 1.4L5.8 12l4.2 4.2zm6.8 0-1.4-1.4L18.2 12 14 7.8l1.4-1.4L21 12z"></path></svg></a>
|
||||
<a href="https://discord.gg/igneum" target="_blank" rel="noopener" aria-label="The Igneum Discord"><svg viewBox="0 0 24 24" width="22" height="22" fill="currentColor" aria-hidden="true"><path d="M19.6 5.3A17 17 0 0 0 15.4 4l-.2.4a15.6 15.6 0 0 1 3.9 1.9 13.6 13.6 0 0 0-14.2 0A15.6 15.6 0 0 1 8.8 4.4L8.6 4a17 17 0 0 0-4.2 1.3C1.8 9.2 1.1 13 1.4 16.7a17.1 17.1 0 0 0 5.2 2.6l1.1-1.8a10.8 10.8 0 0 1-1.7-.8l.4-.3a12.2 12.2 0 0 0 11.2 0l.4.3-1.7.8 1.1 1.8a17 17 0 0 0 5.2-2.6c.4-4.3-.7-8-3-11.4zM8.7 14.4c-1 0-1.8-.9-1.8-2.1s.8-2.1 1.8-2.1 1.9 1 1.8 2.1c0 1.2-.8 2.1-1.8 2.1zm6.6 0c-1 0-1.8-.9-1.8-2.1s.8-2.1 1.8-2.1 1.9 1 1.8 2.1c0 1.2-.8 2.1-1.8 2.1z"></path></svg></a>
|
||||
<a data-social="reddit" href="https://www.reddit.com/user/Igneum_network/" target="_blank" rel="noopener" aria-label="Igneum on Reddit"><svg viewBox="0 0 24 24" width="22" height="22" fill="currentColor" aria-hidden="true"><path d="M22 12.1a2.2 2.2 0 0 0-3.7-1.6 10.8 10.8 0 0 0-5.8-1.8l1-4.6 3.2.7a1.5 1.5 0 1 0 .2-.9l-3.6-.8a.5.5 0 0 0-.5.4l-1.1 5.2a10.8 10.8 0 0 0-5.9 1.8A2.2 2.2 0 1 0 3.4 14a4.3 4.3 0 0 0 0 .7c0 3.4 3.9 6.1 8.6 6.1s8.6-2.7 8.6-6.1a4.3 4.3 0 0 0 0-.7 2.2 2.2 0 0 0 1.4-1.9zM7 13.6a1.5 1.5 0 1 1 1.5 1.5A1.5 1.5 0 0 1 7 13.6zm8.6 4.1a5.7 5.7 0 0 1-3.6 1.1 5.7 5.7 0 0 1-3.6-1.1.4.4 0 0 1 .6-.6 4.9 4.9 0 0 0 3 .9 4.9 4.9 0 0 0 3-.9.4.4 0 0 1 .6.6zm-.3-2.6a1.5 1.5 0 1 1 1.5-1.5 1.5 1.5 0 0 1-1.5 1.5z"></path></svg></a>
|
||||
</div>
|
||||
<div class="footer-dl" aria-label="Download Ember"><a href="/download#windows"><span class="osmark mini" data-os="windows" title="Windows"><svg viewBox="0 0 24 24" width="22" height="22" aria-hidden="true" focusable="false" fill="currentColor"><path d="M3 5.6l7.3-1v7.1H3zM11.4 4.4L21 3v8.7h-9.6zM3 12.3h7.3v7.1L3 18.4zM11.4 12.3H21V21l-9.6-1.4z"/></svg></span>Windows</a><a href="/download#mac"><span class="osmark mini" data-os="mac" title="macOS"><svg viewBox="0 0 24 24" width="22" height="22" aria-hidden="true" focusable="false" fill="currentColor"><path d="M16.4 12.6c0-2.5 2-3.6 2.1-3.7-1.2-1.7-3-1.9-3.6-2-1.5-.2-3 .9-3.8.9-.8 0-2-.9-3.3-.8-1.7 0-3.2 1-4.1 2.5-1.8 3-.5 7.6 1.3 10.1.9 1.2 1.9 2.6 3.2 2.5 1.3 0 1.8-.8 3.3-.8 1.6 0 2 .8 3.3.8 1.4 0 2.3-1.2 3.1-2.5 1-1.4 1.4-2.8 1.4-2.9 0 0-2.7-1-2.9-4.1zM13.9 5.3c.7-.8 1.2-2 1-3.2-1 0-2.2.7-2.9 1.5-.6.7-1.2 1.9-1 3 1.1.1 2.2-.5 2.9-1.3z"/></svg></span>macOS</a><a href="/download#linux"><span class="osmark mini" data-os="linux" title="Linux"><svg viewBox="0 0 24 24" width="22" height="22" aria-hidden="true" focusable="false" fill="currentColor"><path d="M12 2c-2.4 0-4 1.9-4 4.6 0 1.2.2 2 0 2.8-.6 1.4-2.1 2.9-2.6 4.9-.3 1.1-.1 2 .3 2.6-.6.4-1.3 1-1.1 1.7.3 1 2.1 1.2 3.2 1.8.7.4 1.5.6 2.1.1.6.2 1.3.3 2.1.3s1.5-.1 2.1-.3c.6.5 1.4.3 2.1-.1 1.1-.6 2.9-.8 3.2-1.8.2-.7-.5-1.3-1.1-1.7.4-.6.6-1.5.3-2.6-.5-2-2-3.5-2.6-4.9-.2-.8 0-1.6 0-2.8C16 3.9 14.4 2 12 2zm-1.4 4.2c.5 0 .8.5.8 1.2s-.3 1.2-.8 1.2-.8-.5-.8-1.2.3-1.2.8-1.2zm2.8 0c.5 0 .8.5.8 1.2s-.3 1.2-.8 1.2-.8-.5-.8-1.2.3-1.2.8-1.2zM12 9.3c.9 0 1.9.5 1.9 1s-1 1.2-1.9 1.2-1.9-.7-1.9-1.2 1-1 1.9-1zm0 3.4c2.2 0 3.6 2.6 3.6 4.4 0 1.5-1.6 2.3-3.6 2.3s-3.6-.8-3.6-2.3c0-1.8 1.4-4.4 3.6-4.4z"/></svg></span>Linux</a><a href="/download#hive"><span class="osmark mini" data-os="hive" title="HiveOS"><svg viewBox="0 0 24 24" width="22" height="22" aria-hidden="true" focusable="false" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linejoin="round" stroke-linecap="round"><path d="M12 2.6 20.2 7.3v9.4L12 21.4 3.8 16.7V7.3z"/><path d="M12 7.4 16 9.7v4.6L12 16.6 8 14.3V9.7z"/><path d="M12 7.4V2.6M16 9.7l4.2-2.4M16 14.3l4.2 2.4M12 16.6v4.8M8 14.3l-4.2 2.4M8 9.7 3.8 7.3"/></svg></span>HiveOS</a></div>
|
||||
<a href="https://git.igneum.network/igneum-network/spec" target="_blank" rel="noopener" class="text-link">Specification and test vectors<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="M6 18 18 6M6 6h12v12"/></svg></a>
|
||||
</div>
|
||||
<div class="footer-column"><h4>Run</h4><div>
|
||||
<a href="/download">Download Ember</a>
|
||||
<a href="/miner">The miner</a>
|
||||
<a href="/app">The app</a>
|
||||
<a href="/wallet">The wallet</a>
|
||||
<a href="/miners">GPU bench table</a>
|
||||
<a href="/dev-fee">The dev fee</a>
|
||||
<a href="/faucet">Devnet faucet</a>
|
||||
<a href="/metamask">Add Igneum to MetaMask</a>
|
||||
</div></div>
|
||||
<div class="footer-column"><h4>Read</h4><div>
|
||||
<a href="/litepaper">Litepaper</a>
|
||||
<a href="/evidence">Evidence</a>
|
||||
<a href="/bench">Engineering log</a>
|
||||
<a href="/ledger">Ledger: every criticism</a>
|
||||
<a href="/claims">What Igneum does not claim</a>
|
||||
<a href="/randomx">Igneum vs RandomX</a>
|
||||
<a href="/provenance">Built on the shoulders</a>
|
||||
</div></div>
|
||||
<div class="footer-column"><h4>Explore</h4><div>
|
||||
<a href="/live">Live devnet</a>
|
||||
<a href="/explorer">Explorer</a>
|
||||
<a href="/build">Build on Igneum</a>
|
||||
<a href="/swap">Swap</a>
|
||||
<a href="/grants">Grants</a>
|
||||
<a href="/journey">Journey</a>
|
||||
<a href="/download">Downloads: devnet build</a>
|
||||
<a href="https://discord.gg/igneum" target="_blank" rel="noopener">Community Discord</a>
|
||||
<a href="mailto:hello@igneum.network">hello@igneum.network</a>
|
||||
<a href="https://git.igneum.network/igneum-network/spec/issues" rel="noopener">An issue on the spec</a>
|
||||
</div></div>
|
||||
</div>
|
||||
<div class="footer-bottom">
|
||||
<p>Igneum Labs LTD · Unit IH-00-01-01-OF-01, Level 01, Innovation One, Dubai International Financial Centre. Experimental software. Nothing on this site is an offer to sell anything.<br>Report a flaw by email or by an issue on the spec. Nobody from Igneum will ask for your seed. © 2026 Igneum · not an offer to sell anything</p>
|
||||
<div class="theme-group" role="group" aria-label="Theme"><button type="button" data-theme-set="system" aria-pressed="true">System</button><button type="button" data-theme-set="light" aria-pressed="false">Light</button><button type="button" data-theme-set="dark" aria-pressed="false">Dark</button></div>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
<script>
|
||||
(function(){
|
||||
// theme control: stores light or dark under igneum-theme; system clears it and follows the OS. The head applied the value before paint.
|
||||
var bs=document.querySelectorAll('[data-theme-set]');if(!bs.length)return;
|
||||
var media=window.matchMedia('(prefers-color-scheme: light)');
|
||||
function stored(){try{var t=localStorage.getItem('igneum-theme');return t==='light'||t==='dark'?t:'system';}catch(e){return 'system';}}
|
||||
function apply(){var c=stored();document.documentElement.setAttribute('data-theme',c==='system'?(media.matches?'light':'dark'):c);bs.forEach(function(b){b.setAttribute('aria-pressed',b.getAttribute('data-theme-set')===c?'true':'false');});document.dispatchEvent(new CustomEvent('igneum-theme'));}
|
||||
bs.forEach(function(b){b.addEventListener('click',function(){var v=b.getAttribute('data-theme-set');try{if(v==='system')localStorage.removeItem('igneum-theme');else localStorage.setItem('igneum-theme',v);}catch(e){}apply();});});
|
||||
if(media.addEventListener)media.addEventListener('change',function(){if(stored()==='system')apply();});
|
||||
document.addEventListener('igneum-theme',function(){var c=stored();bs.forEach(function(b){b.setAttribute('aria-pressed',b.getAttribute('data-theme-set')===c?'true':'false');});});
|
||||
bs.forEach(function(b){b.setAttribute('aria-pressed',b.getAttribute('data-theme-set')===stored()?'true':'false');});
|
||||
// the network state word in the status bar: one read of the observer per page view
|
||||
var fs=document.getElementById('foot-state'),fd=document.getElementById('foot-dot');if(fs&&fd){fetch('/api/live?window=30',{cache:'no-store'}).then(function(r){return r.json();}).then(function(d){var on=d&&d.ok&&d.state&&!d.state.stale;fs.textContent=on?'devnet live':'devnet, observer stale';fd.className='dot '+(on?'live':'off');}).catch(function(){fs.textContent='devnet';});}
|
||||
})();
|
||||
</script>
|
||||
<!-- footer:end -->
|
||||
<script>
|
||||
(function(){
|
||||
// one request per button; the wallet shows the chain to the user and decides. No key, no seed, no signature here.
|
||||
var CHAINS = {
|
||||
testnet: { chainId: '0x116e', chainName: 'Igneum Testnet', nativeCurrency: { name: 'Igneum', symbol: 'IGN', decimals: 18 }, rpcUrls: ['https://rpc.testnet.igneum.network'], blockExplorerUrls: [] },
|
||||
devnet: { chainId: '0x116f', chainName: 'Igneum Devnet (local node)', nativeCurrency: { name: 'Igneum', symbol: 'IGN', decimals: 18 }, rpcUrls: ['http://127.0.0.1:26790'], blockExplorerUrls: [] }
|
||||
};
|
||||
function status(name, text) { var el = document.querySelector('[data-status="' + name + '"]'); if (el) el.textContent = text; }
|
||||
Array.prototype.forEach.call(document.querySelectorAll('[data-add]'), function (btn) {
|
||||
btn.addEventListener('click', function () {
|
||||
var name = btn.getAttribute('data-add'); var chain = CHAINS[name];
|
||||
if (!window.ethereum || !window.ethereum.request) { status(name, 'No Ethereum wallet found in this browser. Install MetaMask, or add the network by hand (below).'); return; }
|
||||
status(name, 'Waiting for the wallet...');
|
||||
window.ethereum.request({ method: 'wallet_addEthereumChain', params: [chain] })
|
||||
.then(function () { status(name, 'Added. The wallet is on ' + chain.chainName + ' (chain id ' + parseInt(chain.chainId, 16) + ').'); })
|
||||
.catch(function (e) { status(name, e && e.code === 4001 ? 'Cancelled in the wallet.' : 'The wallet refused: ' + ((e && e.message) || 'unknown error') + '. Add it by hand (below).'); });
|
||||
});
|
||||
});
|
||||
})();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -19,7 +19,7 @@
|
|||
<a href="/wallet">The wallet</a>
|
||||
<a href="/miners">GPU bench table</a>
|
||||
<a href="/dev-fee">The dev fee</a>
|
||||
<a href="/faucet">Testnet faucet</a>
|
||||
<a href="/faucet">Devnet faucet</a>
|
||||
<a href="/metamask">Add Igneum to MetaMask</a>
|
||||
</div></div>
|
||||
<div class="footer-column"><h4>Read</h4><div>
|
||||
|
|
@ -34,6 +34,9 @@
|
|||
<div class="footer-column"><h4>Explore</h4><div>
|
||||
<a href="/live">Live devnet</a>
|
||||
<a href="/explorer">Explorer</a>
|
||||
<a href="/build">Build on Igneum</a>
|
||||
<a href="/swap">Swap</a>
|
||||
<a href="/grants">Grants</a>
|
||||
<a href="/journey">Journey</a>
|
||||
<a href="/download">Downloads: devnet build</a>
|
||||
<a href="https://discord.gg/igneum" target="_blank" rel="noopener">Community Discord</a>
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-mine" data-group="mine" aria-expanded="false" aria-controls="nav-panel-mine" aria-haspopup="true">Mine<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-network" data-group="network" aria-expanded="false" aria-controls="nav-panel-network" aria-haspopup="true">Network<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-learn" data-group="learn" aria-expanded="false" aria-controls="nav-panel-learn" aria-haspopup="true">Learn<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-build" data-group="build" aria-expanded="false" aria-controls="nav-panel-build" aria-haspopup="true">Build<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
</div>
|
||||
<div class="nav-controls">
|
||||
<button class="btn icon-btn" type="button" data-theme-toggle aria-label="Switch to light theme"><svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><circle cx="12" cy="12" r="4"/><path d="M12 2v2m0 16v2M2 12h2m16 0h2M5 5l1 1m12 12 1 1M5 19l1-1M18 6l1-1"/></svg></button>
|
||||
|
|
@ -27,7 +28,6 @@
|
|||
<a href="/wallet" data-nav="wallet"><b>The wallet</b><span>Your coins. Final means final.</span></a>
|
||||
<a href="/miners" data-nav="miners"><b>GPU bench table</b><span>Measured rates, card by card.</span></a>
|
||||
<a href="/dev-fee" data-nav="dev-fee"><b>The dev fee</b><span>The optional one, in full view, off with one flag.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Testnet faucet</b><span>Test coin for an address, once a day.</span></a>
|
||||
<a href="/metamask" data-nav="metamask"><b>Add to MetaMask</b><span>Igneum as a network in your wallet.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -38,6 +38,9 @@
|
|||
<a href="/journey" data-nav="journey"><b>The journey</b><span>Six phases, four gates, the log behind them.</span></a>
|
||||
<a href="/bench" data-nav="bench"><b>Engineering log</b><span>Every measurement, with the commands that made it.</span></a>
|
||||
<a href="/evidence" data-nav="evidence"><b>Evidence</b><span>Every claim and how far it is tested.</span></a>
|
||||
<a href="/light" data-nav="light"><b>Light wallet</b><span>A balance your browser proves, trusting no node.</span></a>
|
||||
<a href="/receipt" data-nav="receipt"><b>Payment receipt</b><span>A receipt any third party re-verifies offline.</span></a>
|
||||
<a href="/oracle" data-nav="oracle"><b>State oracle on Sepolia</b><span>Devnet 3 balances read from another chain.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-panel" id="nav-panel-learn" data-group="learn" role="region" aria-labelledby="nav-btn-learn" hidden>
|
||||
|
|
@ -50,6 +53,14 @@
|
|||
<a href="/provenance" data-nav="provenance"><b>Built on the shoulders</b><span>Every borrowed part, credited.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-panel" id="nav-panel-build" data-group="build" role="region" aria-labelledby="nav-btn-build" hidden>
|
||||
<div class="panel-list">
|
||||
<a href="/build" data-nav="build"><b>Build on Igneum</b><span>Chain ids, RPC, a contract in five minutes.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Devnet faucet</b><span>10 IGN of devnet coin, once a day.</span></a>
|
||||
<a href="/swap" data-nav="swap"><b>Swap</b><span>Test tokens on Devnet 3; every swap is a proven block.</span></a>
|
||||
<a href="/grants" data-nav="grants"><b>Grants</b><span>Tooling, apps, infrastructure, research.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-sheet" id="nav-sheet" role="dialog" aria-modal="true" aria-label="Menu" hidden>
|
||||
|
|
@ -61,7 +72,6 @@
|
|||
<a href="/wallet" data-nav="wallet"><b>The wallet</b><span>Your coins. Final means final.</span></a>
|
||||
<a href="/miners" data-nav="miners"><b>GPU bench table</b><span>Measured rates, card by card.</span></a>
|
||||
<a href="/dev-fee" data-nav="dev-fee"><b>The dev fee</b><span>The optional one, in full view, off with one flag.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Testnet faucet</b><span>Test coin for an address, once a day.</span></a>
|
||||
<a href="/metamask" data-nav="metamask"><b>Add to MetaMask</b><span>Igneum as a network in your wallet.</span></a>
|
||||
</div>
|
||||
<div class="sheet-group"><div class="sheet-head">Network</div>
|
||||
|
|
@ -70,6 +80,9 @@
|
|||
<a href="/journey" data-nav="journey"><b>The journey</b><span>Six phases, four gates, the log behind them.</span></a>
|
||||
<a href="/bench" data-nav="bench"><b>Engineering log</b><span>Every measurement, with the commands that made it.</span></a>
|
||||
<a href="/evidence" data-nav="evidence"><b>Evidence</b><span>Every claim and how far it is tested.</span></a>
|
||||
<a href="/light" data-nav="light"><b>Light wallet</b><span>A balance your browser proves, trusting no node.</span></a>
|
||||
<a href="/receipt" data-nav="receipt"><b>Payment receipt</b><span>A receipt any third party re-verifies offline.</span></a>
|
||||
<a href="/oracle" data-nav="oracle"><b>State oracle on Sepolia</b><span>Devnet 3 balances read from another chain.</span></a>
|
||||
</div>
|
||||
<div class="sheet-group"><div class="sheet-head">Learn</div>
|
||||
<a href="/litepaper" data-nav="litepaper"><b>Litepaper</b><span>The design, as published.</span></a>
|
||||
|
|
@ -79,6 +92,12 @@
|
|||
<a href="/randomx" data-nav="randomx"><b>Igneum vs RandomX</b><span>What was kept and what was rebuilt for GPUs.</span></a>
|
||||
<a href="/provenance" data-nav="provenance"><b>Built on the shoulders</b><span>Every borrowed part, credited.</span></a>
|
||||
</div>
|
||||
<div class="sheet-group"><div class="sheet-head">Build</div>
|
||||
<a href="/build" data-nav="build"><b>Build on Igneum</b><span>Chain ids, RPC, a contract in five minutes.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Devnet faucet</b><span>10 IGN of devnet coin, once a day.</span></a>
|
||||
<a href="/swap" data-nav="swap"><b>Swap</b><span>Test tokens on Devnet 3; every swap is a proven block.</span></a>
|
||||
<a href="/grants" data-nav="grants"><b>Grants</b><span>Tooling, apps, infrastructure, research.</span></a>
|
||||
</div>
|
||||
<div class="sheet-foot">
|
||||
<a href="/download" class="btn primary big" data-nav="download">Download</a>
|
||||
<div class="sheet-social"><a href="https://discord.gg/igneum" target="_blank" rel="noopener">Discord</a><a href="https://git.igneum.network/igneum-network/spec" target="_blank" rel="noopener">Source</a><a href="https://www.reddit.com/user/Igneum_network/" target="_blank" rel="noopener">Reddit</a></div>
|
||||
|
|
|
|||
|
|
@ -87,6 +87,7 @@ table{min-width:560px}
|
|||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-mine" data-group="mine" aria-expanded="false" aria-controls="nav-panel-mine" aria-haspopup="true">Mine<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-network" data-group="network" aria-expanded="false" aria-controls="nav-panel-network" aria-haspopup="true">Network<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-learn" data-group="learn" data-active aria-expanded="false" aria-controls="nav-panel-learn" aria-haspopup="true">Learn<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-build" data-group="build" aria-expanded="false" aria-controls="nav-panel-build" aria-haspopup="true">Build<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
</div>
|
||||
<div class="nav-controls">
|
||||
<button class="btn icon-btn" type="button" data-theme-toggle aria-label="Switch to light theme"><svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><circle cx="12" cy="12" r="4"/><path d="M12 2v2m0 16v2M2 12h2m16 0h2M5 5l1 1m12 12 1 1M5 19l1-1M18 6l1-1"/></svg></button>
|
||||
|
|
@ -104,7 +105,6 @@ table{min-width:560px}
|
|||
<a href="/wallet" data-nav="wallet"><b>The wallet</b><span>Your coins. Final means final.</span></a>
|
||||
<a href="/miners" data-nav="miners"><b>GPU bench table</b><span>Measured rates, card by card.</span></a>
|
||||
<a href="/dev-fee" data-nav="dev-fee"><b>The dev fee</b><span>The optional one, in full view, off with one flag.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Testnet faucet</b><span>Test coin for an address, once a day.</span></a>
|
||||
<a href="/metamask" data-nav="metamask"><b>Add to MetaMask</b><span>Igneum as a network in your wallet.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -115,6 +115,9 @@ table{min-width:560px}
|
|||
<a href="/journey" data-nav="journey"><b>The journey</b><span>Six phases, four gates, the log behind them.</span></a>
|
||||
<a href="/bench" data-nav="bench"><b>Engineering log</b><span>Every measurement, with the commands that made it.</span></a>
|
||||
<a href="/evidence" data-nav="evidence"><b>Evidence</b><span>Every claim and how far it is tested.</span></a>
|
||||
<a href="/light" data-nav="light"><b>Light wallet</b><span>A balance your browser proves, trusting no node.</span></a>
|
||||
<a href="/receipt" data-nav="receipt"><b>Payment receipt</b><span>A receipt any third party re-verifies offline.</span></a>
|
||||
<a href="/oracle" data-nav="oracle"><b>State oracle on Sepolia</b><span>Devnet 3 balances read from another chain.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-panel" id="nav-panel-learn" data-group="learn" role="region" aria-labelledby="nav-btn-learn" hidden>
|
||||
|
|
@ -127,6 +130,14 @@ table{min-width:560px}
|
|||
<a href="/provenance" data-nav="provenance" aria-current="page"><b>Built on the shoulders</b><span>Every borrowed part, credited.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-panel" id="nav-panel-build" data-group="build" role="region" aria-labelledby="nav-btn-build" hidden>
|
||||
<div class="panel-list">
|
||||
<a href="/build" data-nav="build"><b>Build on Igneum</b><span>Chain ids, RPC, a contract in five minutes.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Devnet faucet</b><span>10 IGN of devnet coin, once a day.</span></a>
|
||||
<a href="/swap" data-nav="swap"><b>Swap</b><span>Test tokens on Devnet 3; every swap is a proven block.</span></a>
|
||||
<a href="/grants" data-nav="grants"><b>Grants</b><span>Tooling, apps, infrastructure, research.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-sheet" id="nav-sheet" role="dialog" aria-modal="true" aria-label="Menu" hidden>
|
||||
|
|
@ -138,7 +149,6 @@ table{min-width:560px}
|
|||
<a href="/wallet" data-nav="wallet"><b>The wallet</b><span>Your coins. Final means final.</span></a>
|
||||
<a href="/miners" data-nav="miners"><b>GPU bench table</b><span>Measured rates, card by card.</span></a>
|
||||
<a href="/dev-fee" data-nav="dev-fee"><b>The dev fee</b><span>The optional one, in full view, off with one flag.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Testnet faucet</b><span>Test coin for an address, once a day.</span></a>
|
||||
<a href="/metamask" data-nav="metamask"><b>Add to MetaMask</b><span>Igneum as a network in your wallet.</span></a>
|
||||
</div>
|
||||
<div class="sheet-group"><div class="sheet-head">Network</div>
|
||||
|
|
@ -147,6 +157,9 @@ table{min-width:560px}
|
|||
<a href="/journey" data-nav="journey"><b>The journey</b><span>Six phases, four gates, the log behind them.</span></a>
|
||||
<a href="/bench" data-nav="bench"><b>Engineering log</b><span>Every measurement, with the commands that made it.</span></a>
|
||||
<a href="/evidence" data-nav="evidence"><b>Evidence</b><span>Every claim and how far it is tested.</span></a>
|
||||
<a href="/light" data-nav="light"><b>Light wallet</b><span>A balance your browser proves, trusting no node.</span></a>
|
||||
<a href="/receipt" data-nav="receipt"><b>Payment receipt</b><span>A receipt any third party re-verifies offline.</span></a>
|
||||
<a href="/oracle" data-nav="oracle"><b>State oracle on Sepolia</b><span>Devnet 3 balances read from another chain.</span></a>
|
||||
</div>
|
||||
<div class="sheet-group"><div class="sheet-head">Learn</div>
|
||||
<a href="/litepaper" data-nav="litepaper"><b>Litepaper</b><span>The design, as published.</span></a>
|
||||
|
|
@ -156,6 +169,12 @@ table{min-width:560px}
|
|||
<a href="/randomx" data-nav="randomx"><b>Igneum vs RandomX</b><span>What was kept and what was rebuilt for GPUs.</span></a>
|
||||
<a href="/provenance" data-nav="provenance" aria-current="page"><b>Built on the shoulders</b><span>Every borrowed part, credited.</span></a>
|
||||
</div>
|
||||
<div class="sheet-group"><div class="sheet-head">Build</div>
|
||||
<a href="/build" data-nav="build"><b>Build on Igneum</b><span>Chain ids, RPC, a contract in five minutes.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Devnet faucet</b><span>10 IGN of devnet coin, once a day.</span></a>
|
||||
<a href="/swap" data-nav="swap"><b>Swap</b><span>Test tokens on Devnet 3; every swap is a proven block.</span></a>
|
||||
<a href="/grants" data-nav="grants"><b>Grants</b><span>Tooling, apps, infrastructure, research.</span></a>
|
||||
</div>
|
||||
<div class="sheet-foot">
|
||||
<a href="/download" class="btn primary big" data-nav="download">Download</a>
|
||||
<div class="sheet-social"><a href="https://discord.gg/igneum" target="_blank" rel="noopener">Discord</a><a href="https://git.igneum.network/igneum-network/spec" target="_blank" rel="noopener">Source</a><a href="https://www.reddit.com/user/Igneum_network/" target="_blank" rel="noopener">Reddit</a></div>
|
||||
|
|
@ -269,7 +288,7 @@ table{min-width:560px}
|
|||
<a href="/wallet">The wallet</a>
|
||||
<a href="/miners">GPU bench table</a>
|
||||
<a href="/dev-fee">The dev fee</a>
|
||||
<a href="/faucet">Testnet faucet</a>
|
||||
<a href="/faucet">Devnet faucet</a>
|
||||
<a href="/metamask">Add Igneum to MetaMask</a>
|
||||
</div></div>
|
||||
<div class="footer-column"><h4>Read</h4><div>
|
||||
|
|
@ -284,6 +303,9 @@ table{min-width:560px}
|
|||
<div class="footer-column"><h4>Explore</h4><div>
|
||||
<a href="/live">Live devnet</a>
|
||||
<a href="/explorer">Explorer</a>
|
||||
<a href="/build">Build on Igneum</a>
|
||||
<a href="/swap">Swap</a>
|
||||
<a href="/grants">Grants</a>
|
||||
<a href="/journey">Journey</a>
|
||||
<a href="/download">Downloads: devnet build</a>
|
||||
<a href="https://discord.gg/igneum" target="_blank" rel="noopener">Community Discord</a>
|
||||
|
|
|
|||
403
site/proving.html
Normal file
403
site/proving.html
Normal file
|
|
@ -0,0 +1,403 @@
|
|||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
|
||||
<title>Igneum Devnet 3 proving</title>
|
||||
<meta name="description" content="Proving on Devnet 3: the shard plan of every chain block, who proved what, the payouts and the block-to-paid latency.">
|
||||
<link rel="canonical" href="https://igneum.network/proving">
|
||||
<meta name="theme-color" content="#0C0C0E">
|
||||
<meta property="og:type" content="website">
|
||||
<meta property="og:site_name" content="Igneum">
|
||||
<meta property="og:title" content="Igneum Devnet 3 proving">
|
||||
<meta property="og:description" content="Proving on Devnet 3: the shard plan of every chain block, who proved what, the payouts and the block-to-paid latency.">
|
||||
<meta property="og:url" content="https://igneum.network/proving">
|
||||
<meta property="og:image" content="https://igneum.network/og-small.png?v=3">
|
||||
<meta property="og:image:width" content="256">
|
||||
<meta property="og:image:height" content="256">
|
||||
<meta property="og:image:alt" content="Igneum. Mined by GPUs. Proven by fire.">
|
||||
<meta name="twitter:card" content="summary">
|
||||
<meta name="twitter:title" content="Igneum Devnet 3 proving">
|
||||
<meta name="twitter:description" content="Proving on Devnet 3: the shard plan of every chain block, who proved what, the payouts and the block-to-paid latency.">
|
||||
<meta name="twitter:image" content="https://igneum.network/og-small.png?v=3">
|
||||
<meta name="twitter:image:alt" content="Igneum. Mined by GPUs. Proven by fire.">
|
||||
<link rel="icon" href="/favicon.ico" sizes="48x48">
|
||||
<link rel="icon" href="/favicon-32.png" type="image/png" sizes="32x32">
|
||||
<link rel="apple-touch-icon" href="/apple-touch-icon.png" sizes="180x180">
|
||||
<link rel="manifest" href="/site.webmanifest">
|
||||
<!-- head:start -->
|
||||
<link rel="preload" href="/fonts/unbounded-900.woff2" as="font" type="font/woff2" crossorigin>
|
||||
<link rel="preload" href="/fonts/plex-sans-400.woff2" as="font" type="font/woff2" crossorigin>
|
||||
<meta name="color-scheme" content="dark light">
|
||||
<link rel="stylesheet" href="/site.css">
|
||||
<style>
|
||||
/* Shared by every page: the head partial, injected by the build between the head markers. Edit the partial, not the page. */
|
||||
/* Fonts, self-hosted (latin subsets, OFL): Unbounded 500/700/900, IBM Plex Sans 400/500/600, IBM Plex Mono 400/500. Fallbacks carry size and ascent overrides so the swap does not move the layout. The tokens, type and components are in /site.css (docs/plans/site-ui-3.md). */
|
||||
@font-face{font-family:'Unbounded';font-style:normal;font-weight:500;font-display:swap;src:url(/fonts/unbounded-500.woff2) format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
|
||||
@font-face{font-family:'Unbounded';font-style:normal;font-weight:700;font-display:swap;src:url(/fonts/unbounded-700.woff2) format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
|
||||
@font-face{font-family:'Unbounded';font-style:normal;font-weight:900;font-display:swap;src:url(/fonts/unbounded-900.woff2) format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
|
||||
@font-face{font-family:'IBM Plex Sans';font-style:normal;font-weight:400;font-display:swap;src:url(/fonts/plex-sans-400.woff2) format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
|
||||
@font-face{font-family:'IBM Plex Sans';font-style:normal;font-weight:500;font-display:swap;src:url(/fonts/plex-sans-500.woff2) format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
|
||||
@font-face{font-family:'IBM Plex Sans';font-style:normal;font-weight:600;font-display:swap;src:url(/fonts/plex-sans-600.woff2) format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
|
||||
@font-face{font-family:'IBM Plex Mono';font-style:normal;font-weight:400;font-display:swap;src:url(/fonts/plex-mono-400.woff2) format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
|
||||
@font-face{font-family:'IBM Plex Mono';font-style:normal;font-weight:500;font-display:swap;src:url(/fonts/plex-mono-500.woff2) format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
|
||||
@font-face{font-family:'Unbounded Fallback';src:local('Arial Black'),local('Arial-Black'),local('Impact');size-adjust:114%;ascent-override:87.5%;descent-override:21.5%;line-gap-override:0%}
|
||||
@font-face{font-family:'Plex Sans Fallback';src:local('Arial'),local('Helvetica Neue'),local('Helvetica');size-adjust:100.5%;ascent-override:102%;descent-override:27.4%;line-gap-override:0%}
|
||||
@font-face{font-family:'Plex Mono Fallback';src:local('Courier New'),local('Menlo');size-adjust:100%;ascent-override:102.5%;descent-override:27.5%;line-gap-override:0%}
|
||||
</style>
|
||||
<script>
|
||||
/* theme before first paint: ?theme=light|dark for one view (the capture tool), else the stored choice under igneum-theme, else the system setting; ?motion=off marks the page data-motion=off so every .reveal is drawn at once (a headless render never scrolls) */
|
||||
(function(){var t=null;try{t=new URLSearchParams(location.search).get("theme");}catch(e){}if(t!=="light"&&t!=="dark"){try{t=localStorage.getItem("igneum-theme");}catch(e){t=null;}}if(t!=="light"&&t!=="dark")t=window.matchMedia&&window.matchMedia("(prefers-color-scheme: light)").matches?"light":"dark";document.documentElement.setAttribute("data-theme",t);try{if(new URLSearchParams(location.search).get("motion")==="off")document.documentElement.setAttribute("data-motion","off");}catch(e){}})();
|
||||
</script>
|
||||
<!-- head:end -->
|
||||
<style>
|
||||
/* page block; tokens, type and components are in /site.css */
|
||||
/* the explorer pages share this block with block.html and address.html; same tokens as live.html */
|
||||
--card-pad:clamp(18px,3vw,28px);--card-r:18px;--tile-pad:18px 20px;--tile-r:14px;--gap:24px;--gap-tile:12px;
|
||||
--fs-h1:clamp(32px,5.5vw,56px);--fs-h3:clamp(18px,2vw,22px);--fs-tile:clamp(20px,2.2vw,26px)}
|
||||
a:focus-visible,button:focus-visible,input:focus-visible{outline:2px solid var(--ember);outline-offset:3px;border-radius:6px}
|
||||
.mono{font-family:var(--f-mono)}
|
||||
h1,h2{font-family:var(--f-display);margin:0;line-height:1.08;text-wrap:balance}
|
||||
.head{padding:65px 0 45px;display:flex;flex-direction:column;gap:14px}
|
||||
.head p{color:var(--ink-2);max-width:67ch;font-size:18px;line-height:1.65}
|
||||
.search{display:flex;gap:10px;max-width:760px;margin-top:4px;align-items:center;padding:12px 16px;border:1px solid var(--line-2);border-radius:8px;background:var(--row)}
|
||||
.search input{flex:1;min-width:0;border:0;outline:none;background:transparent;color:var(--bone);font-size:14px}
|
||||
.search input::placeholder{color:var(--ash)}
|
||||
.btn.primary:hover{background:#FF6A2B;border-color:#FF6A2B;color:var(--ember-ink)}
|
||||
.msg{font-family:var(--f-mono);font-size:13px;color:var(--molten);min-height:18px}
|
||||
.strip{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));border:1px solid var(--line);border-radius:12px;overflow:hidden;margin-bottom:24px;background:var(--row)}
|
||||
@media (max-width:700px){.strip{grid-template-columns:repeat(2,minmax(0,1fr))}.cell{border-right:1px solid var(--line)!important}.cell:nth-child(2n){border-right:0!important}.cell:nth-last-child(-n+4){border-bottom:1px solid var(--line)}.cell:nth-last-child(-n+2){border-bottom:0}}
|
||||
.cell{padding:22px 25px;border-right:1px solid var(--line);border-bottom:1px solid var(--line);display:flex;flex-direction:column;gap:6px;min-width:0}.cell:nth-child(4n){border-right:0}.cell:nth-last-child(-n+4){border-bottom:0}
|
||||
.cell .k{font:10px var(--mono);letter-spacing:.1em;text-transform:uppercase;color:var(--ash);margin-bottom:5px}
|
||||
.cell .v{font:700 clamp(21px,2.2vw,29px)/1.1 var(--display);letter-spacing:-.04em;font-variant-numeric:tabular-nums;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
|
||||
.cell .v small{font-family:var(--f-mono);font-weight:500;font-size:13px;color:var(--ash);margin-left:4px;letter-spacing:.04em}
|
||||
@media (max-width:700px){.cell .v{font-size:19px}}
|
||||
.cell .s{font:10px/1.5 var(--mono);color:var(--ash);text-wrap:balance;margin-top:4px}
|
||||
.cell.status .v{display:flex;align-items:center;gap:10px}
|
||||
.off .dot{background:var(--ash);animation:none}.off .cell.status .v{color:var(--ash)}.on .cell.status .v{color:var(--molten)}
|
||||
@media (prefers-reduced-motion:reduce){.dot{animation:none}}
|
||||
td.n,th.n{text-align:right;font-variant-numeric:tabular-nums}
|
||||
tbody tr:hover td{background:rgba(255,255,255,.025)}
|
||||
.id{font-family:var(--f-mono);color:var(--molten)}
|
||||
.hash{font-family:var(--f-mono)}
|
||||
.sw.chain{background:var(--ember);border-color:var(--blue)}.sw.blue{background:rgba(92,184,255,.7);border-color:var(--blue)}.sw.red{background:linear-gradient(45deg,transparent 44%,var(--ash) 44%,var(--ash) 56%,transparent 56%) center/8px 8px no-repeat}
|
||||
.chip{display:inline-block;font-family:var(--f-mono);font-size:11px;letter-spacing:.08em;text-transform:uppercase;padding:3px 8px;border-radius:999px;border:1px solid var(--line-2);color:var(--ink-2);margin-right:6px}
|
||||
.chip.hot{border-color:var(--molten);color:var(--molten)}.chip.ok{border-color:var(--green);color:var(--green)}
|
||||
dl{display:grid;grid-template-columns:max-content minmax(0,1fr);gap:8px 20px;margin:12px 0 0;font-size:14px}
|
||||
dt{font-family:var(--f-mono);font-size:11px;letter-spacing:.12em;text-transform:uppercase;color:var(--ash);padding-top:3px}
|
||||
dd{margin:0;overflow-wrap:anywhere;font-variant-numeric:tabular-nums}
|
||||
@media (max-width:640px){dl{grid-template-columns:1fr;gap:2px 0}dd{margin-bottom:8px}}
|
||||
.two{display:grid;gap:var(--gap);grid-template-columns:1fr}
|
||||
@media (min-width:900px){.two{grid-template-columns:1fr 1fr}.two .card{margin-top:0}}
|
||||
.two-wrap{margin-top:var(--gap)}
|
||||
main{padding-bottom:100px}.card{background:var(--row);border:1px solid var(--line);border-radius:16px;padding:25px;margin-top:24px}.card .viz-head h2{font-size:19px}.card .viz-head .eyebrow{margin:0}
|
||||
.badge{display:inline-flex;align-items:center;gap:6px;font-family:var(--f-mono);font-size:11px;letter-spacing:.06em;text-transform:uppercase;padding:4px 9px;border-radius:999px;border:1px solid var(--line-2);color:var(--ink-2);margin:0 6px 6px 0}
|
||||
.badge.ok{border-color:var(--green,#5CC48A);color:var(--green,#5CC48A)}.badge.hot{border-color:var(--molten);color:var(--molten)}.badge.bad{border-color:var(--excluded);color:var(--excluded)}.badge.wait{color:var(--ash)}
|
||||
.bar{display:inline-block;width:72px;height:7px;border-radius:4px;background:var(--line);vertical-align:middle;margin-right:7px;overflow:hidden}.bar i{display:block;height:100%;background:var(--green,#5CC48A)}.bar i.part{background:var(--molten)}
|
||||
.dagbox{position:relative;width:100%;height:320px;border:1px solid var(--line);border-radius:12px;background:var(--obsidian);overflow:hidden}.dagbox canvas{width:100%;height:100%;display:block;cursor:pointer}
|
||||
.dagtip{position:absolute;pointer-events:none;font:11px/1.5 var(--mono);color:var(--bone);background:var(--graphite);border:1px solid var(--line-2);border-radius:8px;padding:8px 10px;max-width:300px;display:none}
|
||||
.kv{color:var(--ash)}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<!-- nav:start -->
|
||||
<a class="skip" href="#main">Skip to content</a>
|
||||
<nav class="nav" aria-label="Main" data-nav-version="5">
|
||||
<div class="container nav-row">
|
||||
<a href="/" class="logo" aria-label="Igneum home">
|
||||
<svg class="brand-mark" viewBox="0 0 1024 1024" aria-hidden="true"><rect width="1024" height="1024" rx="160" fill="#0C0C0E"></rect><g transform="translate(166.95 166.95) scale(6.901)"><polygon points="50,4 74,34 67,58 80,54 61,96 39,96 20,54 33,58 26,34" fill="#F2541B"></polygon><polygon points="50,42 59,58 50,82 41,58" fill="#0C0C0E"></polygon></g></svg>
|
||||
<span class="word">IGNEUM</span>
|
||||
</a>
|
||||
<span class="devnet" id="nav-devnet" title="igneum-devnet-3, chain id 4463. Coins have no value. The chain may reset."><span class="dot off" id="foot-dot"></span><span id="foot-state">devnet</span></span>
|
||||
<div class="nav-groups" id="nav-groups" role="list">
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-mine" data-group="mine" aria-expanded="false" aria-controls="nav-panel-mine" aria-haspopup="true">Mine<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-network" data-group="network" data-active aria-expanded="false" aria-controls="nav-panel-network" aria-haspopup="true">Network<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-learn" data-group="learn" aria-expanded="false" aria-controls="nav-panel-learn" aria-haspopup="true">Learn<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-build" data-group="build" aria-expanded="false" aria-controls="nav-panel-build" aria-haspopup="true">Build<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
</div>
|
||||
<div class="nav-controls">
|
||||
<button class="btn icon-btn" type="button" data-theme-toggle aria-label="Switch to light theme"><svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><circle cx="12" cy="12" r="4"/><path d="M12 2v2m0 16v2M2 12h2m16 0h2M5 5l1 1m12 12 1 1M5 19l1-1M18 6l1-1"/></svg></button>
|
||||
<a href="/download" class="btn primary small cta" data-nav="download">Download</a>
|
||||
<button class="burger" id="nav-burger" type="button" aria-expanded="false" aria-controls="nav-sheet" aria-label="Open the menu" aria-haspopup="true"><svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path class="bars" d="M4 6h16M4 12h16M4 18h16"/><path class="cross" d="m6 6 12 12M6 18 18 6"/></svg></button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="panels" id="nav-panels">
|
||||
<div class="panel-wrap container">
|
||||
<div class="nav-panel" id="nav-panel-mine" data-group="mine" role="region" aria-labelledby="nav-btn-mine" hidden>
|
||||
<div class="panel-list">
|
||||
<a href="/miner" data-nav="miner"><b>Ember, the miner</b><span>One click installs the node, the miner and the prover.</span></a>
|
||||
<a href="/download" data-nav="download"><b>Download</b><span>Windows, macOS, Linux and HiveOS.</span></a>
|
||||
<a href="/app" data-nav="app"><b>The app</b><span>What you see while the card mines.</span></a>
|
||||
<a href="/wallet" data-nav="wallet"><b>The wallet</b><span>Your coins. Final means final.</span></a>
|
||||
<a href="/miners" data-nav="miners"><b>GPU bench table</b><span>Measured rates, card by card.</span></a>
|
||||
<a href="/dev-fee" data-nav="dev-fee"><b>The dev fee</b><span>The optional one, in full view, off with one flag.</span></a>
|
||||
<a href="/metamask" data-nav="metamask"><b>Add to MetaMask</b><span>Igneum as a network in your wallet.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-panel" id="nav-panel-network" data-group="network" role="region" aria-labelledby="nav-btn-network" hidden>
|
||||
<div class="panel-list">
|
||||
<a href="/live" data-nav="live"><b>Live devnet</b><span>The chain as it grows, one lane per miner.</span></a>
|
||||
<a href="/explorer" data-nav="explorer" aria-current="page"><b>Explorer</b><span>Look a block or an address up.</span></a>
|
||||
<a href="/journey" data-nav="journey"><b>The journey</b><span>Six phases, four gates, the log behind them.</span></a>
|
||||
<a href="/bench" data-nav="bench"><b>Engineering log</b><span>Every measurement, with the commands that made it.</span></a>
|
||||
<a href="/evidence" data-nav="evidence"><b>Evidence</b><span>Every claim and how far it is tested.</span></a>
|
||||
<a href="/light" data-nav="light"><b>Light wallet</b><span>A balance your browser proves, trusting no node.</span></a>
|
||||
<a href="/receipt" data-nav="receipt"><b>Payment receipt</b><span>A receipt any third party re-verifies offline.</span></a>
|
||||
<a href="/oracle" data-nav="oracle"><b>State oracle on Sepolia</b><span>Devnet 3 balances read from another chain.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-panel" id="nav-panel-learn" data-group="learn" role="region" aria-labelledby="nav-btn-learn" hidden>
|
||||
<div class="panel-list">
|
||||
<a href="/litepaper" data-nav="litepaper"><b>Litepaper</b><span>The design, as published.</span></a>
|
||||
<a href="/income" data-nav="income"><b>Income per tier</b><span>IGN a day per card at three network sizes, and the electricity.</span></a>
|
||||
<a href="/ledger" data-nav="ledger"><b>Ledger</b><span>Every criticism, answered or conceded.</span></a>
|
||||
<a href="/claims" data-nav="claims"><b>What Igneum does not claim</b><span>The limits, stated first.</span></a>
|
||||
<a href="/randomx" data-nav="randomx"><b>Igneum vs RandomX</b><span>What was kept and what was rebuilt for GPUs.</span></a>
|
||||
<a href="/provenance" data-nav="provenance"><b>Built on the shoulders</b><span>Every borrowed part, credited.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-panel" id="nav-panel-build" data-group="build" role="region" aria-labelledby="nav-btn-build" hidden>
|
||||
<div class="panel-list">
|
||||
<a href="/build" data-nav="build"><b>Build on Igneum</b><span>Chain ids, RPC, a contract in five minutes.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Devnet faucet</b><span>10 IGN of devnet coin, once a day.</span></a>
|
||||
<a href="/swap" data-nav="swap"><b>Swap</b><span>Test tokens on Devnet 3; every swap is a proven block.</span></a>
|
||||
<a href="/grants" data-nav="grants"><b>Grants</b><span>Tooling, apps, infrastructure, research.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-sheet" id="nav-sheet" role="dialog" aria-modal="true" aria-label="Menu" hidden>
|
||||
<div class="sheet-scroll">
|
||||
<div class="sheet-group"><div class="sheet-head">Mine</div>
|
||||
<a href="/miner" data-nav="miner"><b>Ember, the miner</b><span>One click installs the node, the miner and the prover.</span></a>
|
||||
<a href="/download" data-nav="download"><b>Download</b><span>Windows, macOS, Linux and HiveOS.</span></a>
|
||||
<a href="/app" data-nav="app"><b>The app</b><span>What you see while the card mines.</span></a>
|
||||
<a href="/wallet" data-nav="wallet"><b>The wallet</b><span>Your coins. Final means final.</span></a>
|
||||
<a href="/miners" data-nav="miners"><b>GPU bench table</b><span>Measured rates, card by card.</span></a>
|
||||
<a href="/dev-fee" data-nav="dev-fee"><b>The dev fee</b><span>The optional one, in full view, off with one flag.</span></a>
|
||||
<a href="/metamask" data-nav="metamask"><b>Add to MetaMask</b><span>Igneum as a network in your wallet.</span></a>
|
||||
</div>
|
||||
<div class="sheet-group"><div class="sheet-head">Network</div>
|
||||
<a href="/live" data-nav="live"><b>Live devnet</b><span>The chain as it grows, one lane per miner.</span></a>
|
||||
<a href="/explorer" data-nav="explorer" aria-current="page"><b>Explorer</b><span>Look a block or an address up.</span></a>
|
||||
<a href="/journey" data-nav="journey"><b>The journey</b><span>Six phases, four gates, the log behind them.</span></a>
|
||||
<a href="/bench" data-nav="bench"><b>Engineering log</b><span>Every measurement, with the commands that made it.</span></a>
|
||||
<a href="/evidence" data-nav="evidence"><b>Evidence</b><span>Every claim and how far it is tested.</span></a>
|
||||
<a href="/light" data-nav="light"><b>Light wallet</b><span>A balance your browser proves, trusting no node.</span></a>
|
||||
<a href="/receipt" data-nav="receipt"><b>Payment receipt</b><span>A receipt any third party re-verifies offline.</span></a>
|
||||
<a href="/oracle" data-nav="oracle"><b>State oracle on Sepolia</b><span>Devnet 3 balances read from another chain.</span></a>
|
||||
</div>
|
||||
<div class="sheet-group"><div class="sheet-head">Learn</div>
|
||||
<a href="/litepaper" data-nav="litepaper"><b>Litepaper</b><span>The design, as published.</span></a>
|
||||
<a href="/income" data-nav="income"><b>Income per tier</b><span>IGN a day per card at three network sizes, and the electricity.</span></a>
|
||||
<a href="/ledger" data-nav="ledger"><b>Ledger</b><span>Every criticism, answered or conceded.</span></a>
|
||||
<a href="/claims" data-nav="claims"><b>What Igneum does not claim</b><span>The limits, stated first.</span></a>
|
||||
<a href="/randomx" data-nav="randomx"><b>Igneum vs RandomX</b><span>What was kept and what was rebuilt for GPUs.</span></a>
|
||||
<a href="/provenance" data-nav="provenance"><b>Built on the shoulders</b><span>Every borrowed part, credited.</span></a>
|
||||
</div>
|
||||
<div class="sheet-group"><div class="sheet-head">Build</div>
|
||||
<a href="/build" data-nav="build"><b>Build on Igneum</b><span>Chain ids, RPC, a contract in five minutes.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Devnet faucet</b><span>10 IGN of devnet coin, once a day.</span></a>
|
||||
<a href="/swap" data-nav="swap"><b>Swap</b><span>Test tokens on Devnet 3; every swap is a proven block.</span></a>
|
||||
<a href="/grants" data-nav="grants"><b>Grants</b><span>Tooling, apps, infrastructure, research.</span></a>
|
||||
</div>
|
||||
<div class="sheet-foot">
|
||||
<a href="/download" class="btn primary big" data-nav="download">Download</a>
|
||||
<div class="sheet-social"><a href="https://discord.gg/igneum" target="_blank" rel="noopener">Discord</a><a href="https://git.igneum.network/igneum-network/spec" target="_blank" rel="noopener">Source</a><a href="https://www.reddit.com/user/Igneum_network/" target="_blank" rel="noopener">Reddit</a></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
<script>
|
||||
(function(){
|
||||
// the slim bar (site-ui-5, 7 Oct 2026): three group buttons open one panel each; the burger opens the sheet on phones.
|
||||
// Keyboard: Enter or Space opens a group, Escape closes it and returns focus to its button, arrows move between the
|
||||
// group buttons, Tab walks the open panel's links, a click outside closes. The theme toggle flips data-theme and stores it.
|
||||
var n=document.querySelector('.nav');if(!n)return;
|
||||
var btns=[].slice.call(n.querySelectorAll('.group-btn')),panels=[].slice.call(n.querySelectorAll('.nav-panel')),wrap=n.querySelector('.panels');
|
||||
var burger=document.getElementById('nav-burger'),sheet=document.getElementById('nav-sheet');
|
||||
function panelOf(g){return panels.filter(function(p){return p.getAttribute('data-group')===g;})[0];}
|
||||
function closeAll(focusBack){var was=null;btns.forEach(function(b){if(b.getAttribute('aria-expanded')==='true')was=b;b.setAttribute('aria-expanded','false');});panels.forEach(function(p){p.hidden=true;});n.classList.remove('panel-open');if(focusBack&&was)was.focus();}
|
||||
function open(g){closeAll(false);var b=btns.filter(function(x){return x.getAttribute('data-group')===g;})[0],p=panelOf(g);if(!b||!p)return;b.setAttribute('aria-expanded','true');p.hidden=false;n.classList.add('panel-open');anchor(b,p);}
|
||||
// the panel sits under its button; a panel that would run past the container's right edge aligns its right edge to the button's right edge instead (never past the viewport)
|
||||
function anchor(b,p){var pw=n.querySelector('.panel-wrap');if(!pw)return;var cr=pw.getBoundingClientRect(),br=b.getBoundingClientRect(),w=p.offsetWidth,left=br.left-cr.left;if(left+w>cr.width)left=(br.right-cr.left)-w;if(left<0)left=0;p.style.setProperty('--panel-left',Math.round(left)+'px');}
|
||||
window.addEventListener('resize',function(){var o=btns.filter(function(x){return x.getAttribute('aria-expanded')==='true';})[0];if(o)anchor(o,panelOf(o.getAttribute('data-group')));}); btns.forEach(function(b,i){
|
||||
b.addEventListener('click',function(){var on=b.getAttribute('aria-expanded')==='true';if(on)closeAll(false);else open(b.getAttribute('data-group'));});
|
||||
b.addEventListener('keydown',function(e){
|
||||
var k=e.key;
|
||||
if(k==='ArrowRight'||k==='ArrowLeft'){e.preventDefault();var j=(i+(k==='ArrowRight'?1:btns.length-1))%btns.length;btns[j].focus();if(n.classList.contains('panel-open'))open(btns[j].getAttribute('data-group'));}
|
||||
else if(k==='ArrowDown'){e.preventDefault();open(b.getAttribute('data-group'));var f=panelOf(b.getAttribute('data-group')).querySelector('a');if(f)f.focus();}
|
||||
else if(k==='Escape'){closeAll(true);}
|
||||
});
|
||||
});
|
||||
if(wrap)wrap.addEventListener('keydown',function(e){if(e.key==='Escape'){e.stopPropagation();closeAll(true);}});
|
||||
document.addEventListener('click',function(e){if(!n.classList.contains('panel-open'))return;if(e.target.closest('.group-btn')||e.target.closest('.nav-panel'))return;closeAll(false);});
|
||||
document.addEventListener('focusin',function(e){if(!n.classList.contains('panel-open'))return;if(n.contains(e.target))return;closeAll(false);});
|
||||
document.addEventListener('keydown',function(e){if(e.key==='Escape'&&n.classList.contains('panel-open'))closeAll(true);});
|
||||
// the sheet on phones
|
||||
function setSheet(o){if(!burger||!sheet)return;n.classList.toggle('open',o);sheet.hidden=!o;burger.setAttribute('aria-expanded',o?'true':'false');burger.setAttribute('aria-label',o?'Close the menu':'Open the menu');document.documentElement.classList.toggle('nav-locked',o);if(o){var f=sheet.querySelector('a');if(f)f.focus();}}
|
||||
if(burger&&sheet){
|
||||
burger.addEventListener('click',function(){setSheet(!n.classList.contains('open'));});
|
||||
sheet.addEventListener('click',function(e){if(e.target.closest('a'))setSheet(false);});
|
||||
sheet.addEventListener('keydown',function(e){
|
||||
if(e.key==='Escape'){setSheet(false);burger.focus();return;}
|
||||
if(e.key!=='Tab')return;var f=sheet.querySelectorAll('a,button');if(!f.length)return;var first=f[0],last=f[f.length-1];
|
||||
if(e.shiftKey&&document.activeElement===first){e.preventDefault();burger.focus();}else if(!e.shiftKey&&document.activeElement===last){e.preventDefault();burger.focus();}
|
||||
});
|
||||
burger.addEventListener('keydown',function(e){if(e.key==='Tab'&&!e.shiftKey&&n.classList.contains('open')){e.preventDefault();var f=sheet.querySelector('a');if(f)f.focus();}});
|
||||
var mq=window.matchMedia('(min-width:861px)');if(mq.addEventListener)mq.addEventListener('change',function(){setSheet(false);});
|
||||
}
|
||||
// the theme toggle
|
||||
var t=n.querySelector('[data-theme-toggle]');
|
||||
function paintToggle(){var dark=document.documentElement.getAttribute('data-theme')!=='light';t.setAttribute('aria-label',dark?'Switch to light theme':'Switch to dark theme');t.innerHTML=dark?'<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><circle cx="12" cy="12" r="4"/><path d="M12 2v2m0 16v2M2 12h2m16 0h2M5 5l1 1m12 12 1 1M5 19l1-1M18 6l1-1"/></svg>':'<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="M20.7 13.3A8.5 8.5 0 0 1 10.7 3.3 8.5 8.5 0 1 0 20.7 13.3Z"/></svg>';}
|
||||
if(t){t.addEventListener('click',function(){var v=document.documentElement.getAttribute('data-theme')==='light'?'dark':'light';document.documentElement.setAttribute('data-theme',v);try{localStorage.setItem('igneum-theme',v);}catch(e){}document.dispatchEvent(new CustomEvent('igneum-theme'));});paintToggle();document.addEventListener('igneum-theme',paintToggle);}
|
||||
})();
|
||||
</script>
|
||||
<!-- nav:end -->
|
||||
<main id="main" class="wrap">
|
||||
<div class="head">
|
||||
<div class="breadcrumb"><a href="/">Igneum</a><span>/</span><a href="/explorer">Explorer</a><span>/</span><span>Proving</span></div>
|
||||
<div class="eyebrow"><a href="/explorer">Devnet 3 explorer</a> · proving</div>
|
||||
<h1>Proving on Devnet 3<span class="accent">.</span></h1>
|
||||
<p>Every chain block's execution is split into shards. Miners prove them, the node verifies the proofs, and a later coinbase pays the prover. This page reads the observer's record of that cycle: the plan per block, who proved what, and how long a block waits to be paid.</p>
|
||||
<div class="msg" id="msg" aria-live="polite"></div>
|
||||
</div>
|
||||
<div class="strip" aria-live="polite">
|
||||
<div class="cell status"><div class="k">Proving</div><div class="v"><span class="dot"></span><span id="p-status">OFFLINE</span></div><div class="s" id="p-status-s">the node's proving layer</div></div>
|
||||
<div class="cell"><div class="k">Paid, 10 min</div><div class="v" id="p-paid10">0</div><div class="s" id="p-paid10-s">shards</div></div>
|
||||
<div class="cell"><div class="k">Paid, 24 h</div><div class="v" id="p-paid24">0</div><div class="s" id="p-paid24-s">shards, IGN to provers</div></div>
|
||||
<div class="cell"><div class="k">Open blocks</div><div class="v" id="p-open">0</div><div class="s" id="p-open-s">chain blocks with unpaid shards</div></div>
|
||||
<div class="cell"><div class="k">Provers, 24 h</div><div class="v" id="p-provers">0</div><div class="s" id="p-provers-s">vote keys paid for a shard</div></div>
|
||||
<div class="cell"><div class="k">Latency, 1 h</div><div class="v" id="p-lat">n/a</div><div class="s" id="p-lat-s">median DAA from block to payment</div></div>
|
||||
<div class="cell"><div class="k">Pool</div><div class="v" id="p-pool">0</div><div class="s" id="p-pool-s">records in the node's pool</div></div>
|
||||
<div class="cell"><div class="k">Shard budget</div><div class="v" id="p-budget">0<small>pgas</small></div><div class="s">proving gas per shard</div></div>
|
||||
</div>
|
||||
<div class="card" aria-label="Chain blocks and their shards">
|
||||
<div class="viz-head"><h2>Chain blocks</h2><div class="eyebrow" id="b-eyebrow">newest 60, every 5 s</div></div>
|
||||
<div class="tbl">
|
||||
<table>
|
||||
<thead><tr><th class="n">Number</th><th>Block</th><th class="n">DAA</th><th>Class</th><th>Miner</th><th class="n">Txs</th><th class="n">pgas</th><th>Shards paid</th><th>States</th><th class="n">Median lag, DAA</th><th>Time</th></tr></thead>
|
||||
<tbody id="blocks"><tr><td colspan="11" class="empty">Loading.</td></tr></tbody>
|
||||
</table>
|
||||
</div>
|
||||
<p class="note">States count the block's shards as planned (the node published the plan), proving (a record is in the pool), verified (the node's verifier accepted the proof) and paid (a later coinbase carried the record). Lag is the DAA score of the paying block minus the block's own; Devnet 3 targets one DAA step per second.</p>
|
||||
</div>
|
||||
<div class="two two-wrap">
|
||||
<div class="card" aria-label="Provers">
|
||||
<div class="viz-head"><h2>Provers, 24 h</h2><div class="eyebrow" id="pr-eyebrow">by shards paid</div></div>
|
||||
<div class="tbl"><table><thead><tr><th>Prover</th><th class="n">Shards</th><th class="n">Paid, IGN</th><th class="n">Median lag</th><th class="n">Last hour</th><th>Last paid</th></tr></thead><tbody id="provers"></tbody></table></div>
|
||||
<p class="note">A prover is a vote key (its first 8 hex characters). A card runs several keys, so one machine can be several rows.</p>
|
||||
</div>
|
||||
<div class="card" aria-label="Latency">
|
||||
<div class="viz-head"><h2>Block to paid</h2><div class="eyebrow" id="l-eyebrow">the last hour</div></div>
|
||||
<dl id="latency"></dl>
|
||||
<p class="note">Measured on the shards paid in the window, from the proven block's DAA score to the paying block's. The 24-hour totals by state are below the hour.</p>
|
||||
<dl id="totals"></dl>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
<!-- footer:start -->
|
||||
<footer class="site-footer">
|
||||
<div class="container">
|
||||
<div class="footer-grid">
|
||||
<div class="footer-brand">
|
||||
<a href="/" class="logo" aria-label="Igneum home"><svg class="brand-mark" viewBox="0 0 1024 1024" aria-hidden="true"><rect width="1024" height="1024" rx="160" fill="#0C0C0E"></rect><g transform="translate(166.95 166.95) scale(6.901)"><polygon points="50,4 74,34 67,58 80,54 61,96 39,96 20,54 33,58 26,34" fill="#F2541B"></polygon><polygon points="50,42 59,58 50,82 41,58" fill="#0C0C0E"></polygon></g></svg><span class="word">IGNEUM</span><span class="stop">.</span></a>
|
||||
<p>Mined by GPUs. Proven by fire.</p>
|
||||
<div class="social" aria-label="Igneum elsewhere">
|
||||
<a href="https://git.igneum.network/igneum-network/spec" target="_blank" rel="noopener" aria-label="Igneum source: the spec, the vectors and the issues"><svg viewBox="0 0 24 24" width="22" height="22" fill="currentColor" aria-hidden="true"><path d="M8.6 17.6 3 12l5.6-5.6 1.4 1.4L5.8 12l4.2 4.2zm6.8 0-1.4-1.4L18.2 12 14 7.8l1.4-1.4L21 12z"></path></svg></a>
|
||||
<a href="https://discord.gg/igneum" target="_blank" rel="noopener" aria-label="The Igneum Discord"><svg viewBox="0 0 24 24" width="22" height="22" fill="currentColor" aria-hidden="true"><path d="M19.6 5.3A17 17 0 0 0 15.4 4l-.2.4a15.6 15.6 0 0 1 3.9 1.9 13.6 13.6 0 0 0-14.2 0A15.6 15.6 0 0 1 8.8 4.4L8.6 4a17 17 0 0 0-4.2 1.3C1.8 9.2 1.1 13 1.4 16.7a17.1 17.1 0 0 0 5.2 2.6l1.1-1.8a10.8 10.8 0 0 1-1.7-.8l.4-.3a12.2 12.2 0 0 0 11.2 0l.4.3-1.7.8 1.1 1.8a17 17 0 0 0 5.2-2.6c.4-4.3-.7-8-3-11.4zM8.7 14.4c-1 0-1.8-.9-1.8-2.1s.8-2.1 1.8-2.1 1.9 1 1.8 2.1c0 1.2-.8 2.1-1.8 2.1zm6.6 0c-1 0-1.8-.9-1.8-2.1s.8-2.1 1.8-2.1 1.9 1 1.8 2.1c0 1.2-.8 2.1-1.8 2.1z"></path></svg></a>
|
||||
<a data-social="reddit" href="https://www.reddit.com/user/Igneum_network/" target="_blank" rel="noopener" aria-label="Igneum on Reddit"><svg viewBox="0 0 24 24" width="22" height="22" fill="currentColor" aria-hidden="true"><path d="M22 12.1a2.2 2.2 0 0 0-3.7-1.6 10.8 10.8 0 0 0-5.8-1.8l1-4.6 3.2.7a1.5 1.5 0 1 0 .2-.9l-3.6-.8a.5.5 0 0 0-.5.4l-1.1 5.2a10.8 10.8 0 0 0-5.9 1.8A2.2 2.2 0 1 0 3.4 14a4.3 4.3 0 0 0 0 .7c0 3.4 3.9 6.1 8.6 6.1s8.6-2.7 8.6-6.1a4.3 4.3 0 0 0 0-.7 2.2 2.2 0 0 0 1.4-1.9zM7 13.6a1.5 1.5 0 1 1 1.5 1.5A1.5 1.5 0 0 1 7 13.6zm8.6 4.1a5.7 5.7 0 0 1-3.6 1.1 5.7 5.7 0 0 1-3.6-1.1.4.4 0 0 1 .6-.6 4.9 4.9 0 0 0 3 .9 4.9 4.9 0 0 0 3-.9.4.4 0 0 1 .6.6zm-.3-2.6a1.5 1.5 0 1 1 1.5-1.5 1.5 1.5 0 0 1-1.5 1.5z"></path></svg></a>
|
||||
</div>
|
||||
<div class="footer-dl" aria-label="Download Ember"><a href="/download#windows"><span class="osmark mini" data-os="windows" title="Windows"><svg viewBox="0 0 24 24" width="22" height="22" aria-hidden="true" focusable="false" fill="currentColor"><path d="M3 5.6l7.3-1v7.1H3zM11.4 4.4L21 3v8.7h-9.6zM3 12.3h7.3v7.1L3 18.4zM11.4 12.3H21V21l-9.6-1.4z"/></svg></span>Windows</a><a href="/download#mac"><span class="osmark mini" data-os="mac" title="macOS"><svg viewBox="0 0 24 24" width="22" height="22" aria-hidden="true" focusable="false" fill="currentColor"><path d="M16.4 12.6c0-2.5 2-3.6 2.1-3.7-1.2-1.7-3-1.9-3.6-2-1.5-.2-3 .9-3.8.9-.8 0-2-.9-3.3-.8-1.7 0-3.2 1-4.1 2.5-1.8 3-.5 7.6 1.3 10.1.9 1.2 1.9 2.6 3.2 2.5 1.3 0 1.8-.8 3.3-.8 1.6 0 2 .8 3.3.8 1.4 0 2.3-1.2 3.1-2.5 1-1.4 1.4-2.8 1.4-2.9 0 0-2.7-1-2.9-4.1zM13.9 5.3c.7-.8 1.2-2 1-3.2-1 0-2.2.7-2.9 1.5-.6.7-1.2 1.9-1 3 1.1.1 2.2-.5 2.9-1.3z"/></svg></span>macOS</a><a href="/download#linux"><span class="osmark mini" data-os="linux" title="Linux"><svg viewBox="0 0 24 24" width="22" height="22" aria-hidden="true" focusable="false" fill="currentColor"><path d="M12 2c-2.4 0-4 1.9-4 4.6 0 1.2.2 2 0 2.8-.6 1.4-2.1 2.9-2.6 4.9-.3 1.1-.1 2 .3 2.6-.6.4-1.3 1-1.1 1.7.3 1 2.1 1.2 3.2 1.8.7.4 1.5.6 2.1.1.6.2 1.3.3 2.1.3s1.5-.1 2.1-.3c.6.5 1.4.3 2.1-.1 1.1-.6 2.9-.8 3.2-1.8.2-.7-.5-1.3-1.1-1.7.4-.6.6-1.5.3-2.6-.5-2-2-3.5-2.6-4.9-.2-.8 0-1.6 0-2.8C16 3.9 14.4 2 12 2zm-1.4 4.2c.5 0 .8.5.8 1.2s-.3 1.2-.8 1.2-.8-.5-.8-1.2.3-1.2.8-1.2zm2.8 0c.5 0 .8.5.8 1.2s-.3 1.2-.8 1.2-.8-.5-.8-1.2.3-1.2.8-1.2zM12 9.3c.9 0 1.9.5 1.9 1s-1 1.2-1.9 1.2-1.9-.7-1.9-1.2 1-1 1.9-1zm0 3.4c2.2 0 3.6 2.6 3.6 4.4 0 1.5-1.6 2.3-3.6 2.3s-3.6-.8-3.6-2.3c0-1.8 1.4-4.4 3.6-4.4z"/></svg></span>Linux</a><a href="/download#hive"><span class="osmark mini" data-os="hive" title="HiveOS"><svg viewBox="0 0 24 24" width="22" height="22" aria-hidden="true" focusable="false" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linejoin="round" stroke-linecap="round"><path d="M12 2.6 20.2 7.3v9.4L12 21.4 3.8 16.7V7.3z"/><path d="M12 7.4 16 9.7v4.6L12 16.6 8 14.3V9.7z"/><path d="M12 7.4V2.6M16 9.7l4.2-2.4M16 14.3l4.2 2.4M12 16.6v4.8M8 14.3l-4.2 2.4M8 9.7 3.8 7.3"/></svg></span>HiveOS</a></div>
|
||||
<a href="https://git.igneum.network/igneum-network/spec" target="_blank" rel="noopener" class="text-link">Specification and test vectors<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="M6 18 18 6M6 6h12v12"/></svg></a>
|
||||
</div>
|
||||
<div class="footer-column"><h4>Run</h4><div>
|
||||
<a href="/download">Download Ember</a>
|
||||
<a href="/miner">The miner</a>
|
||||
<a href="/app">The app</a>
|
||||
<a href="/wallet">The wallet</a>
|
||||
<a href="/miners">GPU bench table</a>
|
||||
<a href="/dev-fee">The dev fee</a>
|
||||
<a href="/faucet">Devnet faucet</a>
|
||||
<a href="/metamask">Add Igneum to MetaMask</a>
|
||||
</div></div>
|
||||
<div class="footer-column"><h4>Read</h4><div>
|
||||
<a href="/litepaper">Litepaper</a>
|
||||
<a href="/evidence">Evidence</a>
|
||||
<a href="/bench">Engineering log</a>
|
||||
<a href="/ledger">Ledger: every criticism</a>
|
||||
<a href="/claims">What Igneum does not claim</a>
|
||||
<a href="/randomx">Igneum vs RandomX</a>
|
||||
<a href="/provenance">Built on the shoulders</a>
|
||||
</div></div>
|
||||
<div class="footer-column"><h4>Explore</h4><div>
|
||||
<a href="/live">Live devnet</a>
|
||||
<a href="/explorer">Explorer</a>
|
||||
<a href="/build">Build on Igneum</a>
|
||||
<a href="/swap">Swap</a>
|
||||
<a href="/grants">Grants</a>
|
||||
<a href="/journey">Journey</a>
|
||||
<a href="/download">Downloads: devnet build</a>
|
||||
<a href="https://discord.gg/igneum" target="_blank" rel="noopener">Community Discord</a>
|
||||
<a href="mailto:hello@igneum.network">hello@igneum.network</a>
|
||||
<a href="https://git.igneum.network/igneum-network/spec/issues" rel="noopener">An issue on the spec</a>
|
||||
</div></div>
|
||||
</div>
|
||||
<div class="footer-bottom">
|
||||
<p>Igneum Labs LTD · Unit IH-00-01-01-OF-01, Level 01, Innovation One, Dubai International Financial Centre. Experimental software. Nothing on this site is an offer to sell anything.<br>Report a flaw by email or by an issue on the spec. Nobody from Igneum will ask for your seed. © 2026 Igneum · not an offer to sell anything</p>
|
||||
<div class="theme-group" role="group" aria-label="Theme"><button type="button" data-theme-set="system" aria-pressed="true">System</button><button type="button" data-theme-set="light" aria-pressed="false">Light</button><button type="button" data-theme-set="dark" aria-pressed="false">Dark</button></div>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
<script>
|
||||
(function(){
|
||||
// theme control: stores light or dark under igneum-theme; system clears it and follows the OS. The head applied the value before paint.
|
||||
var bs=document.querySelectorAll('[data-theme-set]');if(!bs.length)return;
|
||||
var media=window.matchMedia('(prefers-color-scheme: light)');
|
||||
function stored(){try{var t=localStorage.getItem('igneum-theme');return t==='light'||t==='dark'?t:'system';}catch(e){return 'system';}}
|
||||
function apply(){var c=stored();document.documentElement.setAttribute('data-theme',c==='system'?(media.matches?'light':'dark'):c);bs.forEach(function(b){b.setAttribute('aria-pressed',b.getAttribute('data-theme-set')===c?'true':'false');});document.dispatchEvent(new CustomEvent('igneum-theme'));}
|
||||
bs.forEach(function(b){b.addEventListener('click',function(){var v=b.getAttribute('data-theme-set');try{if(v==='system')localStorage.removeItem('igneum-theme');else localStorage.setItem('igneum-theme',v);}catch(e){}apply();});});
|
||||
if(media.addEventListener)media.addEventListener('change',function(){if(stored()==='system')apply();});
|
||||
document.addEventListener('igneum-theme',function(){var c=stored();bs.forEach(function(b){b.setAttribute('aria-pressed',b.getAttribute('data-theme-set')===c?'true':'false');});});
|
||||
bs.forEach(function(b){b.setAttribute('aria-pressed',b.getAttribute('data-theme-set')===stored()?'true':'false');});
|
||||
// the network state word in the status bar: one read of the observer per page view
|
||||
var fs=document.getElementById('foot-state'),fd=document.getElementById('foot-dot');if(fs&&fd){fetch('/api/live?window=30',{cache:'no-store'}).then(function(r){return r.json();}).then(function(d){var on=d&&d.ok&&d.state&&!d.state.stale;fs.textContent=on?'devnet live':'devnet, observer stale';fd.className='dot '+(on?'live':'off');}).catch(function(){fs.textContent='devnet';});}
|
||||
})();
|
||||
</script>
|
||||
<!-- footer:end -->
|
||||
<script type="module">
|
||||
import { ignFromWei, shortHash, rel, int } from '/lib/explorer.mjs';
|
||||
const $ = id => document.getElementById(id);
|
||||
const esc = s => String(s ?? '').replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>');
|
||||
const dl = pairs => pairs.filter(p => p).map(([k, v]) => `<dt>${esc(k)}</dt><dd>${v}</dd>`).join('');
|
||||
const stamp = iso => iso ? new Date(iso).toISOString().slice(11, 19) + ' UTC' : '';
|
||||
function bar(s) { if (!s || !s.total) return '<span class="kv">no plan yet</span>'; const pct = Math.round(s.paid / s.total * 100); return `<span class="bar"><i class="${s.paid === s.total ? '' : 'part'}" style="width:${pct}%"></i></span>${s.paid} of ${s.total}`; }
|
||||
async function load() {
|
||||
const j = await fetch('/api/explorer?proving=1').then(r => r.json()); if (!j.ok) throw new Error(j.error);
|
||||
const now = new Date(j.now).getTime(), p = j.proving || {}, l = j.latency_1h || {}, t = j.totals_24h || {};
|
||||
const on = p.supported !== false && !j.stale;
|
||||
document.body.classList.toggle('on', on); document.body.classList.toggle('off', !on);
|
||||
$('p-status').textContent = j.stale ? 'OFFLINE' : (p.supported === false ? 'NO LAYER' : (p.active ? 'ACTIVE' : 'INACTIVE'));
|
||||
$('p-status-s').textContent = j.stale ? 'observer stale' : `read ${stamp(j.now)}, tip DAA ${int(p.tip_daa)}${p.paused_since_ms ? ', paused' : ''}`;
|
||||
$('p-paid10').textContent = int(p.shards_paid_10m ?? 0); $('p-paid10-s').textContent = `shards; ${int(p.blocks_fully_proven_10m ?? 0)} of ${int(p.blocks_10m ?? 0)} blocks of the window fully proven`;
|
||||
$('p-paid24').textContent = int(t.paid ? t.paid.shards : 0); $('p-paid24-s').textContent = `shards, ${ignFromWei(t.paid ? t.paid.payout_wei : '0', 2)} IGN to provers`;
|
||||
$('p-open').textContent = int(p.open_blocks ?? 0); $('p-open-s').textContent = `chain blocks with unpaid shards, ${int(p.pending_plans ?? 0)} plans not read yet`;
|
||||
$('p-provers').textContent = int(j.provers.length); $('p-provers-s').textContent = `vote keys paid for a shard; ${int(p.provers_10m ?? 0)} in the last 10 min`;
|
||||
$('p-lat').textContent = l.paid ? int(l.p50_daa) : 'n/a'; $('p-lat-s').textContent = l.paid ? `median DAA from block to payment over ${int(l.paid)} shards, p90 ${int(l.p90_daa)}` : 'no shard paid in the last hour';
|
||||
const pool = p.pool || {}; $('p-pool').textContent = int(pool.entries ?? 0); $('p-pool-s').textContent = `records in the node's pool: ${int(pool.pending ?? 0)} pending, ${int(pool.verified ?? 0)} verified, ${int(pool.failed ?? 0)} failed`;
|
||||
$('p-budget').innerHTML = esc(int(p.shard_budget_pgas ?? 0)) + '<small>pgas</small>';
|
||||
$('b-eyebrow').textContent = `newest ${j.blocks.length}, every 5 s, read ${stamp(j.now)}`;
|
||||
$('blocks').innerHTML = j.blocks.length ? j.blocks.map(b => `<tr data-href="/block/${b.hash}"><td class="n">${int(b.number)}</td><td><a class="hash" href="/block/${b.hash}">${esc(shortHash(b.hash, 10, 6))}</a></td><td class="n">${int(b.daa)}</td><td><span class="chip">${esc(b.class)}</span></td><td>${b.evm_miner ? `<a class="hash" href="/address/${b.evm_miner}">${esc(shortHash(b.evm_miner, 6, 4))}</a>` : ''} <span class="id" style="font-size:12px">${esc(b.miner_id || '')}</span></td><td class="n">${int(b.tx_count)}</td><td class="n">${int(b.pgas)}</td><td>${bar(b.shards)}</td><td class="kv" style="font-size:12px">${b.shards && b.shards.total ? `${b.shards.planned} planned, ${b.shards.proving} proving, ${b.shards.verified} verified, ${b.shards.paid} paid` : ''}</td><td class="n">${b.shards && b.shards.median_lag !== null && b.shards.median_lag !== undefined ? int(b.shards.median_lag) : ''}</td><td title="${new Date(b.ts).toISOString()}">${rel(now - b.ts)}</td></tr>`).join('') : '<tr><td colspan="11" class="empty">No chain block in the last 24 hours.</td></tr>';
|
||||
$('pr-eyebrow').textContent = `${int(j.provers.length)} keys, by shards paid`;
|
||||
$('provers').innerHTML = j.provers.length ? j.provers.map(x => `<tr><td class="id">${esc(x.id)}</td><td class="n">${int(x.shards_24h)}</td><td class="n">${ignFromWei(x.payout_wei_24h, 2)}</td><td class="n">${x.median_lag_24h === null ? '' : int(x.median_lag_24h)}</td><td class="n">${int(x.shards_1h)}</td><td title="${x.last_paid ? new Date(x.last_paid).toISOString() : ''}">${x.last_paid ? rel(now - new Date(x.last_paid).getTime()) : ''}</td></tr>`).join('') : '<tr><td colspan="6" class="empty">No shard paid in the last 24 hours.</td></tr>';
|
||||
$('l-eyebrow').textContent = `the last hour, read ${stamp(j.now)}`;
|
||||
$('latency').innerHTML = l.paid ? dl([['Shards paid', int(l.paid)], ['Median', `${int(l.p50_daa)} DAA`], ['p90', `${int(l.p90_daa)} DAA`], ['Fastest', `${int(l.min_daa)} DAA`], ['Slowest', `${int(l.max_daa)} DAA`]]) : '<div class="empty">No shard paid in the last hour.</div>';
|
||||
$('totals').innerHTML = dl(Object.entries(t).sort().map(([k, v]) => [`${k}, 24 h`, `${int(v.shards)} shards${k === 'paid' ? `, ${ignFromWei(v.payout_wei, 2)} IGN` : ''}`]));
|
||||
}
|
||||
$('blocks').addEventListener('click', e => { const tr = e.target.closest('tr[data-href]'); if (tr && !e.target.closest('a')) location.href = tr.dataset.href; });
|
||||
setInterval(() => { load().catch(() => {}); }, 5000);
|
||||
load().catch(e => { $('msg').textContent = 'The API did not answer: ' + e.message; });
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -86,6 +86,7 @@
|
|||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-mine" data-group="mine" aria-expanded="false" aria-controls="nav-panel-mine" aria-haspopup="true">Mine<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-network" data-group="network" aria-expanded="false" aria-controls="nav-panel-network" aria-haspopup="true">Network<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-learn" data-group="learn" data-active aria-expanded="false" aria-controls="nav-panel-learn" aria-haspopup="true">Learn<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-build" data-group="build" aria-expanded="false" aria-controls="nav-panel-build" aria-haspopup="true">Build<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
</div>
|
||||
<div class="nav-controls">
|
||||
<button class="btn icon-btn" type="button" data-theme-toggle aria-label="Switch to light theme"><svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><circle cx="12" cy="12" r="4"/><path d="M12 2v2m0 16v2M2 12h2m16 0h2M5 5l1 1m12 12 1 1M5 19l1-1M18 6l1-1"/></svg></button>
|
||||
|
|
@ -103,7 +104,6 @@
|
|||
<a href="/wallet" data-nav="wallet"><b>The wallet</b><span>Your coins. Final means final.</span></a>
|
||||
<a href="/miners" data-nav="miners"><b>GPU bench table</b><span>Measured rates, card by card.</span></a>
|
||||
<a href="/dev-fee" data-nav="dev-fee"><b>The dev fee</b><span>The optional one, in full view, off with one flag.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Testnet faucet</b><span>Test coin for an address, once a day.</span></a>
|
||||
<a href="/metamask" data-nav="metamask"><b>Add to MetaMask</b><span>Igneum as a network in your wallet.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -114,6 +114,9 @@
|
|||
<a href="/journey" data-nav="journey"><b>The journey</b><span>Six phases, four gates, the log behind them.</span></a>
|
||||
<a href="/bench" data-nav="bench"><b>Engineering log</b><span>Every measurement, with the commands that made it.</span></a>
|
||||
<a href="/evidence" data-nav="evidence"><b>Evidence</b><span>Every claim and how far it is tested.</span></a>
|
||||
<a href="/light" data-nav="light"><b>Light wallet</b><span>A balance your browser proves, trusting no node.</span></a>
|
||||
<a href="/receipt" data-nav="receipt"><b>Payment receipt</b><span>A receipt any third party re-verifies offline.</span></a>
|
||||
<a href="/oracle" data-nav="oracle"><b>State oracle on Sepolia</b><span>Devnet 3 balances read from another chain.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-panel" id="nav-panel-learn" data-group="learn" role="region" aria-labelledby="nav-btn-learn" hidden>
|
||||
|
|
@ -126,6 +129,14 @@
|
|||
<a href="/provenance" data-nav="provenance"><b>Built on the shoulders</b><span>Every borrowed part, credited.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-panel" id="nav-panel-build" data-group="build" role="region" aria-labelledby="nav-btn-build" hidden>
|
||||
<div class="panel-list">
|
||||
<a href="/build" data-nav="build"><b>Build on Igneum</b><span>Chain ids, RPC, a contract in five minutes.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Devnet faucet</b><span>10 IGN of devnet coin, once a day.</span></a>
|
||||
<a href="/swap" data-nav="swap"><b>Swap</b><span>Test tokens on Devnet 3; every swap is a proven block.</span></a>
|
||||
<a href="/grants" data-nav="grants"><b>Grants</b><span>Tooling, apps, infrastructure, research.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-sheet" id="nav-sheet" role="dialog" aria-modal="true" aria-label="Menu" hidden>
|
||||
|
|
@ -137,7 +148,6 @@
|
|||
<a href="/wallet" data-nav="wallet"><b>The wallet</b><span>Your coins. Final means final.</span></a>
|
||||
<a href="/miners" data-nav="miners"><b>GPU bench table</b><span>Measured rates, card by card.</span></a>
|
||||
<a href="/dev-fee" data-nav="dev-fee"><b>The dev fee</b><span>The optional one, in full view, off with one flag.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Testnet faucet</b><span>Test coin for an address, once a day.</span></a>
|
||||
<a href="/metamask" data-nav="metamask"><b>Add to MetaMask</b><span>Igneum as a network in your wallet.</span></a>
|
||||
</div>
|
||||
<div class="sheet-group"><div class="sheet-head">Network</div>
|
||||
|
|
@ -146,6 +156,9 @@
|
|||
<a href="/journey" data-nav="journey"><b>The journey</b><span>Six phases, four gates, the log behind them.</span></a>
|
||||
<a href="/bench" data-nav="bench"><b>Engineering log</b><span>Every measurement, with the commands that made it.</span></a>
|
||||
<a href="/evidence" data-nav="evidence"><b>Evidence</b><span>Every claim and how far it is tested.</span></a>
|
||||
<a href="/light" data-nav="light"><b>Light wallet</b><span>A balance your browser proves, trusting no node.</span></a>
|
||||
<a href="/receipt" data-nav="receipt"><b>Payment receipt</b><span>A receipt any third party re-verifies offline.</span></a>
|
||||
<a href="/oracle" data-nav="oracle"><b>State oracle on Sepolia</b><span>Devnet 3 balances read from another chain.</span></a>
|
||||
</div>
|
||||
<div class="sheet-group"><div class="sheet-head">Learn</div>
|
||||
<a href="/litepaper" data-nav="litepaper"><b>Litepaper</b><span>The design, as published.</span></a>
|
||||
|
|
@ -155,6 +168,12 @@
|
|||
<a href="/randomx" data-nav="randomx" aria-current="page"><b>Igneum vs RandomX</b><span>What was kept and what was rebuilt for GPUs.</span></a>
|
||||
<a href="/provenance" data-nav="provenance"><b>Built on the shoulders</b><span>Every borrowed part, credited.</span></a>
|
||||
</div>
|
||||
<div class="sheet-group"><div class="sheet-head">Build</div>
|
||||
<a href="/build" data-nav="build"><b>Build on Igneum</b><span>Chain ids, RPC, a contract in five minutes.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Devnet faucet</b><span>10 IGN of devnet coin, once a day.</span></a>
|
||||
<a href="/swap" data-nav="swap"><b>Swap</b><span>Test tokens on Devnet 3; every swap is a proven block.</span></a>
|
||||
<a href="/grants" data-nav="grants"><b>Grants</b><span>Tooling, apps, infrastructure, research.</span></a>
|
||||
</div>
|
||||
<div class="sheet-foot">
|
||||
<a href="/download" class="btn primary big" data-nav="download">Download</a>
|
||||
<div class="sheet-social"><a href="https://discord.gg/igneum" target="_blank" rel="noopener">Discord</a><a href="https://git.igneum.network/igneum-network/spec" target="_blank" rel="noopener">Source</a><a href="https://www.reddit.com/user/Igneum_network/" target="_blank" rel="noopener">Reddit</a></div>
|
||||
|
|
@ -219,7 +238,7 @@
|
|||
</section>
|
||||
<section class="section compact">
|
||||
<div class="container">
|
||||
<div class="derived"><p>RandomX has kept chips off Monero since 2019 (approximate) by making the mining program random, so the hardware that runs it well is the hardware everyone already owns. The one chip announced against it, Bitmain’s Antminer X9 (pre-orders from 26 December 2025 at 1 MH/s and 2,472 W, about USD 5,600), was withdrawn in mid-May 2026 before any unit shipped; RandomX 2.0 shipped on 25 March 2026 (monero-project/monero issue 10270). Igneum takes the same principle to graphics cards and adds what RandomX never had.</p>
|
||||
<div class="derived"><p>RandomX has kept Monero on commodity hardware since 2019 by making the mining program random, so the hardware that runs it well is close to the hardware everyone already owns: the one chip that shipped, Bitmain’s Antminer X5 (September 2023), is a board of RISC-V chips at 1.46x per joule over a desktop CPU. The one chip announced against it, Bitmain’s Antminer X9 (pre-orders from 26 December 2025 at 1 MH/s and 2,472 W, about USD 5,600), was withdrawn in mid-May 2026 before any unit shipped; RandomX 2.0 shipped on 25 March 2026 with its mainnet activation pending (monero-project/monero issue 10270). Igneum takes the same principle to graphics cards and adds what RandomX never had.</p>
|
||||
<div class="tbl"><table>
|
||||
<thead><tr><th>Property</th><th>RandomX, Monero</th><th>Igneum</th></tr></thead>
|
||||
<tbody>
|
||||
|
|
@ -230,7 +249,7 @@
|
|||
<tr><td>Changes over time</td><td>None. A fixed design, unchanged for seven years</td><td>A new program every hour, its memory pattern with it; era draws and reserved families on a schedule fixed at genesis. Nobody touches it</td></tr>
|
||||
<tr><td>Seed grinding</td><td>Not applicable, the program comes from the hash input</td><td>Closed by a verifiable delay between seed and program</td></tr>
|
||||
<tr><td>Useful work</td><td>None. Hashing only</td><td>Every NVIDIA card from 8 GB proves; 12 GB and up mine and prove; 24 GB on the stock server (eleven rented cards, RTX 3060 to RTX 5090, 6 October 2026); they sell proofs to other chains. AMD and Apple cards mine, and a prover for them lands when a zkVM ships one</td></tr>
|
||||
<tr><td>Track record</td><td>About seven years without a shipped chip; the one announced, Bitmain’s Antminer X9, was withdrawn in May 2026 before launch</td><td>Zero years. Every number above is measured and logged with the commands that produced it. The specification, reference hash, test vectors and simulators are public now (git.igneum.network/igneum-network/spec). The node, the miner and the wallet follow to the same host as the repository is published</td></tr>
|
||||
<tr><td>Track record</td><td>About seven years with one shipped chip, Bitmain’s Antminer X5 (September 2023), at 1.46x per joule over a desktop CPU; the one announced beyond it, Bitmain’s Antminer X9, was withdrawn in May 2026 with zero units; RandomX v2 released 25 March 2026, activation pending</td><td>Zero years. Every number above is measured and logged with the commands that produced it. The specification, reference hash, test vectors and simulators are public now (git.igneum.network/igneum-network/spec). The node, the miner and the wallet follow to the same host as the repository is published</td></tr>
|
||||
</tbody>
|
||||
</table></div>
|
||||
<p>Measured so far: the same hourly program, generated on an Apple M5 Max, compiled by Apple's Metal and NVIDIA's CUDA on an RTX 5090, produced identical hashes on both, 192 of 192 across two programs. On a 1 GB dataset the 5090 ran at about 228 million hashes a second and the Mac at about 45 million, both bound by random memory access rather than arithmetic. Those are prototype figures, not mining rates. The first prototype dataset was a closed-form function, and a miner could compute items instead of loading them: measured 111x faster that way on the Mac. The 256 MB cache construction replaced it on 3 October 2026. With the cache, computing items on the fly runs 4.8x slower than loading them, measured on the Mac, and the honest rate is unchanged on both vendors. Open: the same shortcut ratio on NVIDIA and on a discrete AMD card, and the time-memory trade-off between the two measured points. Inside the 5090's 96 MB cache the same program ran nearly six times faster, which is why the dataset starts at 2 GB and grows. On 4 October 2026 the live devnet crossed an hourly program change on all three vendors with no pause and no rejected block: a Mac at 26.7 million hashes a second, an RTX 5090 at 123 million and an integrated AMD chip at 2.7 million, every hash doing 128 distinct reads of the memory-hard dataset.</p></div>
|
||||
|
|
@ -260,7 +279,7 @@
|
|||
<a href="/wallet">The wallet</a>
|
||||
<a href="/miners">GPU bench table</a>
|
||||
<a href="/dev-fee">The dev fee</a>
|
||||
<a href="/faucet">Testnet faucet</a>
|
||||
<a href="/faucet">Devnet faucet</a>
|
||||
<a href="/metamask">Add Igneum to MetaMask</a>
|
||||
</div></div>
|
||||
<div class="footer-column"><h4>Read</h4><div>
|
||||
|
|
@ -275,6 +294,9 @@
|
|||
<div class="footer-column"><h4>Explore</h4><div>
|
||||
<a href="/live">Live devnet</a>
|
||||
<a href="/explorer">Explorer</a>
|
||||
<a href="/build">Build on Igneum</a>
|
||||
<a href="/swap">Swap</a>
|
||||
<a href="/grants">Grants</a>
|
||||
<a href="/journey">Journey</a>
|
||||
<a href="/download">Downloads: devnet build</a>
|
||||
<a href="https://discord.gg/igneum" target="_blank" rel="noopener">Community Discord</a>
|
||||
|
|
|
|||
363
site/receipt.html
Normal file
363
site/receipt.html
Normal file
|
|
@ -0,0 +1,363 @@
|
|||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
|
||||
<title>Igneum payment receipt</title>
|
||||
<meta name="description" content="A Devnet 3 payment receipt proven against the finality certificate, downloadable as JSON and re-verified offline by anyone with a one-file verifier. Devnet 3, no value.">
|
||||
<link rel="canonical" href="https://igneum.network/receipt">
|
||||
<meta name="theme-color" content="#0C0C0E">
|
||||
<meta property="og:type" content="website">
|
||||
<meta property="og:site_name" content="Igneum">
|
||||
<meta property="og:title" content="Igneum payment receipt">
|
||||
<meta property="og:description" content="A Devnet 3 payment receipt proven against the finality certificate, downloadable as JSON and re-verified offline by anyone with a one-file verifier. Devnet 3, no value.">
|
||||
<meta property="og:url" content="https://igneum.network/receipt">
|
||||
<meta property="og:image" content="https://igneum.network/og.png?v=3">
|
||||
<meta property="og:image:width" content="1200">
|
||||
<meta property="og:image:height" content="630">
|
||||
<meta property="og:image:alt" content="Igneum. Mined by GPUs. Proven by fire.">
|
||||
<meta name="twitter:card" content="summary_large_image">
|
||||
<meta name="twitter:title" content="Igneum payment receipt">
|
||||
<meta name="twitter:description" content="A Devnet 3 payment receipt proven against the finality certificate, downloadable as JSON and re-verified offline by anyone with a one-file verifier. Devnet 3, no value.">
|
||||
<meta name="twitter:image" content="https://igneum.network/og.png?v=3">
|
||||
<meta name="twitter:image:alt" content="Igneum. Mined by GPUs. Proven by fire.">
|
||||
<link rel="icon" href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1024 1024'%3E%3Crect width='1024' height='1024' fill='%230C0C0E'/%3E%3Cg transform='translate(166.95 166.95) scale(6.901)'%3E%3Cpolygon points='50,4 74,34 67,58 80,54 61,96 39,96 20,54 33,58 26,34' fill='%23F2541B'/%3E%3Cpolygon points='50,42 59,58 50,82 41,58' fill='%230C0C0E'/%3E%3C/g%3E%3C/svg%3E" type="image/svg+xml">
|
||||
<link rel="icon" href="/favicon.ico" sizes="48x48">
|
||||
<link rel="icon" href="/favicon-32.png" type="image/png" sizes="32x32">
|
||||
<link rel="icon" href="/icon-192.png" type="image/png" sizes="192x192">
|
||||
<link rel="icon" href="/icon-512.png" type="image/png" sizes="512x512">
|
||||
<link rel="apple-touch-icon" href="/apple-touch-icon.png" sizes="180x180">
|
||||
<link rel="manifest" href="/site.webmanifest">
|
||||
<!-- head:start -->
|
||||
<link rel="preload" href="/fonts/unbounded-900.woff2" as="font" type="font/woff2" crossorigin>
|
||||
<link rel="preload" href="/fonts/plex-sans-400.woff2" as="font" type="font/woff2" crossorigin>
|
||||
<meta name="color-scheme" content="dark light">
|
||||
<link rel="stylesheet" href="/site.css">
|
||||
<style>
|
||||
/* Shared by every page: the head partial, injected by the build between the head markers. Edit the partial, not the page. */
|
||||
/* Fonts, self-hosted (latin subsets, OFL): Unbounded 500/700/900, IBM Plex Sans 400/500/600, IBM Plex Mono 400/500. Fallbacks carry size and ascent overrides so the swap does not move the layout. The tokens, type and components are in /site.css (docs/plans/site-ui-3.md). */
|
||||
@font-face{font-family:'Unbounded';font-style:normal;font-weight:500;font-display:swap;src:url(/fonts/unbounded-500.woff2) format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
|
||||
@font-face{font-family:'Unbounded';font-style:normal;font-weight:700;font-display:swap;src:url(/fonts/unbounded-700.woff2) format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
|
||||
@font-face{font-family:'Unbounded';font-style:normal;font-weight:900;font-display:swap;src:url(/fonts/unbounded-900.woff2) format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
|
||||
@font-face{font-family:'IBM Plex Sans';font-style:normal;font-weight:400;font-display:swap;src:url(/fonts/plex-sans-400.woff2) format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
|
||||
@font-face{font-family:'IBM Plex Sans';font-style:normal;font-weight:500;font-display:swap;src:url(/fonts/plex-sans-500.woff2) format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
|
||||
@font-face{font-family:'IBM Plex Sans';font-style:normal;font-weight:600;font-display:swap;src:url(/fonts/plex-sans-600.woff2) format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
|
||||
@font-face{font-family:'IBM Plex Mono';font-style:normal;font-weight:400;font-display:swap;src:url(/fonts/plex-mono-400.woff2) format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
|
||||
@font-face{font-family:'IBM Plex Mono';font-style:normal;font-weight:500;font-display:swap;src:url(/fonts/plex-mono-500.woff2) format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
|
||||
@font-face{font-family:'Unbounded Fallback';src:local('Arial Black'),local('Arial-Black'),local('Impact');size-adjust:114%;ascent-override:87.5%;descent-override:21.5%;line-gap-override:0%}
|
||||
@font-face{font-family:'Plex Sans Fallback';src:local('Arial'),local('Helvetica Neue'),local('Helvetica');size-adjust:100.5%;ascent-override:102%;descent-override:27.4%;line-gap-override:0%}
|
||||
@font-face{font-family:'Plex Mono Fallback';src:local('Courier New'),local('Menlo');size-adjust:100%;ascent-override:102.5%;descent-override:27.5%;line-gap-override:0%}
|
||||
</style>
|
||||
<script>
|
||||
/* theme before first paint: ?theme=light|dark for one view (the capture tool), else the stored choice under igneum-theme, else the system setting; ?motion=off marks the page data-motion=off so every .reveal is drawn at once (a headless render never scrolls) */
|
||||
(function(){var t=null;try{t=new URLSearchParams(location.search).get("theme");}catch(e){}if(t!=="light"&&t!=="dark"){try{t=localStorage.getItem("igneum-theme");}catch(e){t=null;}}if(t!=="light"&&t!=="dark")t=window.matchMedia&&window.matchMedia("(prefers-color-scheme: light)").matches?"light":"dark";document.documentElement.setAttribute("data-theme",t);try{if(new URLSearchParams(location.search).get("motion")==="off")document.documentElement.setAttribute("data-motion","off");}catch(e){}})();
|
||||
</script>
|
||||
<!-- head:end -->
|
||||
<style>
|
||||
/* reference apps (8 Oct 2026): the verify form, the proven headline, the step list; tokens and components are in /site.css */
|
||||
.vform{display:grid;gap:10px;margin:0}
|
||||
.vform label{font:500 var(--t-sm)/1.4 var(--f-mono);letter-spacing:.08em;text-transform:uppercase;color:var(--ash)}
|
||||
.vform .row{display:flex;gap:10px;flex-wrap:wrap}.vform input{flex:1 1 320px;font-family:var(--f-mono);font-size:14px}
|
||||
.vstatus{font:400 13px/1.5 var(--f-mono);color:var(--ash);min-height:20px}.vstatus[data-kind="ok"]{color:var(--ember-text)}.vstatus[data-kind="bad"]{color:var(--molten-text)}
|
||||
.headline{background:var(--graphite);border:1px solid var(--line);border-radius:var(--r-card);padding:var(--s-5);margin:var(--s-5) 0 var(--s-4)}
|
||||
.headline.bad{border-color:var(--molten)}
|
||||
.headline .big{font:900 clamp(32px,6vw,56px)/1.05 var(--f-display);color:var(--bone);margin:10px 0 8px;overflow-wrap:anywhere}.headline .big span{font-size:.45em;color:var(--ash);font-weight:700}
|
||||
.headline .kv{margin-top:var(--s-3)}.headline .kv small{color:var(--ash);display:block}.headline .mono{font-family:var(--f-mono);font-size:13px;overflow-wrap:anywhere}
|
||||
.kv>div{min-width:0;overflow-wrap:anywhere}.card .kv .mono{font-family:var(--f-mono);font-size:13px}
|
||||
@media (max-width:640px){.kv{grid-template-columns:1fr}.kv>div{padding:6px 0}.kv .k{padding-top:10px;border-top:1px solid var(--line)}.kv>div:not(.k){border-top:0}}
|
||||
.neg{border-left:2px solid var(--ember);background:var(--row);border-radius:0 var(--r-row) var(--r-row) 0;padding:12px var(--s-4);margin:0 0 var(--s-3);font-size:14px;color:var(--ink-2)}
|
||||
.neg b{font:500 11px/1 var(--f-mono);letter-spacing:.12em;text-transform:uppercase;color:var(--ember-text);margin-right:8px}.neg.wrong{border-color:var(--molten)}.neg.wrong b{color:var(--molten-text)}
|
||||
.neg small{display:block;color:var(--ash);font-family:var(--f-mono);font-size:12px;margin-top:4px;overflow-wrap:anywhere}
|
||||
.steps{list-style:none;margin:0;padding:0;display:grid;gap:8px}
|
||||
.steps li{display:grid;grid-template-columns:84px 1fr;gap:4px 12px;background:var(--row);border:1px solid var(--line);border-radius:var(--r-row);padding:10px 14px;font-size:14px;color:var(--ink-2)}
|
||||
.steps li b{font:500 11px/1.6 var(--f-mono);letter-spacing:.12em;text-transform:uppercase;color:var(--ember-text)}.steps li.bad b{color:var(--molten-text)}
|
||||
.steps li small{grid-column:2;color:var(--ash);font-family:var(--f-mono);font-size:12px;overflow-wrap:anywhere}
|
||||
.why{border:1px solid var(--line-2);border-radius:var(--r-card);padding:var(--s-4) var(--s-5);background:var(--obsidian);margin:var(--s-5) 0}
|
||||
.why p{margin:0;font-size:15px;color:var(--ink-2)}.why p+p{margin-top:8px}
|
||||
.meta{display:grid;gap:6px;font:400 13px/1.6 var(--f-mono);color:var(--ash);margin:var(--s-4) 0 0}.meta code{overflow-wrap:anywhere}
|
||||
@media (max-width:640px){.steps li{grid-template-columns:1fr}.steps li small{grid-column:1}}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<!-- nav:start -->
|
||||
<a class="skip" href="#main">Skip to content</a>
|
||||
<nav class="nav" aria-label="Main" data-nav-version="5">
|
||||
<div class="container nav-row">
|
||||
<a href="/" class="logo" aria-label="Igneum home">
|
||||
<svg class="brand-mark" viewBox="0 0 1024 1024" aria-hidden="true"><rect width="1024" height="1024" rx="160" fill="#0C0C0E"></rect><g transform="translate(166.95 166.95) scale(6.901)"><polygon points="50,4 74,34 67,58 80,54 61,96 39,96 20,54 33,58 26,34" fill="#F2541B"></polygon><polygon points="50,42 59,58 50,82 41,58" fill="#0C0C0E"></polygon></g></svg>
|
||||
<span class="word">IGNEUM</span>
|
||||
</a>
|
||||
<span class="devnet" id="nav-devnet" title="igneum-devnet-3, chain id 4463. Coins have no value. The chain may reset."><span class="dot off" id="foot-dot"></span><span id="foot-state">devnet</span></span>
|
||||
<div class="nav-groups" id="nav-groups" role="list">
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-mine" data-group="mine" aria-expanded="false" aria-controls="nav-panel-mine" aria-haspopup="true">Mine<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-network" data-group="network" data-active aria-expanded="false" aria-controls="nav-panel-network" aria-haspopup="true">Network<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-learn" data-group="learn" aria-expanded="false" aria-controls="nav-panel-learn" aria-haspopup="true">Learn<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-build" data-group="build" aria-expanded="false" aria-controls="nav-panel-build" aria-haspopup="true">Build<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
</div>
|
||||
<div class="nav-controls">
|
||||
<button class="btn icon-btn" type="button" data-theme-toggle aria-label="Switch to light theme"><svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><circle cx="12" cy="12" r="4"/><path d="M12 2v2m0 16v2M2 12h2m16 0h2M5 5l1 1m12 12 1 1M5 19l1-1M18 6l1-1"/></svg></button>
|
||||
<a href="/download" class="btn primary small cta" data-nav="download">Download</a>
|
||||
<button class="burger" id="nav-burger" type="button" aria-expanded="false" aria-controls="nav-sheet" aria-label="Open the menu" aria-haspopup="true"><svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path class="bars" d="M4 6h16M4 12h16M4 18h16"/><path class="cross" d="m6 6 12 12M6 18 18 6"/></svg></button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="panels" id="nav-panels">
|
||||
<div class="panel-wrap container">
|
||||
<div class="nav-panel" id="nav-panel-mine" data-group="mine" role="region" aria-labelledby="nav-btn-mine" hidden>
|
||||
<div class="panel-list">
|
||||
<a href="/miner" data-nav="miner"><b>Ember, the miner</b><span>One click installs the node, the miner and the prover.</span></a>
|
||||
<a href="/download" data-nav="download"><b>Download</b><span>Windows, macOS, Linux and HiveOS.</span></a>
|
||||
<a href="/app" data-nav="app"><b>The app</b><span>What you see while the card mines.</span></a>
|
||||
<a href="/wallet" data-nav="wallet"><b>The wallet</b><span>Your coins. Final means final.</span></a>
|
||||
<a href="/miners" data-nav="miners"><b>GPU bench table</b><span>Measured rates, card by card.</span></a>
|
||||
<a href="/dev-fee" data-nav="dev-fee"><b>The dev fee</b><span>The optional one, in full view, off with one flag.</span></a>
|
||||
<a href="/metamask" data-nav="metamask"><b>Add to MetaMask</b><span>Igneum as a network in your wallet.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-panel" id="nav-panel-network" data-group="network" role="region" aria-labelledby="nav-btn-network" hidden>
|
||||
<div class="panel-list">
|
||||
<a href="/live" data-nav="live"><b>Live devnet</b><span>The chain as it grows, one lane per miner.</span></a>
|
||||
<a href="/explorer" data-nav="explorer"><b>Explorer</b><span>Look a block or an address up.</span></a>
|
||||
<a href="/journey" data-nav="journey"><b>The journey</b><span>Six phases, four gates, the log behind them.</span></a>
|
||||
<a href="/bench" data-nav="bench"><b>Engineering log</b><span>Every measurement, with the commands that made it.</span></a>
|
||||
<a href="/evidence" data-nav="evidence"><b>Evidence</b><span>Every claim and how far it is tested.</span></a>
|
||||
<a href="/light" data-nav="light"><b>Light wallet</b><span>A balance your browser proves, trusting no node.</span></a>
|
||||
<a href="/receipt" data-nav="receipt" aria-current="page"><b>Payment receipt</b><span>A receipt any third party re-verifies offline.</span></a>
|
||||
<a href="/oracle" data-nav="oracle"><b>State oracle on Sepolia</b><span>Devnet 3 balances read from another chain.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-panel" id="nav-panel-learn" data-group="learn" role="region" aria-labelledby="nav-btn-learn" hidden>
|
||||
<div class="panel-list">
|
||||
<a href="/litepaper" data-nav="litepaper"><b>Litepaper</b><span>The design, as published.</span></a>
|
||||
<a href="/income" data-nav="income"><b>Income per tier</b><span>IGN a day per card at three network sizes, and the electricity.</span></a>
|
||||
<a href="/ledger" data-nav="ledger"><b>Ledger</b><span>Every criticism, answered or conceded.</span></a>
|
||||
<a href="/claims" data-nav="claims"><b>What Igneum does not claim</b><span>The limits, stated first.</span></a>
|
||||
<a href="/randomx" data-nav="randomx"><b>Igneum vs RandomX</b><span>What was kept and what was rebuilt for GPUs.</span></a>
|
||||
<a href="/provenance" data-nav="provenance"><b>Built on the shoulders</b><span>Every borrowed part, credited.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-panel" id="nav-panel-build" data-group="build" role="region" aria-labelledby="nav-btn-build" hidden>
|
||||
<div class="panel-list">
|
||||
<a href="/build" data-nav="build"><b>Build on Igneum</b><span>Chain ids, RPC, a contract in five minutes.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Devnet faucet</b><span>10 IGN of devnet coin, once a day.</span></a>
|
||||
<a href="/swap" data-nav="swap"><b>Swap</b><span>Test tokens on Devnet 3; every swap is a proven block.</span></a>
|
||||
<a href="/grants" data-nav="grants"><b>Grants</b><span>Tooling, apps, infrastructure, research.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-sheet" id="nav-sheet" role="dialog" aria-modal="true" aria-label="Menu" hidden>
|
||||
<div class="sheet-scroll">
|
||||
<div class="sheet-group"><div class="sheet-head">Mine</div>
|
||||
<a href="/miner" data-nav="miner"><b>Ember, the miner</b><span>One click installs the node, the miner and the prover.</span></a>
|
||||
<a href="/download" data-nav="download"><b>Download</b><span>Windows, macOS, Linux and HiveOS.</span></a>
|
||||
<a href="/app" data-nav="app"><b>The app</b><span>What you see while the card mines.</span></a>
|
||||
<a href="/wallet" data-nav="wallet"><b>The wallet</b><span>Your coins. Final means final.</span></a>
|
||||
<a href="/miners" data-nav="miners"><b>GPU bench table</b><span>Measured rates, card by card.</span></a>
|
||||
<a href="/dev-fee" data-nav="dev-fee"><b>The dev fee</b><span>The optional one, in full view, off with one flag.</span></a>
|
||||
<a href="/metamask" data-nav="metamask"><b>Add to MetaMask</b><span>Igneum as a network in your wallet.</span></a>
|
||||
</div>
|
||||
<div class="sheet-group"><div class="sheet-head">Network</div>
|
||||
<a href="/live" data-nav="live"><b>Live devnet</b><span>The chain as it grows, one lane per miner.</span></a>
|
||||
<a href="/explorer" data-nav="explorer"><b>Explorer</b><span>Look a block or an address up.</span></a>
|
||||
<a href="/journey" data-nav="journey"><b>The journey</b><span>Six phases, four gates, the log behind them.</span></a>
|
||||
<a href="/bench" data-nav="bench"><b>Engineering log</b><span>Every measurement, with the commands that made it.</span></a>
|
||||
<a href="/evidence" data-nav="evidence"><b>Evidence</b><span>Every claim and how far it is tested.</span></a>
|
||||
<a href="/light" data-nav="light"><b>Light wallet</b><span>A balance your browser proves, trusting no node.</span></a>
|
||||
<a href="/receipt" data-nav="receipt" aria-current="page"><b>Payment receipt</b><span>A receipt any third party re-verifies offline.</span></a>
|
||||
<a href="/oracle" data-nav="oracle"><b>State oracle on Sepolia</b><span>Devnet 3 balances read from another chain.</span></a>
|
||||
</div>
|
||||
<div class="sheet-group"><div class="sheet-head">Learn</div>
|
||||
<a href="/litepaper" data-nav="litepaper"><b>Litepaper</b><span>The design, as published.</span></a>
|
||||
<a href="/income" data-nav="income"><b>Income per tier</b><span>IGN a day per card at three network sizes, and the electricity.</span></a>
|
||||
<a href="/ledger" data-nav="ledger"><b>Ledger</b><span>Every criticism, answered or conceded.</span></a>
|
||||
<a href="/claims" data-nav="claims"><b>What Igneum does not claim</b><span>The limits, stated first.</span></a>
|
||||
<a href="/randomx" data-nav="randomx"><b>Igneum vs RandomX</b><span>What was kept and what was rebuilt for GPUs.</span></a>
|
||||
<a href="/provenance" data-nav="provenance"><b>Built on the shoulders</b><span>Every borrowed part, credited.</span></a>
|
||||
</div>
|
||||
<div class="sheet-group"><div class="sheet-head">Build</div>
|
||||
<a href="/build" data-nav="build"><b>Build on Igneum</b><span>Chain ids, RPC, a contract in five minutes.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Devnet faucet</b><span>10 IGN of devnet coin, once a day.</span></a>
|
||||
<a href="/swap" data-nav="swap"><b>Swap</b><span>Test tokens on Devnet 3; every swap is a proven block.</span></a>
|
||||
<a href="/grants" data-nav="grants"><b>Grants</b><span>Tooling, apps, infrastructure, research.</span></a>
|
||||
</div>
|
||||
<div class="sheet-foot">
|
||||
<a href="/download" class="btn primary big" data-nav="download">Download</a>
|
||||
<div class="sheet-social"><a href="https://discord.gg/igneum" target="_blank" rel="noopener">Discord</a><a href="https://git.igneum.network/igneum-network/spec" target="_blank" rel="noopener">Source</a><a href="https://www.reddit.com/user/Igneum_network/" target="_blank" rel="noopener">Reddit</a></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
<script>
|
||||
(function(){
|
||||
// the slim bar (site-ui-5, 7 Oct 2026): three group buttons open one panel each; the burger opens the sheet on phones.
|
||||
// Keyboard: Enter or Space opens a group, Escape closes it and returns focus to its button, arrows move between the
|
||||
// group buttons, Tab walks the open panel's links, a click outside closes. The theme toggle flips data-theme and stores it.
|
||||
var n=document.querySelector('.nav');if(!n)return;
|
||||
var btns=[].slice.call(n.querySelectorAll('.group-btn')),panels=[].slice.call(n.querySelectorAll('.nav-panel')),wrap=n.querySelector('.panels');
|
||||
var burger=document.getElementById('nav-burger'),sheet=document.getElementById('nav-sheet');
|
||||
function panelOf(g){return panels.filter(function(p){return p.getAttribute('data-group')===g;})[0];}
|
||||
function closeAll(focusBack){var was=null;btns.forEach(function(b){if(b.getAttribute('aria-expanded')==='true')was=b;b.setAttribute('aria-expanded','false');});panels.forEach(function(p){p.hidden=true;});n.classList.remove('panel-open');if(focusBack&&was)was.focus();}
|
||||
function open(g){closeAll(false);var b=btns.filter(function(x){return x.getAttribute('data-group')===g;})[0],p=panelOf(g);if(!b||!p)return;b.setAttribute('aria-expanded','true');p.hidden=false;n.classList.add('panel-open');anchor(b,p);}
|
||||
// the panel sits under its button; a panel that would run past the container's right edge aligns its right edge to the button's right edge instead (never past the viewport)
|
||||
function anchor(b,p){var pw=n.querySelector('.panel-wrap');if(!pw)return;var cr=pw.getBoundingClientRect(),br=b.getBoundingClientRect(),w=p.offsetWidth,left=br.left-cr.left;if(left+w>cr.width)left=(br.right-cr.left)-w;if(left<0)left=0;p.style.setProperty('--panel-left',Math.round(left)+'px');}
|
||||
window.addEventListener('resize',function(){var o=btns.filter(function(x){return x.getAttribute('aria-expanded')==='true';})[0];if(o)anchor(o,panelOf(o.getAttribute('data-group')));}); btns.forEach(function(b,i){
|
||||
b.addEventListener('click',function(){var on=b.getAttribute('aria-expanded')==='true';if(on)closeAll(false);else open(b.getAttribute('data-group'));});
|
||||
b.addEventListener('keydown',function(e){
|
||||
var k=e.key;
|
||||
if(k==='ArrowRight'||k==='ArrowLeft'){e.preventDefault();var j=(i+(k==='ArrowRight'?1:btns.length-1))%btns.length;btns[j].focus();if(n.classList.contains('panel-open'))open(btns[j].getAttribute('data-group'));}
|
||||
else if(k==='ArrowDown'){e.preventDefault();open(b.getAttribute('data-group'));var f=panelOf(b.getAttribute('data-group')).querySelector('a');if(f)f.focus();}
|
||||
else if(k==='Escape'){closeAll(true);}
|
||||
});
|
||||
});
|
||||
if(wrap)wrap.addEventListener('keydown',function(e){if(e.key==='Escape'){e.stopPropagation();closeAll(true);}});
|
||||
document.addEventListener('click',function(e){if(!n.classList.contains('panel-open'))return;if(e.target.closest('.group-btn')||e.target.closest('.nav-panel'))return;closeAll(false);});
|
||||
document.addEventListener('focusin',function(e){if(!n.classList.contains('panel-open'))return;if(n.contains(e.target))return;closeAll(false);});
|
||||
document.addEventListener('keydown',function(e){if(e.key==='Escape'&&n.classList.contains('panel-open'))closeAll(true);});
|
||||
// the sheet on phones
|
||||
function setSheet(o){if(!burger||!sheet)return;n.classList.toggle('open',o);sheet.hidden=!o;burger.setAttribute('aria-expanded',o?'true':'false');burger.setAttribute('aria-label',o?'Close the menu':'Open the menu');document.documentElement.classList.toggle('nav-locked',o);if(o){var f=sheet.querySelector('a');if(f)f.focus();}}
|
||||
if(burger&&sheet){
|
||||
burger.addEventListener('click',function(){setSheet(!n.classList.contains('open'));});
|
||||
sheet.addEventListener('click',function(e){if(e.target.closest('a'))setSheet(false);});
|
||||
sheet.addEventListener('keydown',function(e){
|
||||
if(e.key==='Escape'){setSheet(false);burger.focus();return;}
|
||||
if(e.key!=='Tab')return;var f=sheet.querySelectorAll('a,button');if(!f.length)return;var first=f[0],last=f[f.length-1];
|
||||
if(e.shiftKey&&document.activeElement===first){e.preventDefault();burger.focus();}else if(!e.shiftKey&&document.activeElement===last){e.preventDefault();burger.focus();}
|
||||
});
|
||||
burger.addEventListener('keydown',function(e){if(e.key==='Tab'&&!e.shiftKey&&n.classList.contains('open')){e.preventDefault();var f=sheet.querySelector('a');if(f)f.focus();}});
|
||||
var mq=window.matchMedia('(min-width:861px)');if(mq.addEventListener)mq.addEventListener('change',function(){setSheet(false);});
|
||||
}
|
||||
// the theme toggle
|
||||
var t=n.querySelector('[data-theme-toggle]');
|
||||
function paintToggle(){var dark=document.documentElement.getAttribute('data-theme')!=='light';t.setAttribute('aria-label',dark?'Switch to light theme':'Switch to dark theme');t.innerHTML=dark?'<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><circle cx="12" cy="12" r="4"/><path d="M12 2v2m0 16v2M2 12h2m16 0h2M5 5l1 1m12 12 1 1M5 19l1-1M18 6l1-1"/></svg>':'<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="M20.7 13.3A8.5 8.5 0 0 1 10.7 3.3 8.5 8.5 0 1 0 20.7 13.3Z"/></svg>';}
|
||||
if(t){t.addEventListener('click',function(){var v=document.documentElement.getAttribute('data-theme')==='light'?'dark':'light';document.documentElement.setAttribute('data-theme',v);try{localStorage.setItem('igneum-theme',v);}catch(e){}document.dispatchEvent(new CustomEvent('igneum-theme'));});paintToggle();document.addEventListener('igneum-theme',paintToggle);}
|
||||
})();
|
||||
</script>
|
||||
<!-- nav:end -->
|
||||
<main id="main" class="wrap">
|
||||
<div class="head">
|
||||
<div class="breadcrumb"><a href="/">Igneum</a><span>/</span><span>Payment receipt</span></div>
|
||||
<div class="eyebrow"><span class="line"></span>Reference app 2 · Devnet 3, no value</div>
|
||||
<h1>A receipt any third party re-verifies<span class="accent">.</span></h1>
|
||||
</div>
|
||||
<p class="note">Paste a Devnet 3 transaction hash. This tab fetches the raw transaction, the including block's merkle path, every header up to the certified checkpoint and the certificate, then proves inclusion and finality itself. Download the receipt as JSON. Anyone checks it later with a one-file verifier, offline, with no node and no network.</p>
|
||||
|
||||
<div class="why">
|
||||
<p><b>Why this only works on a proven chain.</b> A merchant's receipt is only worth something if the payment cannot be undone and the proof of that fits in a file: here the certificate is a weighted BLS signature by the miners over a checkpoint, and the block holding the payment hashes into that checkpoint's past. On a chain with probabilistic finality a receipt is a guess that ages well; here it is a fact that a file carries.</p>
|
||||
<p>Source: <code>site/lc/core.js</code> (the checks), <code>site/lc/app.js</code> (this page), <code>tools/reference-apps/receipt/verify-receipt.src.mjs</code> (the one-file verifier, bundled to <code>/lc/verify-receipt.js</code>). Test with the negative cases: <a href="/lc/test">/lc/test</a> in the browser, <code>tools/reference-apps/light-service/verify.test.mjs</code> under Node.</p>
|
||||
</div>
|
||||
|
||||
<section class="card" aria-labelledby="verify">
|
||||
<h2 id="verify">Get a receipt</h2>
|
||||
<form class="vform" data-form="receipt" novalidate>
|
||||
<label for="tx">Transaction hash</label>
|
||||
<div class="row"><input id="tx" name="tx" inputmode="text" autocomplete="off" spellcheck="false" placeholder="0x…" pattern="^0x[0-9a-fA-F]{64}$"><button class="btn primary" type="submit">Prove it in this tab</button></div>
|
||||
<div class="vstatus" data-status role="status" aria-live="polite">Devnet 3, no value. A transaction is final once a certified checkpoint has it in its past, about 30 to 90 s after it executes.</div>
|
||||
</form>
|
||||
<div data-result></div>
|
||||
</section>
|
||||
|
||||
<h2 id="offline">Re-verify offline</h2>
|
||||
<p class="note">The verifier is one file of plain JavaScript with the hashing and curve code inside it: <a href="/lc/verify-receipt.js" download>verify-receipt.js</a>. It runs under Node 18 or later (<code>node verify-receipt.js receipt.json</code>) and prints each check, then <code>VERIFIED</code> or <code>REFUSED</code> with the reason. It fetches nothing. Flip one byte of the file and it is refused: <code>node verify-receipt.js receipt.json --tamper</code> runs that case first so you see the refusal before the verdict.</p>
|
||||
<h2 id="checked">What the receipt proves</h2>
|
||||
<ol>
|
||||
<li>The transaction hash is keccak256 of the raw signed transaction in the file, so the recipient, the amount and the data are the signed ones.</li>
|
||||
<li>The transaction is a leaf of the including block's <code>hash_merkle_root</code> (BLAKE2b-256 keyed MerkleBranchHash up the path).</li>
|
||||
<li>Every header from the including block to the certified checkpoint recomputes and links to the next by a direct parent.</li>
|
||||
<li>The certificate over that checkpoint verifies: the aggregate BLS signature of the signers, the voter order, two thirds of active weight and 17/30 of total.</li>
|
||||
</ol>
|
||||
<p class="note">Not proven by the file: the execution result (status, gas) is carried as the node reported it and labelled so; the voter table with weights comes from the node (spec 10.1). Both are named on the result.</p>
|
||||
<p class="asof">Devnet 3, no value. The chain may reset. A demonstration of the verification path, not a product.</p>
|
||||
</main>
|
||||
<script type="module" src="/lc/app.js"></script>
|
||||
<!-- footer:start -->
|
||||
<footer class="site-footer">
|
||||
<div class="container">
|
||||
<div class="footer-grid">
|
||||
<div class="footer-brand">
|
||||
<a href="/" class="logo" aria-label="Igneum home"><svg class="brand-mark" viewBox="0 0 1024 1024" aria-hidden="true"><rect width="1024" height="1024" rx="160" fill="#0C0C0E"></rect><g transform="translate(166.95 166.95) scale(6.901)"><polygon points="50,4 74,34 67,58 80,54 61,96 39,96 20,54 33,58 26,34" fill="#F2541B"></polygon><polygon points="50,42 59,58 50,82 41,58" fill="#0C0C0E"></polygon></g></svg><span class="word">IGNEUM</span><span class="stop">.</span></a>
|
||||
<p>Mined by GPUs. Proven by fire.</p>
|
||||
<div class="social" aria-label="Igneum elsewhere">
|
||||
<a href="https://git.igneum.network/igneum-network/spec" target="_blank" rel="noopener" aria-label="Igneum source: the spec, the vectors and the issues"><svg viewBox="0 0 24 24" width="22" height="22" fill="currentColor" aria-hidden="true"><path d="M8.6 17.6 3 12l5.6-5.6 1.4 1.4L5.8 12l4.2 4.2zm6.8 0-1.4-1.4L18.2 12 14 7.8l1.4-1.4L21 12z"></path></svg></a>
|
||||
<a href="https://discord.gg/igneum" target="_blank" rel="noopener" aria-label="The Igneum Discord"><svg viewBox="0 0 24 24" width="22" height="22" fill="currentColor" aria-hidden="true"><path d="M19.6 5.3A17 17 0 0 0 15.4 4l-.2.4a15.6 15.6 0 0 1 3.9 1.9 13.6 13.6 0 0 0-14.2 0A15.6 15.6 0 0 1 8.8 4.4L8.6 4a17 17 0 0 0-4.2 1.3C1.8 9.2 1.1 13 1.4 16.7a17.1 17.1 0 0 0 5.2 2.6l1.1-1.8a10.8 10.8 0 0 1-1.7-.8l.4-.3a12.2 12.2 0 0 0 11.2 0l.4.3-1.7.8 1.1 1.8a17 17 0 0 0 5.2-2.6c.4-4.3-.7-8-3-11.4zM8.7 14.4c-1 0-1.8-.9-1.8-2.1s.8-2.1 1.8-2.1 1.9 1 1.8 2.1c0 1.2-.8 2.1-1.8 2.1zm6.6 0c-1 0-1.8-.9-1.8-2.1s.8-2.1 1.8-2.1 1.9 1 1.8 2.1c0 1.2-.8 2.1-1.8 2.1z"></path></svg></a>
|
||||
<a data-social="reddit" href="https://www.reddit.com/user/Igneum_network/" target="_blank" rel="noopener" aria-label="Igneum on Reddit"><svg viewBox="0 0 24 24" width="22" height="22" fill="currentColor" aria-hidden="true"><path d="M22 12.1a2.2 2.2 0 0 0-3.7-1.6 10.8 10.8 0 0 0-5.8-1.8l1-4.6 3.2.7a1.5 1.5 0 1 0 .2-.9l-3.6-.8a.5.5 0 0 0-.5.4l-1.1 5.2a10.8 10.8 0 0 0-5.9 1.8A2.2 2.2 0 1 0 3.4 14a4.3 4.3 0 0 0 0 .7c0 3.4 3.9 6.1 8.6 6.1s8.6-2.7 8.6-6.1a4.3 4.3 0 0 0 0-.7 2.2 2.2 0 0 0 1.4-1.9zM7 13.6a1.5 1.5 0 1 1 1.5 1.5A1.5 1.5 0 0 1 7 13.6zm8.6 4.1a5.7 5.7 0 0 1-3.6 1.1 5.7 5.7 0 0 1-3.6-1.1.4.4 0 0 1 .6-.6 4.9 4.9 0 0 0 3 .9 4.9 4.9 0 0 0 3-.9.4.4 0 0 1 .6.6zm-.3-2.6a1.5 1.5 0 1 1 1.5-1.5 1.5 1.5 0 0 1-1.5 1.5z"></path></svg></a>
|
||||
</div>
|
||||
<div class="footer-dl" aria-label="Download Ember"><a href="/download#windows"><span class="osmark mini" data-os="windows" title="Windows"><svg viewBox="0 0 24 24" width="22" height="22" aria-hidden="true" focusable="false" fill="currentColor"><path d="M3 5.6l7.3-1v7.1H3zM11.4 4.4L21 3v8.7h-9.6zM3 12.3h7.3v7.1L3 18.4zM11.4 12.3H21V21l-9.6-1.4z"/></svg></span>Windows</a><a href="/download#mac"><span class="osmark mini" data-os="mac" title="macOS"><svg viewBox="0 0 24 24" width="22" height="22" aria-hidden="true" focusable="false" fill="currentColor"><path d="M16.4 12.6c0-2.5 2-3.6 2.1-3.7-1.2-1.7-3-1.9-3.6-2-1.5-.2-3 .9-3.8.9-.8 0-2-.9-3.3-.8-1.7 0-3.2 1-4.1 2.5-1.8 3-.5 7.6 1.3 10.1.9 1.2 1.9 2.6 3.2 2.5 1.3 0 1.8-.8 3.3-.8 1.6 0 2 .8 3.3.8 1.4 0 2.3-1.2 3.1-2.5 1-1.4 1.4-2.8 1.4-2.9 0 0-2.7-1-2.9-4.1zM13.9 5.3c.7-.8 1.2-2 1-3.2-1 0-2.2.7-2.9 1.5-.6.7-1.2 1.9-1 3 1.1.1 2.2-.5 2.9-1.3z"/></svg></span>macOS</a><a href="/download#linux"><span class="osmark mini" data-os="linux" title="Linux"><svg viewBox="0 0 24 24" width="22" height="22" aria-hidden="true" focusable="false" fill="currentColor"><path d="M12 2c-2.4 0-4 1.9-4 4.6 0 1.2.2 2 0 2.8-.6 1.4-2.1 2.9-2.6 4.9-.3 1.1-.1 2 .3 2.6-.6.4-1.3 1-1.1 1.7.3 1 2.1 1.2 3.2 1.8.7.4 1.5.6 2.1.1.6.2 1.3.3 2.1.3s1.5-.1 2.1-.3c.6.5 1.4.3 2.1-.1 1.1-.6 2.9-.8 3.2-1.8.2-.7-.5-1.3-1.1-1.7.4-.6.6-1.5.3-2.6-.5-2-2-3.5-2.6-4.9-.2-.8 0-1.6 0-2.8C16 3.9 14.4 2 12 2zm-1.4 4.2c.5 0 .8.5.8 1.2s-.3 1.2-.8 1.2-.8-.5-.8-1.2.3-1.2.8-1.2zm2.8 0c.5 0 .8.5.8 1.2s-.3 1.2-.8 1.2-.8-.5-.8-1.2.3-1.2.8-1.2zM12 9.3c.9 0 1.9.5 1.9 1s-1 1.2-1.9 1.2-1.9-.7-1.9-1.2 1-1 1.9-1zm0 3.4c2.2 0 3.6 2.6 3.6 4.4 0 1.5-1.6 2.3-3.6 2.3s-3.6-.8-3.6-2.3c0-1.8 1.4-4.4 3.6-4.4z"/></svg></span>Linux</a><a href="/download#hive"><span class="osmark mini" data-os="hive" title="HiveOS"><svg viewBox="0 0 24 24" width="22" height="22" aria-hidden="true" focusable="false" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linejoin="round" stroke-linecap="round"><path d="M12 2.6 20.2 7.3v9.4L12 21.4 3.8 16.7V7.3z"/><path d="M12 7.4 16 9.7v4.6L12 16.6 8 14.3V9.7z"/><path d="M12 7.4V2.6M16 9.7l4.2-2.4M16 14.3l4.2 2.4M12 16.6v4.8M8 14.3l-4.2 2.4M8 9.7 3.8 7.3"/></svg></span>HiveOS</a></div>
|
||||
<a href="https://git.igneum.network/igneum-network/spec" target="_blank" rel="noopener" class="text-link">Specification and test vectors<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="M6 18 18 6M6 6h12v12"/></svg></a>
|
||||
</div>
|
||||
<div class="footer-column"><h4>Run</h4><div>
|
||||
<a href="/download">Download Ember</a>
|
||||
<a href="/miner">The miner</a>
|
||||
<a href="/app">The app</a>
|
||||
<a href="/wallet">The wallet</a>
|
||||
<a href="/miners">GPU bench table</a>
|
||||
<a href="/dev-fee">The dev fee</a>
|
||||
<a href="/faucet">Devnet faucet</a>
|
||||
<a href="/metamask">Add Igneum to MetaMask</a>
|
||||
</div></div>
|
||||
<div class="footer-column"><h4>Read</h4><div>
|
||||
<a href="/litepaper">Litepaper</a>
|
||||
<a href="/evidence">Evidence</a>
|
||||
<a href="/bench">Engineering log</a>
|
||||
<a href="/ledger">Ledger: every criticism</a>
|
||||
<a href="/claims">What Igneum does not claim</a>
|
||||
<a href="/randomx">Igneum vs RandomX</a>
|
||||
<a href="/provenance">Built on the shoulders</a>
|
||||
</div></div>
|
||||
<div class="footer-column"><h4>Explore</h4><div>
|
||||
<a href="/live">Live devnet</a>
|
||||
<a href="/explorer">Explorer</a>
|
||||
<a href="/build">Build on Igneum</a>
|
||||
<a href="/swap">Swap</a>
|
||||
<a href="/grants">Grants</a>
|
||||
<a href="/journey">Journey</a>
|
||||
<a href="/download">Downloads: devnet build</a>
|
||||
<a href="https://discord.gg/igneum" target="_blank" rel="noopener">Community Discord</a>
|
||||
<a href="mailto:hello@igneum.network">hello@igneum.network</a>
|
||||
<a href="https://git.igneum.network/igneum-network/spec/issues" rel="noopener">An issue on the spec</a>
|
||||
</div></div>
|
||||
</div>
|
||||
<div class="footer-bottom">
|
||||
<p>Igneum Labs LTD · Unit IH-00-01-01-OF-01, Level 01, Innovation One, Dubai International Financial Centre. Experimental software. Nothing on this site is an offer to sell anything.<br>Report a flaw by email or by an issue on the spec. Nobody from Igneum will ask for your seed. © 2026 Igneum · not an offer to sell anything</p>
|
||||
<div class="theme-group" role="group" aria-label="Theme"><button type="button" data-theme-set="system" aria-pressed="true">System</button><button type="button" data-theme-set="light" aria-pressed="false">Light</button><button type="button" data-theme-set="dark" aria-pressed="false">Dark</button></div>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
<script>
|
||||
(function(){
|
||||
// theme control: stores light or dark under igneum-theme; system clears it and follows the OS. The head applied the value before paint.
|
||||
var bs=document.querySelectorAll('[data-theme-set]');if(!bs.length)return;
|
||||
var media=window.matchMedia('(prefers-color-scheme: light)');
|
||||
function stored(){try{var t=localStorage.getItem('igneum-theme');return t==='light'||t==='dark'?t:'system';}catch(e){return 'system';}}
|
||||
function apply(){var c=stored();document.documentElement.setAttribute('data-theme',c==='system'?(media.matches?'light':'dark'):c);bs.forEach(function(b){b.setAttribute('aria-pressed',b.getAttribute('data-theme-set')===c?'true':'false');});document.dispatchEvent(new CustomEvent('igneum-theme'));}
|
||||
bs.forEach(function(b){b.addEventListener('click',function(){var v=b.getAttribute('data-theme-set');try{if(v==='system')localStorage.removeItem('igneum-theme');else localStorage.setItem('igneum-theme',v);}catch(e){}apply();});});
|
||||
if(media.addEventListener)media.addEventListener('change',function(){if(stored()==='system')apply();});
|
||||
document.addEventListener('igneum-theme',function(){var c=stored();bs.forEach(function(b){b.setAttribute('aria-pressed',b.getAttribute('data-theme-set')===c?'true':'false');});});
|
||||
bs.forEach(function(b){b.setAttribute('aria-pressed',b.getAttribute('data-theme-set')===stored()?'true':'false');});
|
||||
// the network state word in the status bar: one read of the observer per page view
|
||||
var fs=document.getElementById('foot-state'),fd=document.getElementById('foot-dot');if(fs&&fd){fetch('/api/live?window=30',{cache:'no-store'}).then(function(r){return r.json();}).then(function(d){var on=d&&d.ok&&d.state&&!d.state.stale;fs.textContent=on?'devnet live':'devnet, observer stale';fd.className='dot '+(on?'live':'off');}).catch(function(){fs.textContent='devnet';});}
|
||||
})();
|
||||
</script>
|
||||
<!-- footer:end -->
|
||||
<script>
|
||||
(function(){
|
||||
// one request per button; the wallet shows the chain to the user and decides. No key, no seed, no signature here.
|
||||
var CHAINS = {
|
||||
testnet: { chainId: '0x116e', chainName: 'Igneum Testnet', nativeCurrency: { name: 'Igneum', symbol: 'IGN', decimals: 18 }, rpcUrls: ['https://rpc.testnet.igneum.network'], blockExplorerUrls: [] },
|
||||
devnet: { chainId: '0x116f', chainName: 'Igneum Devnet (local node)', nativeCurrency: { name: 'Igneum', symbol: 'IGN', decimals: 18 }, rpcUrls: ['http://127.0.0.1:26790'], blockExplorerUrls: [] }
|
||||
};
|
||||
function status(name, text) { var el = document.querySelector('[data-status="' + name + '"]'); if (el) el.textContent = text; }
|
||||
Array.prototype.forEach.call(document.querySelectorAll('[data-add]'), function (btn) {
|
||||
btn.addEventListener('click', function () {
|
||||
var name = btn.getAttribute('data-add'); var chain = CHAINS[name];
|
||||
if (!window.ethereum || !window.ethereum.request) { status(name, 'No Ethereum wallet found in this browser. Install MetaMask, or add the network by hand (below).'); return; }
|
||||
status(name, 'Waiting for the wallet...');
|
||||
window.ethereum.request({ method: 'wallet_addEthereumChain', params: [chain] })
|
||||
.then(function () { status(name, 'Added. The wallet is on ' + chain.chainName + ' (chain id ' + parseInt(chain.chainId, 16) + ').'); })
|
||||
.catch(function (e) { status(name, e && e.code === 4001 ? 'Cancelled in the wallet.' : 'The wallet refused: ' + ((e && e.message) || 'unknown error') + '. Add it by hand (below).'); });
|
||||
});
|
||||
});
|
||||
})();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -64,6 +64,7 @@
|
|||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-mine" data-group="mine" aria-expanded="false" aria-controls="nav-panel-mine" aria-haspopup="true">Mine<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-network" data-group="network" aria-expanded="false" aria-controls="nav-panel-network" aria-haspopup="true">Network<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-learn" data-group="learn" aria-expanded="false" aria-controls="nav-panel-learn" aria-haspopup="true">Learn<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
<div class="nav-group" role="listitem"><button type="button" class="group-btn" id="nav-btn-build" data-group="build" aria-expanded="false" aria-controls="nav-panel-build" aria-haspopup="true">Build<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5"/></svg></button></div>
|
||||
</div>
|
||||
<div class="nav-controls">
|
||||
<button class="btn icon-btn" type="button" data-theme-toggle aria-label="Switch to light theme"><svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><circle cx="12" cy="12" r="4"/><path d="M12 2v2m0 16v2M2 12h2m16 0h2M5 5l1 1m12 12 1 1M5 19l1-1M18 6l1-1"/></svg></button>
|
||||
|
|
@ -81,7 +82,6 @@
|
|||
<a href="/wallet" data-nav="wallet"><b>The wallet</b><span>Your coins. Final means final.</span></a>
|
||||
<a href="/miners" data-nav="miners"><b>GPU bench table</b><span>Measured rates, card by card.</span></a>
|
||||
<a href="/dev-fee" data-nav="dev-fee"><b>The dev fee</b><span>The optional one, in full view, off with one flag.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Testnet faucet</b><span>Test coin for an address, once a day.</span></a>
|
||||
<a href="/metamask" data-nav="metamask"><b>Add to MetaMask</b><span>Igneum as a network in your wallet.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -92,6 +92,9 @@
|
|||
<a href="/journey" data-nav="journey"><b>The journey</b><span>Six phases, four gates, the log behind them.</span></a>
|
||||
<a href="/bench" data-nav="bench"><b>Engineering log</b><span>Every measurement, with the commands that made it.</span></a>
|
||||
<a href="/evidence" data-nav="evidence"><b>Evidence</b><span>Every claim and how far it is tested.</span></a>
|
||||
<a href="/light" data-nav="light"><b>Light wallet</b><span>A balance your browser proves, trusting no node.</span></a>
|
||||
<a href="/receipt" data-nav="receipt"><b>Payment receipt</b><span>A receipt any third party re-verifies offline.</span></a>
|
||||
<a href="/oracle" data-nav="oracle"><b>State oracle on Sepolia</b><span>Devnet 3 balances read from another chain.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-panel" id="nav-panel-learn" data-group="learn" role="region" aria-labelledby="nav-btn-learn" hidden>
|
||||
|
|
@ -104,6 +107,14 @@
|
|||
<a href="/provenance" data-nav="provenance"><b>Built on the shoulders</b><span>Every borrowed part, credited.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-panel" id="nav-panel-build" data-group="build" role="region" aria-labelledby="nav-btn-build" hidden>
|
||||
<div class="panel-list">
|
||||
<a href="/build" data-nav="build"><b>Build on Igneum</b><span>Chain ids, RPC, a contract in five minutes.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Devnet faucet</b><span>10 IGN of devnet coin, once a day.</span></a>
|
||||
<a href="/swap" data-nav="swap"><b>Swap</b><span>Test tokens on Devnet 3; every swap is a proven block.</span></a>
|
||||
<a href="/grants" data-nav="grants"><b>Grants</b><span>Tooling, apps, infrastructure, research.</span></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-sheet" id="nav-sheet" role="dialog" aria-modal="true" aria-label="Menu" hidden>
|
||||
|
|
@ -115,7 +126,6 @@
|
|||
<a href="/wallet" data-nav="wallet"><b>The wallet</b><span>Your coins. Final means final.</span></a>
|
||||
<a href="/miners" data-nav="miners"><b>GPU bench table</b><span>Measured rates, card by card.</span></a>
|
||||
<a href="/dev-fee" data-nav="dev-fee"><b>The dev fee</b><span>The optional one, in full view, off with one flag.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Testnet faucet</b><span>Test coin for an address, once a day.</span></a>
|
||||
<a href="/metamask" data-nav="metamask"><b>Add to MetaMask</b><span>Igneum as a network in your wallet.</span></a>
|
||||
</div>
|
||||
<div class="sheet-group"><div class="sheet-head">Network</div>
|
||||
|
|
@ -124,6 +134,9 @@
|
|||
<a href="/journey" data-nav="journey"><b>The journey</b><span>Six phases, four gates, the log behind them.</span></a>
|
||||
<a href="/bench" data-nav="bench"><b>Engineering log</b><span>Every measurement, with the commands that made it.</span></a>
|
||||
<a href="/evidence" data-nav="evidence"><b>Evidence</b><span>Every claim and how far it is tested.</span></a>
|
||||
<a href="/light" data-nav="light"><b>Light wallet</b><span>A balance your browser proves, trusting no node.</span></a>
|
||||
<a href="/receipt" data-nav="receipt"><b>Payment receipt</b><span>A receipt any third party re-verifies offline.</span></a>
|
||||
<a href="/oracle" data-nav="oracle"><b>State oracle on Sepolia</b><span>Devnet 3 balances read from another chain.</span></a>
|
||||
</div>
|
||||
<div class="sheet-group"><div class="sheet-head">Learn</div>
|
||||
<a href="/litepaper" data-nav="litepaper"><b>Litepaper</b><span>The design, as published.</span></a>
|
||||
|
|
@ -133,6 +146,12 @@
|
|||
<a href="/randomx" data-nav="randomx"><b>Igneum vs RandomX</b><span>What was kept and what was rebuilt for GPUs.</span></a>
|
||||
<a href="/provenance" data-nav="provenance"><b>Built on the shoulders</b><span>Every borrowed part, credited.</span></a>
|
||||
</div>
|
||||
<div class="sheet-group"><div class="sheet-head">Build</div>
|
||||
<a href="/build" data-nav="build"><b>Build on Igneum</b><span>Chain ids, RPC, a contract in five minutes.</span></a>
|
||||
<a href="/faucet" data-nav="faucet"><b>Devnet faucet</b><span>10 IGN of devnet coin, once a day.</span></a>
|
||||
<a href="/swap" data-nav="swap"><b>Swap</b><span>Test tokens on Devnet 3; every swap is a proven block.</span></a>
|
||||
<a href="/grants" data-nav="grants"><b>Grants</b><span>Tooling, apps, infrastructure, research.</span></a>
|
||||
</div>
|
||||
<div class="sheet-foot">
|
||||
<a href="/download" class="btn primary big" data-nav="download">Download</a>
|
||||
<div class="sheet-social"><a href="https://discord.gg/igneum" target="_blank" rel="noopener">Discord</a><a href="https://git.igneum.network/igneum-network/spec" target="_blank" rel="noopener">Source</a><a href="https://www.reddit.com/user/Igneum_network/" target="_blank" rel="noopener">Reddit</a></div>
|
||||
|
|
@ -247,7 +266,7 @@
|
|||
<a href="/wallet">The wallet</a>
|
||||
<a href="/miners">GPU bench table</a>
|
||||
<a href="/dev-fee">The dev fee</a>
|
||||
<a href="/faucet">Testnet faucet</a>
|
||||
<a href="/faucet">Devnet faucet</a>
|
||||
<a href="/metamask">Add Igneum to MetaMask</a>
|
||||
</div></div>
|
||||
<div class="footer-column"><h4>Read</h4><div>
|
||||
|
|
@ -262,6 +281,9 @@
|
|||
<div class="footer-column"><h4>Explore</h4><div>
|
||||
<a href="/live">Live devnet</a>
|
||||
<a href="/explorer">Explorer</a>
|
||||
<a href="/build">Build on Igneum</a>
|
||||
<a href="/swap">Swap</a>
|
||||
<a href="/grants">Grants</a>
|
||||
<a href="/journey">Journey</a>
|
||||
<a href="/download">Downloads: devnet build</a>
|
||||
<a href="https://discord.gg/igneum" target="_blank" rel="noopener">Community Discord</a>
|
||||
|
|
|
|||
|
|
@ -6,10 +6,14 @@
|
|||
<url><loc>https://igneum.network/app</loc><lastmod>2026-10-07</lastmod><changefreq>weekly</changefreq><priority>0.8</priority></url>
|
||||
<url><loc>https://igneum.network/wallet</loc><lastmod>2026-10-07</lastmod><changefreq>monthly</changefreq><priority>0.6</priority></url>
|
||||
<url><loc>https://igneum.network/live</loc><lastmod>2026-10-07</lastmod><changefreq>daily</changefreq><priority>0.7</priority></url>
|
||||
<url><loc>https://igneum.network/explorer</loc><lastmod>2026-10-07</lastmod><changefreq>daily</changefreq><priority>0.5</priority></url>
|
||||
<url><loc>https://igneum.network/explorer</loc><lastmod>2026-10-08</lastmod><changefreq>daily</changefreq><priority>0.5</priority></url>
|
||||
<url><loc>https://igneum.network/proving</loc><lastmod>2026-10-08</lastmod><changefreq>daily</changefreq><priority>0.4</priority></url>
|
||||
<url><loc>https://igneum.network/ledger</loc><lastmod>2026-10-07</lastmod><changefreq>weekly</changefreq><priority>0.6</priority></url>
|
||||
<url><loc>https://igneum.network/bench</loc><lastmod>2026-10-07</lastmod><changefreq>weekly</changefreq><priority>0.6</priority></url>
|
||||
<url><loc>https://igneum.network/evidence</loc><lastmod>2026-10-07</lastmod><changefreq>weekly</changefreq><priority>0.6</priority></url>
|
||||
<url><loc>https://igneum.network/light</loc><lastmod>2026-10-08</lastmod><changefreq>weekly</changefreq><priority>0.6</priority></url>
|
||||
<url><loc>https://igneum.network/receipt</loc><lastmod>2026-10-08</lastmod><changefreq>weekly</changefreq><priority>0.6</priority></url>
|
||||
<url><loc>https://igneum.network/oracle</loc><lastmod>2026-10-08</lastmod><changefreq>weekly</changefreq><priority>0.6</priority></url>
|
||||
<url><loc>https://igneum.network/miners</loc><lastmod>2026-10-07</lastmod><changefreq>weekly</changefreq><priority>0.6</priority></url>
|
||||
<url><loc>https://igneum.network/journey</loc><lastmod>2026-10-07</lastmod><changefreq>weekly</changefreq><priority>0.5</priority></url>
|
||||
<url><loc>https://igneum.network/claims</loc><lastmod>2026-10-07</lastmod><changefreq>monthly</changefreq><priority>0.5</priority></url>
|
||||
|
|
@ -17,5 +21,8 @@
|
|||
<url><loc>https://igneum.network/provenance</loc><lastmod>2026-10-07</lastmod><changefreq>monthly</changefreq><priority>0.4</priority></url>
|
||||
<url><loc>https://igneum.network/dev-fee</loc><lastmod>2026-10-07</lastmod><changefreq>monthly</changefreq><priority>0.4</priority></url>
|
||||
<url><loc>https://igneum.network/metamask</loc><lastmod>2026-10-07</lastmod><changefreq>monthly</changefreq><priority>0.4</priority></url>
|
||||
<url><loc>https://igneum.network/faucet</loc><lastmod>2026-10-07</lastmod><changefreq>monthly</changefreq><priority>0.4</priority></url>
|
||||
<url><loc>https://igneum.network/faucet</loc><lastmod>2026-10-08</lastmod><changefreq>monthly</changefreq><priority>0.4</priority></url>
|
||||
<url><loc>https://igneum.network/build</loc><lastmod>2026-10-08</lastmod><changefreq>weekly</changefreq><priority>0.8</priority></url>
|
||||
<url><loc>https://igneum.network/swap</loc><lastmod>2026-10-08</lastmod><changefreq>weekly</changefreq><priority>0.5</priority></url>
|
||||
<url><loc>https://igneum.network/grants</loc><lastmod>2026-10-08</lastmod><changefreq>monthly</changefreq><priority>0.6</priority></url>
|
||||
</urlset>
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue