Shekyl Stats

Refreshing...

Network

Connected
Seed Nodes Active
--

Chain

Current Block
0
Network Height
—
Top Block Hash
--
Block Time Target
2 min

Rewards

Last Block Reward
0.000000 SKL
Difficulty
0
Estimated Hash Rate
0 H/s

Supply

Circulating Supply
--
Remaining Supply
--
Total Burned
0 SKL

Economics

Release Multiplier
0
Burn Rate
0%

Staking

Stake Ratio
0
Staker Pool
0.000000 SKL
Staker Emission Share
0%
Total Staked
N/A
Staking Height
N/A
Tier 0 Lock Blocks
N/A
Tier 1 Lock Blocks
N/A
Tier 2 Lock Blocks
N/A

Protocol

Transaction Format
TransactionV3
Membership Proof
FCMP++
Spend Auth
Ed25519 + ML-DSA-65
Confidentiality
Stealth + BP+

Node

TX Pool Size
0
Database Size
0 B
Node Version
--
Sync Status
Syncing

Development digest — 3 October 2026

Started by Shekyl Foundation • 0 replies • 8 views

0

Shekyl FoundationAutomated

10/4/2026, 11:05:23 AM

State of dev as of 684673611eb1, 3 October 2026. Twenty pull requests merged over three days. One consensus change landed: a transaction's identity now commits to its archival size. The node also moved to a single transaction relay for every network it uses, and a Tor-only node can now sync. Two pieces of measurement work changed what the project believes about its own numbers.

A transaction's id now commits to how many archival bytes it carries — LANDED

Shekyl splits each transaction into two parts. The skeleton is what every node keeps forever. The archival bytes are the large proofs and post-quantum signatures, which most nodes discard once they have verified them and which archival nodes store in shards. Shard boundaries have to be computed identically by every node, including nodes that never saw the archival bytes. Until now shards closed after a fixed number of transactions. Transactions differ widely in size, so shards did too, and a shard's real storage cost could not be read from its count. The Foundation ruled that shards close on cumulative archival bytes instead. That raised a harder question: a node that has discarded the bytes still has to know their length, and has to be able to trust it.

Two placements were weighed. The first put a declared length field in the transaction, where the signatures would cover it. The objection was ordering: the length includes the signatures themselves, so every signer would need to know the final size of every signature, their own included, before signing. Today's signature schemes have fixed sizes, so that is workable now. A future post-quantum scheme with variable-length signatures could not be sized before signing without padding or a second signing pass. The chosen placement folds the length into the transaction id. Nothing is declared. A node holding the full transaction measures the length from the bytes as it computes the id, so a wrong length cannot exist. A node holding only the skeleton is handed the length alongside the digests it already receives. If that length is wrong, the id comes out wrong and the block's transaction list rejects it. The rejected-alternatives record gives the variable-length signature case as the deciding reason.

That change has now merged (rust/shekyl-wire/src/transaction/txid.rs). There is one transaction-id function, written in Rust. The C++ daemon no longer hashes anything to name a transaction: it hands the serialized byte ranges across to that function. The C++ path that computed ids for pruned transactions was unreachable and has been deleted. A related change in the same window does the same for the digest of a transaction's prunable region. That digest is stored, served beside pruned transactions, and checked by wallets. Rust previously computed it in three places and C++ in a fourth. There is now one definition, and the second C++ derivation is gone.

For anyone running a test node: every non-coinbase transaction id has changed, and both chain stores were version-bumped so an old data directory fails loudly instead of quietly misindexing. Delete the data directory and resync.

One relay for every network, and syncing over Tor works — LANDED

A Shekyl node can talk to peers over clearnet and over Tor at once. Until this window the daemon ran a separate Dandelion++ relay for each network. Dandelion++ is the scheme that passes a new transaction privately along a short chain of peers before broadcasting it. Running one relay per network meant every relay decision existed in several copies, and those copies were spread across the C++ protocol code. The Foundation ruled that there is one relay and that the network is a property of each connection, not of the relay. The network is read at three named points and nowhere else.

The first point is the first hop. If the node has a Tor connection configured, a transaction it originates goes first to a peer reached over a connection that hides this node's address, chosen at random from those peers for the current epoch. If no such peer is connected, the transaction waits. Falling back to a broadcast would publish its origin on a clear link (rust/shekyl-relay/src/zone/own_edge.rs). The second point is the holding period: when a node forwards a transaction privately, it waits for that transaction to come back as a broadcast before acting itself. That wait is now drawn from the measured transit time of the connection the transaction left on. The third point is cover traffic, which follows the class of the link. After the first hop, forwarding is uniform across all outbound connections, and a broadcast reaches every peer except the one it came from.

Testing that end to end over Tor turned up a real fault, which is now fixed. A node whose only peer was an inbound Tor connection completed its handshake, learned the remote chain height, and then stayed at height 1. An inherited allowlist dropped every message on a non-clearnet connection except three, and chain sync was not among them. The allowlist has been deleted, because the per-session message table already decides what a peer may send. On the next run the Tor-only node synced 84 blocks over its one inbound Tor connection in 21 seconds. A spend relayed through the test network arrived in its pool over that same connection. That run and its timings are recorded in docs/benchmarks/D5_TOR_STEM_RUNBOOK.md.

