the vertical slice of the phase-1 root chain — 2026-10-16
One block from genesis to a second machine, locally: the consensus kernel
(#189), the reference miner (#186) and the wire (#187) in one binary, three
nodes on one machine, every block mined by soft3 mine --backend cpu
against a node's /template + /submit, every header, body and transaction
crossing the radio wire to the other nodes and validated there by the
kernel. Requirements: specs/chain.md, specs/chain-wire.md,
specs/chain-conformance.md. Earlier receipts: audit/chain/net-2026-10-15.md
(the wire on its stand-in), audit/chain/mine-2026-10-15.md,
audit/chain/conformance-2026-10-16.md.
what changed
- main: #186 merged on the kernel (
4527df7, merge offeat/chain-mine-on-kernel= #186 + the swap f1f4e94: the miner askschain::{header, pow, daa}, its local ASERT copy is gone). - #187 brought onto main as one squashed commit (the branch carried a merge
of main whose own changes a commit-by-commit rebase would drop), then:
chain/net/devchain.rsdeleted;chain/net/kernel.rsimplements the wire's portChainViewover the kernel'sChainApi: header-first acceptance,NeedBodies(the wire fetches the named bodies from the peer and resubmits,gossip::apply_fetched; IBD takes the gap by ranges),FutureTimeheld and retried each sync tick,DeepFork/Checkpointlogged and never scored,ChainError::Blockscores the serving peer +10, tip-moved events carry the reorged-out bodies, a main-chain txid index forGET /tx/{txid}. Headers and u256 cross as their wire bytes; a test pins header ids, txids, bodies and tx roots on both codecs.- mempool admission asks the kernel (
validate_txwith the neuron's lower pending nonces); a nonce gap inside the window is not scored, a nonce beyond it is (+10). The kernel'svalidate_txnow checks the signature before nonce, fee and balance — chain-wire §4's order; the adversarial tx flood (unsigned junk at fee 0) was going unscored without it. - HTTP §7 on the kernel:
/tipand/templaterendered byTip::json/Template::json;/nonce{neuron, nonce, confirmed};POST /tx{txid, kind, size, fee, account, nonce}(already present = 200);GET /tx/{txid}{txid, kind, tx, height|"mempool", block, index}, 404{"error":"unknown"};POST /submit200 / 409 stale / 422 with the kernel's reason./statusgenesisis the chain id (what the wallet signs for),genesis-block,next-bitsfrom ASERT,finalized. - the node no longer mines (
--mine/--solo/--miner,/dev/minegone): mining issoft3 mine.soft3 chain genesis-devwrites a realGenesisFile(kernel-checked, launch names refused),soft3 chain key|txsign withsoft3::wallet::Signer. - gossip topic loops survive a lagged receiver instead of ending.
[profile.dev.package.cyber-hemera] opt-level = 3: tests mine real blocks at the floor target on debug builds.scripts/chain-fleet.nu: miners aresoft3 mineprocesses; every pid it spawns is recorded in$work/pidsand killed by pid — thepkill -fis gone.
Test chain: dev, bits = POW_LIMIT_BITS (0x1e100000, 2^20 expected
hashes, the easiest target the kernel accepts outside cfg(test)), genesis
time two hours back so ASERT sits at the floor for the first ~240 blocks.
No launch genesis is touched; genesis-dev refuses pussy, bostrom,
pussy-rc.
Hash: hemera 0.3 (hemera d5f0a09). Every hash on the slice goes through
the hemera API (hemera::hash, the kernel's hash32, the miner's sponge
view); the move to hemera 0.4 (profile #15) re-blesses PoW vectors, the
genesis particle and chain.snap in its own sweep.
stand
~/cyber/.stands/N2, Apple M4 Max, macOS 26.4.1. soft3 on slice/net
over main 4527df7. Siblings at the kernel receipt's integration base
(bbg 1d39975, cybergraph 0eae7ae, foculus 9e32aa6, mudra 4bfe3e8,
zheng 0c882e7, joy 06de02c), lens e11eaa8 (release/0.2), nox
2f09ca3 / trident a3cef15f (release/0.4), hemera d5f0a09, radio
50600cc1, tade c7d404a. Deviation from the requested pins: zheng
release/0.4 and bbg master do not build with soft3 main (bbg master lacks
the vendored fjall the chain store uses; bbg 1d39975 needs zheng's
feat/public-certificate-v3 API), so both stay at the kernel receipt's
base.
one block from genesis to a second machine
cargo build --release --locked --bins # 1 m 34 s incremental
nu scripts/chain-fleet.nu --bin .target/release/soft3 --keep
chain-fleet: 3 nodes · chain dev · binary …/.target/release/soft3
ok binary speaks the phase-1 flags
ok ports free: http 17780,17781,17782,17783 radio 17790,17791,17792,17793
ok homes + genesis + peers under /tmp/chain-fleet.wVWUzs; wallet aaaeb678a…
chain-fleet: launched pids 74396 74398 74400
ok all 3 nodes answer /status
chain-fleet: soft3 mine --backend cpu --threads 1 on node-1 (pid 74421) and node-2 (pid 74423)
ok peers connected: node-1=1 node-2=1 node-3=2
ok block 1 f9a96f3fc444d… mined by 111111111… is block 1 on every node
ok heights agree at 7 across 3 nodes
chain-fleet: late joiner node-4 pid 75323
ok late joiner synced to height 8 (IBD by ranges)
txid 7d26e8969032a03206a0996e1402f2ad1a0280b4fc8c72af2bc0425edf6e0117
ok tx 7d26e8969… submitted to node-1, mined at 10 by node-2's miner 222222222…, bob=5 on node-3
ok fork of depth 3 from 10: main 13 reorged to the heavier chain 15, tip 2e253b946… on every node
chain-fleet: node-3 killed and relaunched as pid 76024
ok node-3 recovered from disk: height 15 before the kill, 22 after restart (replayed, then synced), conserved
chain-fleet: artifacts kept in /tmp/chain-fleet.wVWUzs
chain-fleet: GREEN
Block 1, end to end (node-1's miner log, then node-2 and node-3):
soft3 mine · chain dev · node http://127.0.0.1:17780 · cpu (1 threads) · to 1111…1111
template height 1 prev 50453f910886… bits 0x1e100000 (2^20 expected hashes)
found nonce 0x7d717dafd5726d8b00000000000ff34b after 1048576 hashes, 3.9s
block 1 accepted: f9a96f3fc444da08fdb30839140110d8c38ce8364922fbe31a4f410de3020000
node-2 net · header f9a96f3f at 1 from 630a8dba
node-3 net · header f9a96f3f at 1 from 630a8dba
An earlier run the same day (/tmp/chain-fleet.Q7vBAc) was GREEN too:
heights 11, late joiner IBD of 11 blocks in one range, tx mined at 13 by
node-2's miner, depth-3 fork from 14 (main 17 → fork 19), node-3 19 → 20
after restart. After both runs no process of the fleet was left.
the gates
| gate | command | result |
|---|---|---|
| soft3 tests | cargo test --locked (crate/) |
208 lib + 12 bin + 2 adversarial + 1 miner e2e, all ok, with HOME holding a main-format pussy genesis (below) |
| chain conformance tests | cargo test --locked --features chain-conformance --lib chain:: |
106 ok |
| adversarial set | cargo test --locked --test chain_adversary |
2 ok (7.8 s): oversize, malformed, no-dialect, wrong chain, PoW-invalid header (no body requested), bad block +10 not banned, tx flood banned, body on gossip banned — against a kernel node mined by soft3 mine |
| conformance | soft3 conformance check chain --genesis /tmp/n2-genesis/pussy.tade |
chain.snap: 9 entries, no drift |
stack-chain-genesis |
chain_genesis_gate(…, genesis_dir=/tmp/n2-genesis) from release/train_gates.py |
exit 0, no drift, recorded red — the gate fails on any warning: line, and bbg 1d39975's vendored fjall prints 3 (journal_recovery_mode, outstanding_flushes, write_tx lifetime); soft3 prints none. Same on main at this bbg pin. |
The pussy genesis for the conformance rows was rebuilt from the pinned
snapshot with this build into a private directory:
soft3 genesis build --chain pussy --snapshot ~/cyber/space-pussy/snapshot --out /tmp/n2-genesis/pussy.tade
(4.4 s) → particle 2a83e54f…61b5, state root f2296834…5827, block 0
b863ce28…a304: the blessed vectors. The shared cache
~/cyber/.cache/genesis/pussy.tade was rewritten at 11:07 today by an
unmerged branch with a longer params record (pool formats); main cannot
decode it (74 trailing bytes in frame), so with the default HOME the two
cache-reading tests fail on main and on this branch alike. It was left as
it is.
what the deploy to cyberproxy, deimos and jupiter still needs
- a release carrying #187 on the kernel (
cargo install soft3 --version <phase-1>), built against pins that build: bbg needs its fjall vendoring on master (or soft3 moves offbbg/rs/vendor/fjall), and the stack-chain-genesis gate needs those 3 warnings gone to turn green. - the launch genesis files from
soft3 genesis buildwith the final params, the hemera 0.4 re-bless done, and the ids pinned inchain::params::CHAINS; until then--genesis FILEon every machine, byte-identical (step C T−15). - miners: the nodes do not mine. Someone runs
soft3 mine --node http://127.0.0.1:7781 --address <neuron>(Metal/WebGPU/CPU) against at least one node at genesis, or block 1 never comes. - endpoint ids (
soft3 node id) collected intopeers.tomlon each box, ufw for 7791/udp, nginx snippets (README step A6), jupiter's root steps by the owner (no sudo). - not exercised here: three real machines over the internet (NAT, relay
off, clock skew), a replay at a real height (restart replays every body;
tens of blocks took seconds here), and
best_header/missing_bodiesscanning the in-memory store on each call — fine at slice size, to index before long chains.