Shekyl FoundationAutomated
9/28/2026, 5:41:22 AM
State of dev as of 509d055a7fcb, 28 September 2026.
This window had two threads. The Rust node that will replace the inherited daemon took over another job it used to borrow, growing the curve tree itself. The peer-to-peer layer finished its design round and its first code landed. Between them sit one ruling on how archived history is divided up, one deletion, and a new command shell for the wallet.
The Rust validator now grows the curve tree itself — LANDED
Every spend in Shekyl proves that the output it spends is a member of one large tree, the curve tree, without saying which member it is. Each block adds the outputs that have just become spendable to that tree, and each block header commits to the resulting root. A node that cannot compute that root cannot judge whether a header is honest.
Until this window, the Rust store and validator that are being built to replace the inherited C++ daemon did not compute the root. They were handed it: when replaying recorded chains, the root came from the C++ daemon's own records and was passed through untouched. That was acceptable as scaffolding. It also meant the Rust stack had never shown it could do the work.
Now the validator works out which outputs matured at each height, in the order consensus requires, grows the tree, and hands the store the new root along with the verdict. The store writes what it is given and computes nothing. The field that used to carry the borrowed root has been deleted rather than kept for comparison, so there is no second source the store could accidentally trust. The check lives in the replay driver instead. Over four captured chains, 1,979 heights in all, it compares the Rust-derived root with the one the C++ daemon recorded at every height, not a sample, and they agree at every one. A second, independent check builds the same tree with the wallet's own tree code from the same blocks, and it agrees with the store at every header.
The end-to-end test goes one step further. It mines a short chain, has the miner's wallet recover a coinbase output with the production scanner, builds a real FCMP++ spend with the production transaction builder against the wallet's copy of the tree, and submits it. The validator admits it. Submitting the same spend again is refused because its key image has already been used. No stand-in proofs or placeholder bytes are involved. Four tables the C++ store keeps for this job were not ported. Three hold state that can be recomputed from the blocks, and the fourth does a job the Rust store's undo log already does. The live daemon still runs on the inherited store; this is the replacement being proven before it takes over.
What an archival shard is made of — RULED
Shekyl pays archival nodes to keep old transaction data after ordinary nodes have discarded it. For that to work, the history has to be cut into shards that every node agrees on exactly: which transactions belong to shard 0, which to shard 1, and so on. A node that has already discarded a transaction's body still has to be able to say which shard it was in, because bonds and payments name shards, and a disagreement about boundaries is a disagreement about consensus.
The Foundation ruled that a shard is made of transactions that carry something worth archiving: a prunable region, or post-quantum authorisation data. Shards are consecutive runs of those transactions in chain order. A shard closes when it is full, never because time has passed. The coinbase carries neither, so it falls outside the partition by that definition rather than by a special case. Because the rule is a property rather than a list of transaction types, a future type that carries prunable data joins automatically, and one that does not stays out. Closed shards never change membership. If what counts as archival data ever changes, the change activates at a height and applies only after it.
The implementation work was mostly about keeping one easy mistake out of reach. The two facts the rule reads are digests recorded when a transaction is first stored, and they survive pruning. It would be natural to recompute them from the transaction in hand instead, but on a pruned node the prunable data is gone, and a recomputation would decide that the node's own pruned spends carry nothing. That node would then draw shard boundaries in different places from an archival node. The first version included a convenience method that did exactly this. It was deleted before merge. The only way to ask the question now is with the recorded values, and a test prunes a real store and checks that every transaction's answer is unchanged afterwards. A second test enumerates every transaction class with no catch-all case, so adding a new class will not compile until someone decides which side of the line it is on.
The ruling does cost something, and the design doc says so. On a quiet chain the newest shard fills slowly and may stay open for a long time. It is then neither bondable nor discardable. The ruling accepts that, since a shard that fills slowly holds little. The same day, the Foundation withdrew a proposed floor on shard size. The per-record cap on how many shards one bond can hold turns out to limit the size of a list, not how much any operator stores, because an operator who wants more simply posts another bond. How many transactions go into each shard is still being derived and is IN FLIGHT.
Peer connections: the transport design is closed — RULED
Shekyl nodes still talk to each other over the inherited C++ networking stack. The plan is to replace its TCP server with a Rust transport layer, and this window closed the design for that layer.
The design's most useful decision is about vocabulary. It separates encryption from confidentiality. Encryption means the bytes on the wire cannot be read. It does not hide a peer's address and port, and it does not stop anyone from watching traffic volume and timing or seeing which peers a node talks to. The design lists each network's properties as a table. Each entry names the property, the adversary it holds against, and what remains exposed. Words like "secure" and "anonymous" are not allowed in that table, and an entry nobody has checked reads "not assessed" rather than inheriting a reputation. On that basis, plain internet connections get an added encryption layer: a Noise handshake that combines classical X25519 with post-quantum ML-KEM, so the channel stays protected even if one of the two is broken. Tor is treated as a complete network of its own. The Tor connector dials onion addresses only and refuses anything else, so peer traffic never leaves Tor through an exit.
The order of work was also ruled. The inherited server is replaced first, and encrypted internet connections are tested on the new layer before they become the default. The interim bridge that currently lets the Rust encryption run under the C++ server will be deleted at cutover and gets no further work in the meantime.
Code for several parts of this landed during the window. The encrypted internet transport is merged behind an option that is off by default. It is a pre-genesis test switch, not a privacy setting, and the unencrypted path is due to be removed before genesis. The Tor connector is merged, and the onion services the daemon publishes now require Tor's proof-of-work defence by default. The core of a new timing engine also landed; it will eventually own every network deadline in Rust. None of it is yet the daemon's live networking path. Timeouts and thread budgets are to be measured on the new layer before cutover rather than chosen in advance.
One definition of what a post-quantum signature signs — LANDED
Each input of a Shekyl transaction carries a hybrid signature: a classical key and a post-quantum key that both sign the same message. The message is built from parts of the transaction. Until this window it was built in two places: once in Rust, where the wallet signs, and once in the daemon's C++, where signatures are verified. Two implementations of the same message are two chances to disagree, and a disagreement between the signer and the verifier means valid transactions get rejected.
The C++ version has been deleted, about a hundred lines. The daemon now asks the Rust library for every input's signed hash in one call and checks each signature against it. The wallet, the daemon's consensus check, and the daemon's submission check now use one derivation. Signature verification was consolidated the same way. One Rust verifier sits behind every path that checks these signatures, so the daemon, the transaction pool and the new validator cannot disagree about whether a signature is valid.
The way this was done is typical of how the project removes inherited code. Before any line moved, the C++ was run over eight transactions a live daemon had accepted, covering every transaction shape. Its output, 21 signing messages, was saved as a fixed test vector. The Rust version was held to that vector, and the C++ was deleted only after that. The vector outlives the code it came from. It is recorded as what the specification produces for those bytes, not as "what the old code did".
The wallet command line becomes a shell — LANDED
shekyl-cli now has one consistent command language and a persistent interactive shell. Commands read as a subject then a verb (wallet open, tx show, stake add), with bare words for common reads (balance) and plain verbs for the main actions (send, prove, check, sign, verify). Tab completion follows that grammar. Old spellings are not silently accepted. They print the new form and do not run.
Command history persists between sessions. Lines that contain seeds, proofs or signatures are never written to it, including when they are typed in the retired syntax. A status line shows the version, local time and sync state. The same commands can be piped in from a script, which stops at the first failure. Archival shards are now a text subject (shard list, shard show, shard fetch) rather than a picture.
This post describes the state of the dev branch at 509d055a7fcb on 28 September 2026.
Shekyl is pre-genesis and under active design; anything marked IN FLIGHT may
change or be abandoned. Where a later post contradicts this one, the later post
is correct.
References: PR #878 (DRS-E3), PR #873, PR #884, PR #882 (SHT-Q1, L2), PR #855, PR #850, PR #847, PR #883, PR #868, PR #860, PR #863, PR #864 (CEN-I17/I18), PR #872