# FlyChain A blockchain whose proof of work is a fruit fly's brain. Every block is decided by eight flies in a row. The header hashes into a taste stimulus, real gustatory receptor neurons from the Janelia male CNS connectome are driven at it, and the spike train that comes out is both the proof of work and the block's contents: in each slot, if MN9 — the motor neuron that makes a fly swallow — fires, that transaction is in the block. If it does not, the fly spat it out. A transaction is valid only if the account it spends from signed it: secp256k1 over an EIP-712 digest of the chain id, payer, payee, amount, fee and nonce. Connect an injected EVM wallet and your address becomes a fly — cosmetic, so no address is worth grinding for — and your own signature is what authorises your payments. With nobody connected the chain keeps moving on eight demo puppets whose keys the node holds and whose every appearance in the UI says so. Read [DESIGN.md](DESIGN.md) for the mechanism, why it is a real chain, and the honest limitations. This README is how to run it. ``` npm install npm run serve ``` Then open **http://localhost:5311**. One process serves the node, the page and the 3.26 MB brain, and it answers on both 5310 and 5311 — 5311 is where this README has always sent people, and 5310 is the single port the deployment uses. `FLYCHAIN_PORT=5312` moves both; `FLYCHAIN_SINGLE_PORT=1` binds only the first. Nothing the page asks for is absolute, so the same bytes work at the root and under a prefix — `https://traderfly.xyz/flychain/` is this repo behind a proxy that strips `/flychain` before the node sees it. See [deploy/README.md](deploy/README.md) for the server, which shares two cores with a fly that trades real money and is therefore capped, niced, and **mines only while somebody has the page open**: no event stream for fifteen seconds, no simulations. `FLYCHAIN_MINE_WHEN_WATCHED=1` turns that on; it is off here, because a demo you are developing should mine. The chain is kept in `data/chain-5310.jsonl`, one line per block: its 156 header bytes and its candidate list, which is everything a block is. Restarting the node replays that file **through `verifyBlock`** — every fly in the history runs again — so the store cannot smuggle in a block the rules would not accept, and so a rebuild does not drop the drawer back to genesis. It costs about 80 ms a block, which is the honest price of the mechanism and grows with the history. `FLYCHAIN_RESET=1` starts over; a stored chain that a rule change has invalidated is moved aside to `.stale` and the node says so. **The page is quiet by default.** What is on screen when it opens is the fly and its brain at the size they deserve, one line of words saying what the node is doing this second, what just landed and how much of it the flies swallowed, one button, and the wallet in the corner. Everything that is a number — the loop rail, the drawer's hashes and nonces and difficulties, the bench you type a payment into, the flies burned, the replay speed — is behind one switch, **show the numbers**, top right. It is remembered in `localStorage`, and it is the only disclosure on the page: there is a quiet page and an instrument panel, and nothing in between. You will see the chain as a row of pinned flies receding into fog: one specimen per block, each gripping the one ahead. The fly at the front is alive — it is the one being mined, and the cloud of points over it is the consensus brain, 8,418 neurons at their real soma coordinates, lit by the spikes of the attempt running right now. Mining is a blur, which is what mining looks like. When a block is found, its eight slots **replay at about two a second**: you watch each fly taste its transaction and swallow or spit it, and then the block locks and the fly joins the line. That replay is a recording — those eight flies already ran, inside the one attempt that won — and the band across the bottom of the scene says so while it plays. The 1× / 4× / max control sets how fast it is played back; it does not touch how fast the node mines. With the numbers out, a rail under the scene carries the current attempt's own values through the six steps of the loop — the block's bytes, the flavour they hash into, the fly, the spikes, the seal, is it under the target — with the return path drawn on it. It turns over several times a second, and freezes on the attempt that wins. **Walk me through one block** (top left) is the way in. It is a guided run of the real thing at a pace a person can follow: it puts one signed payment in the mouth, waits for the miner to pick it up, counts the flies burned on the block it is in, slows the replay down and nearly stops it on that payment's own slot, reads MN9's spike count out as a verdict, re-runs the whole block in a worker in your tab, and adds one to the sealed nonce so you can watch the rule throw it out. Seven cards, about a minute. Nothing in it is staged — every line is read off a real event from the node, and the only liberties are of pace, which the cards say out loud. While it runs, every region of the page dims except the one the card is talking about, and the numbers are put away for its duration and handed back at the end — the run is the quiet page teaching, and it is what keeps the card clear of everything under it on a short frame. **what is this?**, beside it, is four lines and a disclosure with the long version; it opens on a first visit and is one link away after that. **Connecting a wallet.** The control in the top right — and *your fly* on the bench, with the numbers out — connects an injected EVM wallet (`window.ethereum`, EIP-1193, through viem) — MetaMask, Rabby, whatever you have. The wallet is only ever asked for one signature over a message: no mainnet transaction is sent, no network is switched, and there is nothing on this chain worth anything. Your address hashes into a fly — markings, banding, size, bristles — that rides on the card, on your line in the mouth, and on the mote the fly tastes. A puppet pays you something to spend the first time, and then your payments are signed by you and by nobody else. On a machine with no extension — a recording, a fresh laptop, a test — the card offers a **stand-in wallet**, and `http://localhost:5311/?wallet=demo` connects one on load (`&fresh=1` for a new key rather than the published one). It is a real EIP-1193 provider with its key in the page, so the whole connect-and-sign flow is exercised; every screen using it says it is a stand-in. Drag the scene to look back down the line, or click any fly. Clicking a block — or one of the five in *just landed*, or **check one yourself** beside them — opens its record: what each of the eight flies did with it, *re-run these flies in your browser*, the tamper buttons, and then the 156 header bytes. The re-run downloads the 3.26 MB consensus brain in a worker, runs all eight flies from the header bytes and checks the node's numbers against its own; each tamper edits a stored block and names the rule that catches it. Both stay one click from the quiet page, because they are the proof this is a chain rather than an animation. ## The consensus brain `data/brain.bin` is the slice of the fly this chain runs: **every neuron on a path of at most five synapses from a sugar or bitter gustatory receptor neuron to MN9.** 8,418 neurons, 394,671 synapses, 3.26 MB, SHA-256 `45e6204c…`, which every block header pins. It is committed, so nothing at runtime needs the 50 MB whole-brain file or the network. To rebuild it from source you need the TraderFly checkout's `data/connectome.bin`: ``` npm run fetch:types # one neuPrint query, cached to data/neuron-types.json npm run build:brain # reads the 50 MB connectome, writes data/brain.bin ``` `FLY_CONNECTOME` and `FLY_POSITIONS` override where those live. ## Layout ``` src/chain/ the rules — nothing outside verifyBlock() may accept a block params.ts every consensus constant, in one file sha256.ts one portable hash, so Node and the browser cannot drift header.ts canonical bytes for transactions and the 156-byte header fly.ts THE MECHANISM: eight flies, the spike digest, the decision pow.ts the target test and difficulty retarget block.ts verifyBlock — the eleven rules chain.ts block store, heaviest-chain fork choice, reorgs address.ts accounts are addresses, in one canonical spelling sig.ts THE OTHER RULE: what a payer signs, and how it is checked demo-keys.ts the eight puppets' throwaway keys, published on purpose ledger.ts a toy account ledger, balances and nonces by address miner.ts the nonce loop src/brain/ the LIF engine, vendored from TraderFly (see below) src/web/ the browser's wallet: connect and sign, through viem src/viz/ the scene — the replay clock, the fly, the brain cloud, the stage traits.ts an address, as a fly. Cosmetic, and tested to stay that way fly-badge.ts that fly on a 2D canvas, for the card and the mouth replay.ts elapsed time in, "show bin 4 of slot 2 now" out. Tested. fly-mesh.ts the live fly and the merged husk, vendored from TraderFly brain-cloud.ts 8,418 points at real soma coordinates, vendored likewise chain-stage.ts three.js: the line, the fog, the camera, the render loop src/server/ the node: mines, streams, serves the page web/ the viewer — plain modules; the page, app.js and walkthrough.js are hand-written, verify-worker.js, stage.js and wallet.js are esbuild output from src/ walkthrough.js the guided run: one payment, seven cards, real events only test/ the rules that matter: hashing, tamper-evidence, the fly scripts/ one-time builders for data/brain.bin deploy/ the VPS: deploy.sh, flychain.service, the Caddy route, and why every one of its limits is where it is ``` ## Why the engine is vendored, not imported `src/brain/{lif,rng,poisson,format,types}.ts` are byte-for-byte copies of TraderFly's `packages/brain/src/`. They are copied rather than imported by relative path for one reason: **they are consensus rules here.** A chain whose validity depends on a file in a sibling checkout that another project is free to tune is not a chain. TraderFly can change its LIF engine whenever it likes; FlyChain's must not move without a version bump. The cost is that a real fix over there has to be copied over here on purpose, which is the correct amount of friction. The connectome binary format is TraderFly's `FLY1` layout, unchanged, so the same decoder reads both the 50 MB brain and the 3.26 MB shard. `src/viz/fly-mesh.ts` and `src/viz/brain-cloud.ts` are vendored from the same checkout's `apps/web/src/stage/{Fly.js,BrainCloud.js}` for the weaker reason: they are not consensus rules, they are a fly's proportions and a good idea about shading spikes on the GPU, and a cross-repo import for those would be a dependency on somebody else's art direction. Both were rewritten from three/webgpu and TSL to plain WebGL on the way over; each file says at the top what it took and what it changed. ## Tests ``` npm test # 110 tests npm run typecheck ``` The rules are tested; the plumbing is not. What is covered: the portable SHA-256 against `node:crypto` at every length, header and transaction byte layout, canonical ordering, merkle roots, the fly's determinism and its dose-response, every tamper the demo offers, difficulty retargeting — its sliding window, its per-block cadence and its clamps — fork choice and reorg, and a chain that re-verifies from its parent at every height. Since signatures: the EIP-712 digest against viem's own (an independent implementation of the same standard), a good signature, the wrong signer, an amount tampered with after signing, a signature made for another chain id, one lifted onto another nonce, a high-s twin, a forged block, a block whose merkle root was rebuilt around a raised amount, and the address derivation — including a test that fails if any rule file ever imports it. ## Not a token No money, no token, no deployment, no network. There are keys — the demo puppets', published in this repo, and whatever your wallet holds — but they only ever sign a message about invented balances on one local node, and a connected wallet is never asked to send a transaction. It is a demo of a mechanism.