My homelab forged 57 Leios endorser blocks — what I learned as a testnet BP
Hands-on follow-up: local forge evidence, EB cap honesty, surviving a testnet respin, and why release-day latency is not a bug report.

In June I spun up a Cardano Ouroboros Leios node on Musashi Dōjō, measured endorser-block throughput under IOG load, and registered a stake pool. The promise at the end of that piece was simple: once the stake snapshot activated, the homelab would start forging endorser blocks itself.
It did.
This is the follow-up: local forge evidence, a clearer reading of the famous 2,184-tx EB cap, a respin that nearly turned into a false bug report, and a latency re-test done after the network had calmed down. Same homelab container, same pool identity, new genesis, new release (`prototype-2026w28`, `cardano-node 11.1.0.164`).
What "forging" means here — and what it doesn't
On 2026-07-12, epoch 11, our block producer logged:

| Signal | Count (partial day → ~16:09 UTC) |
|---|---|
| `NodeIsLeader` | 137 |
| `LeiosBlockForged` | 57 |
| EBs at protocol cap (2,184 txs) | 27 |
| Sum of `numTxs` in our EBs | 99,203 |


Those events come from `Consensus.LeiosKernel.BlockForged` on the block producer’s local kernel, not a third-party explorer. First EB of the day: `2026-07-12T01:12:21Z`, slot `954741`, `numTxs` 1181, hash `77efc0d64c7a39736b83d1abe94e66b5a23cd13eec97952bea26a755c393c6f0`.
This does mean: our registered pool (`60ef1953…` / `pool1vrh3j56…`) was elected leader and our node produced endorser blocks locally.
This does not mean: we produce X% of network EBs, that every peer downloaded our blocks, or that we run a public inbound relay. We are not running a public inbound relay for this article: relevant connectivity is outbound, and forge claims rest on local logs, not on being a network entry point.
The 2,184-tx number, said carefully
In June the largest endorser block we observed carried 2,184 transactions — and a ~10-second chain-time window reached ~218 TPS. That peak is still the right intuition pump, but the cleaner statement is:


2,184 is the inclusion-bitmap cap of one EB (≈ 2,184 × 36-byte refs ≈ 78,627 bytes of EB body). A full EB in a 10-second window is ~218 tx/s. That is cap-bound, not a certified multi-hour network capacity study, and the load that filled those blocks was generated by IOG's load generators, not by our submitter.
On July 12, of the 57 EBs we forged:
| `numTxs` range | Count |
|---|---|
| 1–500 | 4 |
| 501–1500 | 10 |
| 1501–2000 | 13 |
| 2001–2183 | 3 |
| 2184 (cap) | 27 |
Median ≈ 2,149, average ≈ 1,740. Almost half of our EBs hit the same ceiling we reported in June — now from the producer side of the log.
Surviving a silent respin (and almost filing the wrong bug)
Around 2026-07-01 the testnet respawned with a new genesis. Our node had been stuck for days on a low slot with `NoCounterForKeyHashOCERT` — not a broken binary in the abstract, but headers from a ledger we did not have. Slot arithmetic vs the old `systemStart` was enough to prove a respin before any changelog.
Recovery lessons worth publishing:
- Prototype testnets respin without ceremony. Keys survive; on-chain registration and faucet funds do not. Pool id is deterministic from cold keys.
- Binaries and configs ship together. A half-update (new binary + old config tag) looks "applied" and poisons the next diagnosis.
- Never hardcode KES period. Compute `slot / slotsPerKESPeriod`; reset opcert counter to 0 on a fresh ledger.
- `build-raw` + draft `+0` underestimates fee by design. Our near-miss "cli bug" was 8 CBOR bytes of change output (352 lovelace = 44 × 8). Verify arithmetic before filing upstream.
- Faucet `delegate` wants bech32 (`pool1…`), not hex.
- Do not publish performance on release day.
End-to-end after detection: tip + re-registration in under ~40 minutes with one human faucet step.
Latency: the day we almost yelled "regression"
On 2026-07-10 — the same calendar day `w28` shipped — external txs looked terrible: single txs taking 4–30 minutes, a 200-tx burst needing 7–8 minutes to confirm. Compared with w25 (~34 s burst), that smelled like a fairness or mempool regression.
It was a deployment window. Re-checked on 2026-07-12 with the network quieter:
| Metric | 2026-07-10 (release day) | 2026-07-12 (stable) |
|---|---|---|
| Single control tx | 4–30 min | ~87 s (N=1) |
| Burst 200 (5 chains × 40, pre-signed submitter) | 7–8 min | ~45 s to 5/5 tips; 0/200 submit errors |
| vs w25 burst (~34 s) | scare | usable, slightly slower |

Rule we now enforce: a shared-network performance claim needs (a) a check for same-day releases, and (b) reproduction on ≥1 quiet day before it becomes a headline. Small N is fine if labeled; large claims are not.
Method, in the open
- Forge counts: parse `node.log` for `NodeIsLeader` and `LeiosBlockForged` on `2026-07-12` (UTC date in the JSON `at` field).
- Throughput (June baseline): `leios_peak.py` — union of inclusion bitmaps per `ebHash`, popcount → txs; slotLength 1 s from genesis; sliding windows over chain time. Scripts: leios-homelab-loadtest.
- Submit path (July): pre-signed chained txs (`submitter.py`) instead of forking hundreds of `cardano-cli` processes (that was the June client bottleneck, not Leios).
- Hardware: homelab container, 4 vCPU / 4 GB RAM class setup — the interesting failure modes were tooling and ops, not CPU.
- Not run for this piece: full ceiling test (`fanout 20×400` @ 150 tx/s, ~1.6k test ADA fees). Optional later article; not required for forge + method claims.
What I'm taking away
Leios on Musashi Dōjō is no longer "I watched 218 TPS in the logs." It is I forged 57 endorser blocks in a day, hit the same 2,184-tx cap from the producer side, and learned that ops honesty (respin, KES, fees, release-day measurement) is half the story of a research testnet.
Cardano's throughput future is still a prototype. Prototypes respin. Numbers move. The job of a homelab write-up is not to freeze a marketing TPS — it is to show primary evidence, clear non-claims, and a method another operator can disagree with productively.
Data: own BP on Musashi Dōjō (magic 164), epoch 11, 2026-07-12 (counts as of ~16:09 UTC). Prior article: [June node + measurement](https://danonight.com/news/leios-node-homelab). Scripts: https://github.com/amvs0122/leios-homelab-loadtest.


