smallnano is an independent cryptocurrency written in Zig, inspired by the ideas of Nano (block-lattice, weighted voting, zero fees) but with a completely new protocol, network, address format, and coin.
The problem we solve: Full nodes for block-lattice cryptocurrencies are too heavy. Running a Nano node costs ~$40/month on a cloud VPS, requires 8 GB RAM, and hundreds of GB of disk. That centralises the network to whoever can afford it. smallnano is designed so that anyone in the world — with a low-end computer, an old laptop, or a $5 VPS — can run a full node and contribute to network security.
| Goal | Target |
|---|---|
| Idle RAM | ≤ 64 MB |
| Peak RAM (under load) | ≤ 256 MB |
| Disk (pruned ledger, 1000 blocks/account) | ≤ 2 GB |
| Minimum CPU | Single-core ARMv7 @ 1 GHz |
| Binary size | ≤ 10 MB (ReleaseSafe) |
| Dependencies | Zig stdlib + SQLite (vendored) |
| Wire protocol | Own protocol (NOT Nano-compatible) |
| Address format | smn_... (own base32 + checksum) |
| Currency | smn, 1 smn = 10^24 raw |
| Genesis supply | 10,000,000 smn (fixed, no inflation) |
- Block-lattice: Every account has its own chain of blocks. No global chain to sync.
- Zero fees: Transfers cost nothing. Spam resistance is achieved via PoW.
- Instant finality: Weighted voting reaches irreversible confirmation in seconds.
- No mining: Representatives vote with their delegated balance, not hash power.
| Area | Nano / rsnano-node | smallnano |
|---|---|---|
| Language | Rust | Zig |
| Storage | LMDB | SQLite (vendored) |
| Wire protocol | Nano protocol (v25+) | Own lightweight protocol |
| Address format | nano_... |
smn_... |
| Ledger pruning | Optional, complex | First-class, configurable |
| GPU PoW | Yes (OpenCL) | No — CPU only |
| Binary | Many crates, ~50 MB | Single static binary, ≤ 10 MB |
| Minimum VPS | ~$40/month (8 GB RAM) | $5/month (512 MB RAM) |
| Coin | XNO | smn |
Total fixed supply: 10,000,000 smn — minted in the genesis block, no inflation ever.
| Allocation | Amount | Purpose |
|---|---|---|
| Development fund | 50,000 smn | Protocol development, infrastructure, tooling |
| Airdrops & faucet game | 9,950,000 smn | Community distribution — earned, not bought |
No ICO. No pre-sale. No investors. The vast majority of supply reaches users through airdrops and a faucet game, keeping distribution fair and decentralised from day one.
Reality check: Milestones 1-3 are fully implemented and locally testable today. Milestones 4-9 have substantial implementation in the repository, but several of their original exit criteria assumed a fully wired node runtime and a real multi-node devnet. That end-to-end proof is still pending and is now captured explicitly in Milestones 11-13 below.
Completed. 80/80 tests pass. Runtime MaxRSS: 1 MB. Zero memory leaks.
-
src/types/amount.zig—Amount(u128 raw), arithmetic (checked), display (24-decimal smn) -
src/types/block.zig—StateBlockstruct: account, previous, representative, balance, link, work, signature. Serialise/deserialise (little-endian binary). -
src/types/account.zig—Account(32-byte Ed25519 pubkey), ownsmn_...base32 encoding + checksum -
src/types/vote.zig—Vote, final-vote bit, timestamp, block hash list, signature -
src/types/pending.zig—PendingKey(recipient + send_hash),PendingInfo(source, amount) -
src/types/genesis.zig— hard-coded genesisStateBlockand genesis account -
src/crypto/blake2b.zig— Blake2b-256, Blake2b-512, Blake2b-64 wrappers aroundstd.crypto -
src/crypto/ed25519.zig— sign / verify thin wrappers aroundstd.crypto.sign.Ed25519 -
src/crypto/work.zig— CPU PoW generation + validation (send threshold > receive threshold) - Unit tests for all of the above, using
std.testing.allocator
Completed. All tests pass. WAL mode, migrations, full CRUD for all tables.
-
src/store/store.zig— comptime-duck-typedStoreinterface -
src/store/null_store.zig— in-memory null store for tests (zero disk I/O) -
src/store/sqlite_store.zig— SQLite-backed implementationaccounts—(account BLOB PK, frontier BLOB, balance BLOB, representative BLOB, height INTEGER, modified INTEGER)blocks—(hash BLOB PK, account BLOB, block BLOB, height INTEGER)pending—(hash BLOB, account BLOB, amount BLOB, source BLOB)— composite PKconfirmation_height—(account BLOB PK, height INTEGER, frontier BLOB)peers—(address TEXT PK, last_seen INTEGER)pruned—(account BLOB PK, pruned_height INTEGER)— watermark for pruned blocks_meta—(key TEXT PK, value TEXT)— schema version, genesis hash, network id
- WAL mode,
PRAGMA synchronous = NORMAL - Sequential migration system — version-stamped SQL scripts
- Unit tests: store/retrieve for all table types
Completed. All tests pass. Pure-logic validator, atomic inserter, pruner, ledger coordinator, and MPSC block processor.
Sub-steps:
- Write
src/ledger/validator.zig— pure block validation, typedBlockError, zero I/O - Write
src/ledger/inserter.zig— apply validated block to store atomically - Write
src/ledger/pruner.zig— enforcemax_blocks_per_account, never prune below confirmation height - Write
src/ledger/ledger.zig— coordinate validate + insert + prune - Write
src/ledger/block_processor.zig— MPSC queue + worker thread - Update
src/main.zigimports - Run
zig build test— all green -
zig fmt src/+ final test run - Mark M3 ✅ in ROADMAP.md, commit, push
Exit criteria: All validation rules correctly accept and reject blocks. Pruner removes old blocks without corrupting the confirmation watermark.
Module-complete. All tests pass for the codec, handshake, framing, bandwidth limiter, peer state machine, and threaded listener/dialer scaffolding. End-to-end relay on a real devnet is still pending the runtime work in Milestones 11-13.
Sub-steps:
- Write
src/network/message.zig— encode/decode all message types (magic0x534E, LE integers) - Write
src/network/handshake.zig— Node-ID cookie/challenge handshake (Ed25519) - Write
src/network/channel.zig— length-prefixed frame helpers (pure buffer, no sockets in tests) - Write
src/network/bandwidth.zig— token-bucket rate limiter (configurable mbps) - Write
src/network/peer.zig— peer state, last-seen, ban list - Write
src/network/network.zig— accept loop, outbound dialer, bounded peer set - Update
src/main.zigimports - Run
zig build test— all green - Mark M4 ✅ in ROADMAP.md
Note: zig build test is slow due to CPU PoW generation in src/ledger/validator.zig tests (THRESHOLD_RECEIVE ≈ 2^29 iterations). Network tests themselves are instant — channel and handshake tests use pure in-memory buffers with no sockets or threads.
Current status: Message framing, handshake, peer tracking, and threaded accept/dial loops exist. Live outbound keepalive/publish relay is still pending.
Module-complete. All tests pass for representative weights, elections, vote processing, and confirmation tracking. Real network confirmation flow is still pending the runtime and relay milestones.
Sub-steps:
- Write
src/consensus/rep_weights.zig— in-memory weight cache built from confirmed ledger - Write
src/consensus/election.zig— election state machine (pure logic, quorum integer math) - Write
src/consensus/vote_processor.zig— validate + deduplicate + route votes - Write
src/consensus/active_elections.zig— bounded elections container with eviction - Write
src/consensus/confirmation.zig— writeconfirmation_heighton quorum - Update
src/main.zigimports - Run
zig build test— fix until green -
zig fmt src/+ final test run - Mark M5 ✅ in ROADMAP.md, commit, push
Current status: Consensus components are implemented and unit-tested. A real two-node confirmation path is still pending M11-M13 integration.
Module-complete. All tests pass for frontier enumeration, PullReq/PullAck, pruning-watermark enforcement, and replay/resume logic. Live ledger sync between running nodes is still pending the runtime and peer-relay milestones.
Sub-steps:
- Write
src/bootstrap/server.zig— serve blocks in response toPullReq, respect pruning watermark - Write
src/bootstrap/client.zig— frontier scan,PullReq/PullAck, resume on restart - Update
src/main.zigimports - Run
zig build test— fix until green -
zig fmt src/+ final test run - Mark M6 ✅ in ROADMAP.md, commit, push
Current status: Bootstrap client/server logic exists and is unit-tested. Fresh-node sync on a real devnet is still pending M11-M13 integration.
Module-complete. All tests pass for deterministic derivation, encrypted seed storage, lock/unlock, and block builders. CLI-driven live wallet usage still depends on the runtime milestones.
Sub-steps:
- Write
src/wallet/wallet.zig— deterministic key derivation, encrypted storage, block builders - Update
src/main.zigimports - Run
zig build test— fix until green -
zig fmt src/+ final test run - Mark M7 ✅ in ROADMAP.md, commit, push
Current status: Wallet primitives and block builders are implemented and tested. Real devnet send/receive through the node CLI is still pending M11-M13.
Module-complete. All tests pass for the HTTP transport and JSON-RPC handlers. A real operator-facing RPC service still depends on wiring the runtime together.
Sub-steps:
- Write
src/rpc/server.zig— single-threaded HTTP/1.1 server, no external lib - Write
src/rpc/handlers.zig— all RPC commands (account_info,process,send,receive, etc.) - Update
src/main.zigimports - Run
zig build test— fix until green -
zig fmt src/+ final test run - Mark M8 ✅ in ROADMAP.md, commit, push
Current status: RPC parsing and handlers exist and are unit-tested. A live RPC server backed by a running node is still pending M11-M13.
Config-complete, runtime-pending. All tests pass for the config loader, CLI parsing, help output, and shutdown hooks. The entrypoint still stops before starting a real node instance.
Sub-steps:
- Write
src/config.zig—NodeConfigparsed from TOML + CLI flags, all parameters - Auto-generate config file with defaults and inline comments on first run
-
--helpoutput for every flag - Graceful shutdown on SIGINT / SIGTERM
- Run
zig build test— fix until green -
zig fmt src/+ final test run - Mark M9 ✅ in ROADMAP.md, commit, push
Current status: The config file and CLI surface are implemented and tested. Full operator-facing runtime behavior still depends on M11-M13.
Goal: Production-quality binary with automated quality gates.
Sub-steps:
- GitHub Actions CI:
zig build teston Linux x86_64, aarch64, macOS arm64 +zig fmt --check - Fuzz targets for block deserialisation and message parsing
- Release binaries:
x86_64-linux-musl,aarch64-linux-musl,x86_64-macos,aarch64-macos - Docker image (scratch-based, < 15 MB compressed)
- Systemd unit file and one-command install script
Current status: CI, release packaging, fuzz harnesses, benchmark scaffolding,
Docker packaging, installer assets, and test-net.md exist.
Exit criteria: curl -fsSL install.sh | sh installs smallnano on a fresh
Ubuntu 22.04 VM. Node runs at ≤ 64 MB RAM idle after sync. Any low-end computer
can run a full node continuously.
Completed. The node runtime now owns store open/migrate, genesis bootstrap, block processing, network bring-up, RPC bring-up, and coordinated shutdown.
Goal: Turn the current module set into a real long-running node process.
Sub-steps:
- Write
src/node/node.zig— own the store, ledger, block processor, network, bootstrap, wallet, and RPC lifecycles - Replace the placeholder wait loop in
src/main.zigwith real startup, shutdown, and error propagation - Wire genesis initialization, database open/migrate, and background worker startup in one runtime path
- Expose a small internal API for publishing blocks, starting elections, and forwarding confirmations between subsystems
- Add unit tests for clean startup/shutdown ordering and subsystem failure handling
- Run
zig build test— fix until green -
zig fmt src/+ final test run
Exit criteria: smallnano node run starts a real node instance, opens its
store, brings up networking/RPC workers, and shuts down cleanly without leaking
threads or state.
Goal: Make multiple nodes discover each other, exchange live traffic, and sync without manual code changes.
Sub-steps:
- Extend
src/network/network.zigwith outbound publish, vote, keepalive, and bootstrap request relay paths - Track active peer channels so the node can broadcast or target messages after handshake completion
- Extend
src/config.zigwith peer-seed, bootstrap-peer, listen-address, external-address, and data-dir settings - Bring up the RPC worker as part of the real long-running node runtime and coordinate network + RPC + owned subsystem start/stop in one live path
- Persist peer discovery state safely and bound retry/backoff behavior for low-resource machines
- Add tests covering outbound relay, peer selection, bootstrap resume, config parsing/validation, and coordinated runtime start/stop
- Run
zig build test— fix until green -
zig fmt src/+ final test run
Current status: Peer discovery persistence, bounded reconnect backoff, and
the node-owned inbound publish / vote / pull_req / pull_ack routing are
implemented and unit-tested. The remaining work is proving the same behavior
across a real three-node devnet, which belongs to M13.
Exit criteria: Three separately configured nodes can discover peers, relay blocks and votes outward, and bootstrap ledger state from each other on a devnet. The real runtime brings up network and RPC workers together and shuts them down cleanly through the same node-owned lifecycle.
Goal: Prove that smallnano works as a real multi-process cryptocurrency network on a controlled devnet.
Sub-steps:
- Add an end-to-end integration test that launches three node processes and verifies block propagation + confirmation
- Verify wallet send/receive flow across three nodes using the JSON-RPC surface
- Measure idle RSS, sync RSS, disk usage, and confirmation latency against the design targets
- Update
test-net.mdwith the final three-Linux manual test procedure and expected results - Run the three-machine manual devnet: three Linux nodes
- Fix the remaining cross-platform defects found during the manual run
- Add the three-node integration test to the release gate once it is stable
- Publish a devnet validation report with measured limits, known gaps, and follow-up work
- Use M13 completion as the gate for a broader public testnet phase, not final release readiness
Exit criteria: A three-node devnet can process and confirm transactions between separate machines, and both automated and manual tests prove the network behaves correctly.
Goal: Implement real representative behavior so voting nodes can autonomously sign, broadcast, and expose consensus state.
Sub-steps:
- Wire
enable_votinginto the node runtime so eligible nodes produce votes for active elections - Add vote scheduling, deduplication, rebroadcast, and final-vote handling for live elections
- Broadcast locally-generated votes over the existing network relay path
- Track representative liveness, observed online weight, and recent vote participation
- Expose quorum state, active elections, representative health, and confirmation progress over RPC
- Add multi-node tests proving confirmations happen from autonomous representative behavior, not manual vote injection
- Document representative operator requirements, recommended hardware, and failure modes
Exit criteria: Multiple nodes with voting enabled can independently produce and relay votes, confirmations occur without manual test hooks, and operators can inspect quorum health from the node API.
Goal: Prove that public-network security is not dominated by one operator, one wallet cluster, or one distribution channel.
Sub-steps:
- Define the public-network distribution plan for genesis custody, faucet reserves, and operational wallets
- Build the faucet / distribution service needed to move supply into real user hands without trusted manual intervention
- Publish representative concentration metrics, delegation distribution, and a simple public decentralization dashboard
- Add RPC and explorer surfaces that let anyone audit supply movement and representative weight
- Define launch thresholds for maximum representative concentration before public mainnet promotion
- Run at least one public test distribution round and publish the resulting concentration data
- Document how users choose, change, and evaluate representatives safely
Exit criteria: The project can publicly demonstrate a broad enough supply and representative distribution that routine quorum capture by one organisation or a very small wallet set is not the default outcome.
Goal: Remove the operator-only rough edges so ordinary users, merchants, and exchanges can use the network reliably.
Sub-steps:
- Add optional auto-receive behavior for wallets and services that do not want manual receive management
- Persist or recover wallet account indexes automatically so restarts do not lose account visibility
- Add wallet recovery/import flows suitable for real end users
- Define and build the indexer / explorer API needed for block, account, pending, and representative visibility
- Add merchant-facing primitives such as payment references, polling/webhook patterns, and settlement examples
- Publish exchange integration guidance for deposits, withdrawals, confirmation tracking, and cold/hot wallet separation
- Build or support at least one mobile/light-client path on top of the node RPC/indexer surfaces
- Update setup, operator, and user docs so common flows do not require reading source code
Exit criteria: A normal user can create, recover, send, and receive funds without manual ledger repair steps, and third-party integrators have stable surfaces for wallets, explorers, merchants, and exchanges.
Goal: Measure the real operating envelope, then tune or redesign anti-spam and resource controls where the data says they are weak.
Sub-steps:
- Build a multi-node load generator that can exercise publish, receive, vote, and bootstrap traffic at sustained rates
- Measure confirmation latency, throughput, CPU, RAM, and disk across low-end and recommended hardware classes
- Run adversarial tests for send spam, receive spam, pending-table growth, election floods, peer churn, and bootstrap abuse
- Quantify the real cost of CPU work under honest use versus attack use, then retune thresholds if needed
- Add backpressure, admission control, or additional anti-abuse rules where measurements show CPU work alone is insufficient
- Re-run the benchmark and attack matrix after each tuning pass and publish the results
- Lock a documented target envelope for public testnet and a stricter envelope for mainnet promotion
Exit criteria: The project has published performance and abuse-resistance data, the anti-spam model has been tuned against those results, and operators know the expected safe workload envelope.
Goal: Build the non-protocol foundation required for a credible public network: operational maturity, governance clarity, legal review, and ecosystem support.
Sub-steps:
- Publish release, upgrade, rollback, and incident-response policies for node operators
- Add deterministic release artifacts, signature verification instructions, and stronger operator security guidance
- Publish a threat model covering representative capture, eclipse risk, bootstrap trust, and operational compromise
- Complete legal and regulatory review for the jurisdictions where the project team operates
- Launch a public testnet with published SLAs, support channels, and known-risk disclaimers
- Bring up the first ecosystem integrations: explorer, wallet, merchant pilot, and exchange pilot
- Publish governance and stewardship expectations for protocol changes and emergency coordination
- Mark the project release-ready only after M14-M18 pass with documented evidence
Exit criteria: The network is not only technically functional, but also operationally supportable, legally reviewed, observable, and trusted enough to justify a public mainnet launch.
| Milestone | Expected peak RSS | Expected disk |
|---|---|---|
| M1–M2 (types + store) | < 8 MB | < 1 MB (tests) |
| M3 (ledger) | < 12 MB | < 1 MB |
| M4 (networking) | < 20 MB | < 1 MB |
| M5 (consensus) | < 40 MB | < 1 MB |
| M6 (bootstrap, 1k blk/acct) | < 128 MB (syncing) | ~500 MB |
| M7–M9 (wallet + RPC + config) | < 64 MB idle | ~500 MB |
| M10 (hardening/release scaffolding) | ≤ 64 MB idle / ≤ 256 MB peak | ≤ 2 GB |
| M11 (runtime wiring) | ≤ 64 MB idle | ~500 MB |
| M12 (peer relay + bootstrap config) | ≤ 96 MB peak | ~500 MB |
| M13 (real multi-node validation) | ≤ 64 MB idle / ≤ 256 MB peak | ≤ 2 GB |
| M14 (representative mode + visibility) | ≤ 96 MB idle / ≤ 256 MB peak | ≤ 2 GB |
| M15 (distribution + decentralization tooling) | node budget unchanged; service budget separate | ≤ 2 GB node / service-specific |
| M16 (production UX + integrations) | node budget unchanged; indexer/explorer budget separate | ≤ 2 GB node / indexer-specific |
| M17 (stress + anti-spam tuning) | test-dependent; must still converge to ≤ 64 MB idle / ≤ 256 MB peak target | ≤ 2 GB target |
| M18 (public network readiness) | same public-node target as M17 | ≤ 2 GB target |
| Omitted | Reason |
|---|---|
| Nano protocol compatibility | We are our own network with a better protocol |
| GPU / OpenCL PoW | Requires heavy drivers; CPU PoW is sufficient |
| WebSocket server | RPC polling is enough for light clients |
| Full archival mode | Defeats the decentralisation goal; use pruning |
| Legacy block types | smallnano uses state blocks only from genesis |
| Smart contracts | Out of scope; pure payment network |
| Mining | No mining — weighted voting, zero energy waste |
- rsnano-node — Nano-compatible node in Rust, studied for protocol ideas only
- Nano protocol overview — design inspiration
- Zig language reference
- SQLite WAL mode — storage layer reference