Introduction
I recently finished building Toki, a peer-to-peer blockchain written entirely in Rust.
This wasn’t a tutorial project or a copy-paste experiment—it was an attempt to truly understand how blockchains and P2P systems work under the hood.
What I didn’t expect was how many things would break along the way.
This post isn’t a step-by-step tutorial.
It’s a developer log about what I built, what failed, and what I learned by fixing it.
What is Toki?
Toki is an educational blockchain node with the following features:
- Proof-of-Work consensus
- Wallets using Ed25519 public/private key cryptography
- Signed transactions and a mempool
- Block mining and validation
- libp2p-based peer-to-peer networking
- Gossip-based transaction and block propagation
- Multi-node support (real nodes, real connections)
Each node runs independently and communicates over a P2P network—no central server.
GitHub repo:
👉 https://github.com/sandy4242/Toki
Wallets & Transactions
Each wallet generates an Ed25519 keypair.
Transactions are signed using the private key and verified using the public key before being accepted.
This immediately taught me an important lesson:
If your transaction format or hashing logic is even slightly inconsistent, nothing works.
Rust’s strict typing helped catch mistakes early—but cryptography is unforgiving by design.
Mining & Blocks
Mining uses a simple Proof-of-Work mechanism:
- Increment a nonce
- Hash the block
- Check for a required number of leading zeros
It’s intentionally simple, but even here, small design choices matter:
- What exactly goes into the hash?
- How are transactions serialized?
- When is a block considered valid?
Getting deterministic hashing across nodes was harder than expected.
The Hard Part: P2P Networking
This is where most of my time went.
I used libp2p, the same networking stack used by IPFS and Polkadot.
It’s powerful—but very strict.
Some things that tripped me up:
-
SwarmConfigvsswarm::Config(API changes) - Futures not in scope (
libp2p::futures::StreamExt) - Async event loops that look “stuck” but are actually idle
- Multiaddr formatting (
/p2p/<PeerId>is mandatory) - Nodes don’t auto-connect—you must explicitly dial peers
At one point, both nodes were running perfectly…
and doing absolutely nothing.
Because in P2P systems:
If no one connects, nothing happens.
Once I understood that mental model, things finally clicked.
Gossip, Mempool, and Sync
Transactions are:
- Created on one node
- Gossiped to peers
- Validated and added to the mempool
- Mined into a block
- Broadcast back to the network
To avoid infinite rebroadcast loops, I had to implement basic message de-duplication.
This was the moment Toki stopped being “code” and started behaving like a networked system.
A Quick Git Lesson (Yes, Really)
At one point, I accidentally committed the entire target/ directory.
Thousands of files.
GitHub repo size exploded.
Lesson learned:
-
.gitignoredoes not untrack files - You must
git rm --cachedthem - Nested project directories make this worse
Not blockchain-related—but very real.
What I Learned
- P2P systems are event-driven, not request-driven
- libp2p is powerful but demands correctness
- Rust forces you to think clearly about ownership and state
- Cryptography has zero tolerance for “almost right”
- If your system compiles and connects, you’re probably doing something right
What’s Next for Toki?
This is v1.0. Planned next steps include:
- Longest-chain fork resolution
- Account balances and state tracking
- Bootstrap nodes
- Persistent storage
- Better CLI tooling
Final Thoughts
Building Toki taught me more about distributed systems than any tutorial ever could.
If you’re learning Rust, blockchain, or P2P networking—my advice is simple:
Build something that breaks. Then fix it.
That’s where the real learning happens.
Thanks for reading
~sandy
Top comments (0)