Why a release with "no new features" matters most
Most blockchain releases compete on what is added. v0.17.0 is deliberately about what was tightened: structural debt repaid, latent attack surface closed, and the gap between spec'd and enforced shrunk to zero.
This is the kind of release that does not produce a hero metric. It is the kind of release that lets the next twelve months of features be built safely.
If you are evaluating Shell Chain for capital allocation or for a production deployment, v0.17 is the version that matters. Here is what changed.
1. Architecture re-split — workspace grew from 12 to 19 crates
The original M0 workspace had 12 crates. Over twelve months a few of those
became too large to reason about — shell-network was carrying both gossip
and consensus messaging; shell-consensus had absorbed the slashing logic
even though it depended on storage and mempool concerns.
v0.17 split them out:
| Old crate | New crates |
|---|---|
shell-network |
shell-network + shell-network-gossip + shell-network-rpc |
shell-consensus |
shell-consensus + shell-consensus-slashing + shell-validator-set |
shell-mempool |
shell-mempool + shell-mempool-policy |
shell-storage |
shell-storage + shell-storage-cold + shell-storage-profile |
The benefits are not cosmetic:
- Cyclic dependencies eliminated.
cargo-modulesconfirms a strict DAG. This unlocks parallel compilation and cleaner external auditing. - Per-crate test budgets. Each new crate has its own
tests/directory and its own CI gate. The 1,200-test number is still aggregate but each gate is now a sub-budget, not a global pool. - External integration surface. A wallet provider can depend on
shell-network-rpcwithout pulling in the consensus engine.
2. Consensus slashing wired in
In M3 we shipped a governance contract that declared slashing penalties for double-signing and for unavailability. In M3–M16 those penalties were never actually enforced — the wPoA validator set was small and trusted, and slashing was a roadmap item.
v0.17 closes that gap. The new shell-consensus-slashing crate:
- Watches for double-sign evidence in gossip and on chain.
- Verifies the evidence cryptographically (a Dilithium3 sig over two conflicting block hashes from the same validator at the same height).
- Emits a
SlashingEventthat the next block producer must include — failure to include is itself a slashable downtime offence. - Decrements the validator's stake in the on-chain
ValidatorSetat the next epoch boundary.
The penalty schedule is configurable per network. Testnet defaults to soft penalties (warning + temporary jail); mainnet defaults will be published with the validator economics paper.
3. Network amplification fix
A pre-v0.17 issue surfaced in adversarial gossip testing: a malformed peer could announce a block hash without producing the body, then keep re-announcing it on every gossipsub heartbeat. Honest peers would re-pull the announcement and re-broadcast it. The amplification factor in a fully-meshed test cluster was measured at ~7× of the original malformed message size.
v0.17 fixes this in three places:
- Per-peer announcement budget. Each peer is rate-limited to
gossip_announces_per_minute = 600per topic; bursts above that are dropped silently. - Hash-availability cache. A negative-result cache on body fetch (with TTL) means a missing body is not re-asked of the same peer for 60 seconds.
- Reputation decay. Repeated missing-body responses lower a peer's reputation; below a threshold, the peer is disconnected and its IP blacklisted for the configured cool-down.
Backported to v0.16.x as a security advisory; v0.17 ships with the fix on by default.
4. Bounded mempool channels
The Tokio mpsc channels inside the mempool were previously unbounded.
That made the code simpler but had a failure mode that was hard to
observe: under sudden load, the channel would silently grow into the
gigabytes before the OS killed the process for OOM.
v0.17 introduces:
- Configurable bounds —
mempool.channel.tx_inbound = 10_000is the default; it is a single config knob. - Back-pressure as a metric —
mempool_channel_full_total{channel=…}is a Prometheus counter you can alert on. A spike means "load is approaching a degradation threshold," not "process is about to die." - Drop policy — the oldest-N or lowest-fee-N transactions are dropped first when a bound is hit, instead of new transactions being silently rejected.
In load tests, the new model degrades smoothly from 100% admission at 500 tx/s to 80% admission at 5,000 tx/s. The old model degraded from 100% to zero over the same range, with an OOM at the end.
5. Supply-chain CI is blocking
Five new gates run on every PR and on every nightly main build:
cargo audit— checks every dependency against the RustSec advisory database. Any unaddressedCriticalorHighadvisory fails the build.cargo deny— license, advisory and source-pinning checks. The workspace has an explicit allowlist; any new dependency from a non-allowlisted source fails.- SBOM generation —
cargo cyclonedxproduces a CycloneDX SBOM that is attached to every release artifact. - Sigstore signing — release binaries are signed with
cosignagainst the project's Sigstore identity. Verification instructions are published with every release. - Reproducible builds — release binaries are built with
--locked --frozenfrom a pinned Rust toolchain in a hermetic container. The release workflow publishes the build log so a third party can rebuild and compare hashes.
Together, these close the supply-chain class of attacks — the one that
took down xz-utils, took down the npm event-stream package, and is the
single most likely vector for a sophisticated attacker against a
production blockchain.
What did not change
We are explicit about scope:
- No new EVM opcodes. Cancun spec parity remains the floor.
- No new signature schemes. Dilithium3 + SPHINCS+ remain the supported set. (Hybrid PQ + ECDSA modes are a research direction, not a roadmap item.)
- No tokenomics changes. v0.17 is a pre-token release; economic parameters are still draft.
Upgrading from v0.16.x
For node operators, the upgrade is non-breaking: stop the node, replace the binary, restart. State and storage formats are wire-compatible. The new mempool config bounds are optional — defaults match previous behaviour.
For developers depending on Shell crates, the workspace re-split means
some import paths moved. The migration is mechanical and documented in
docs/migration-v0.17.md.
What this means for the next twelve months
v0.17 is the operational floor we wanted before opening the chain to external validators. With slashing enforced, supply-chain CI gating every dependency change, and the mempool bounded under load, the public incentivised testnet (M14 on the public timeline) can proceed without carrying inherited debt.