One smaller change also landed. The identifier nodes exchange in their handshake is now derived from the genesis block hash instead of written as a constant (rust/shekyl-p2p-transport/src/prefix.rs). A network with a different genesis therefore gets a different identifier automatically.

The inherited hardware-wallet code is deleted — LANDED

The daemon still contained a Ledger backend inherited from the Monero lineage, about 1,600 lines of device client. It could not be built: its build flag was off by default and the code refused to compile if anyone turned it on. The Trezor backend went the same way earlier. In this window the Ledger backend went too, along with the hardware-device abstraction around it, the logging and session plumbing that only those backends used, and the build machinery that fetched USB and HID libraries to support them.

Keeping the code would not have been a step toward hardware-wallet support. Shekyl's output keys, key exchange and proof construction use operations that no current device firmware implements. Those include post-quantum key encapsulation, a second generator in the output key, and witness data for the membership proofs. A backend written for Monero's device protocol could not be adapted to them. Kept in the tree, it implied a capability that does not exist. docs/HARDWARE_WALLETS.md lists the primitives a device would need to provide. Support returns as new code written against the Rust wallet once a device provides them, not by restoring this tree.

Two other small deletions landed in the same window. Five fee constants in the C++ configuration had no caller left. One of them had been copied into the economics simulator and was quietly pricing an attack scenario there, which is covered below. A dead Trezor build arm also went.

Measuring how a spend's membership path is built — IN FLIGHT

To spend an output, the wallet proves that the output belongs to the set of all outputs on the chain. That set is held as a tree, and the proof needs the output's path from its leaf to the root. How the wallet assembles that path had never been timed: the benchmark harness proved against synthetic paths and skipped assembly entirely. This window added an instrument that drives the real wallet client against populations chosen so that a cost proportional to chain length and a cost proportional to tree depth would look different.

The answer was clear. Cost per leaf was flat to within half a percent across every population tested. That pattern means total cost grows in proportion to the whole chain. Tree depth had no measurable effect, and neither did the number of outputs being spent. The cause is structural: the wallet keeps every leaf it has ever seen and rebuilds every tree layer on each spend. A production comment had described the cost as bounded by about a day of chain, and that comment was wrong. The measurement replaces it, and is recorded with its limits stated: it is an observational figure from one server-class host, not a graded one. The planned redesign, called capture, has the wallet keep only the path material for its own outputs. Its cost then depends on tree depth and not on chain age. That redesign now has a measured baseline to beat, and a structural test fixed in advance that only a design meeting that property can pass.

Building that test also exposed something to fix first. When most of the tree material was removed, assembly still returned a path. The path claimed the correct root, but every branch underneath came from a tree of one leaf. The root was being copied from a check that never looked at the branches. That has been fixed and the fix has merged. Every assembled path is now hashed back up its own branches and refused if it does not reach the root it claims. At each layer the check also confirms that the child really is present in its parent, which ties the path to this particular output. The flaw could not occur in normal operation, since the wallet never assembled from incomplete material. Capture will introduce a second source of branch material, and this check is now in place before it does. The gate is merged. Capture itself is not yet built.

The economics simulator now calls the code the chain runs — IN FLIGHT

The project's archival-economics conclusions come from a long-horizon simulator. A review of it against production code found a problem. It had been charging every transaction a flat placeholder fee for the full sixty-year run, and pricing a block-stuffing attacker with a per-byte constant from C++ that nothing in the daemon used. The fee the chain actually charges falls sharply as the reward schedule decays, so conclusions about fee share were conclusions about a fee that does not exist.

Two rulings set the order of repair. First, the simulator calls production code (fee ladder, weight prediction, emission split) wherever it can, and every place it departs from production is listed in a register of declared divergences. Second, the simulator is fixed first, the current system is then measured under its own rules, and only after that are any levers redesigned. No new mechanism is being proposed in this round.

The first three steps have merged. Each step changes one input to the model and comes with a prediction written before the run. The old flat fee is kept as a named control arm, and running the control reproduces the earlier report exactly, line for line. Any change in the results can therefore be traced to the production code and not to some other edit. The simulator now gets its ordinary fee and the attacker's admission price from the production fee ladder. Its emission split now changes at the same epoch boundary the validator uses. The dead constant the simulator was copying has been deleted from the daemon. The earlier conclusions are being re-read against the corrected runs, and the remaining steps (block-weight median, transaction-volume windowing, among others) are open. We are not yet in a position to say which of the earlier economic conclusions survive.


This post describes the state of the dev branch at 684673611eb1 on 3 October 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 #923, PR #933, PR #924, PR #926, PR #927, PR #931, PR #938, PR #935 (SHT-Q2, CT-6, ESR)

Sign in to reply and vote.