QIAOPANG.COM · SELECTED ESSAYS (2013–2026) · 260 ESSAYSBrowse Chronologically (2013 → 2026) ↗
QiaoPang · Programmers LifeSelected Essays · Systems, Craft & Agentic Era
Timeline ↗

A 1024 Tribute: The Simple Chain

A 1024 Tribute: The Simple Chain

Two weeks ago we brought CyberMiles’ supernode online. Because the CyberMiles mainnet runs on Tendermint, I spent last week digging into Tendermint, learning as I went and putting together a slide deck to introduce it.

Tendermint is a consensus engine born out of PBFT, and on top of it sits an Application Blockchain Interface (ABCI) that lets blockchain developers focus on what services to offer and how to maintain the state of those services — leaving the tedium of reaching consensus, managing the mempool, and running secure p2p communication to Tendermint itself. Tendermint is written in Go; its ABCI interface is defined in protobuf and talks to the application layer over raw TCP or http2 (gRPC).

A 1024 Tribute: The Simple Chain

Sunday rolled around with nothing to do, and I felt like building something with Tendermint. Alas, Tendermint offers no Elixir ABCI implementation, the community Erlang one is missing a few pieces, and I really dislike describing protobuf with Records in Erlang — so I used Tony’s protobuf library to write an Elixir ABCI implementation, published at github.com/arcblock/ex_abci, and then implemented the counter example app that Tendermint itself ships — using the blockchain’s immutability to maintain a single, network-wide counter.

With ex_abci, the core of the counter app is only a few dozen lines: implement the info, check_tx, and deliver_tx interfaces, and that’s it:

A 1024 Tribute: The Simple Chain

Such an app is fine as a hello world, a sanity check on whether Tendermint is trustworthy — but it isn’t trustworthy itself. Tendermint also ships a kv store example, which still doesn’t get at the core elements of a blockchain, so I got the urge to build something simple enough — ideally demonstrable within a few hundred lines — called Simple Chain. So what counts as the core element of a blockchain? I think it’s this diagram — the Merkle Patricia Tree (MPT):

A 1024 Tribute: The Simple Chain

This is the heart of how Ethereum stores its World State. I trust my readers know the Patricia tree (prefix tree, radix tree, or trie), and readers with some blockchain knowledge should know the Merkle tree; MPT combines the two into a self-verifying persistent data structure (the way functional programming languages store lists and maps). On MPT and the diagram above, our engineer Peiling Ding gave an excellent talk at the last Beijing Hackathon — those interested can find it on the ArcBlock YouTube channel: “ArcBlock’s Introduction to Blockchain,” where the MPT segment starts around minute 37 and runs about 10 minutes, remarkably clear and accessible. Space is limited, so I won’t expand on it here.

As for Simple Chain, here’s how I thought about the product:

  • Account system compatible with Ethereum
  • Make full use of all of Tendermint’s interfaces, and explore what they mean
  1. The chain’s state is stored in an MPT, with the state root after each block commit submitted to Tendermint
  2. The chain should have basic fault tolerance — e.g., if a tx crashes halfway through execution, it can recover to the previous block’s state and continue from there
  3. Transactions use a simplified version of the Ethereum tx: a TX contains only from, to, nonce, total, and pub key
  4. The MPT stores Ethereum-like accounts, each with its own balance, nonce, and num_txs
  5. The client RPC is integrated directly into the Wallet module, for easy demonstration

It took two days of work for a rough version — untested across multiple nodes — to finally come together; source code at: ex_abci/examples/simple_chain. Let’s talk about its main public interfaces:

  1. Wallet.new: generate an offline account
  2. Wallet.declare: each Wallet can, on first use, have the system credit it with 10,000 tokens — mainly for convenience in testing
  3. Wallet.transfer: one account sends money to another. The accounts corresponding to both addresses get updated in the chain’s MPT; after each block commits, the MPT root — that is, the app state — is written into the block header.
  4. Wallet.info / Wallet.chain_info: query account info / chain info

Below is the whole runtime process.

Initialization:

A 1024 Tribute: The Simple Chain

Wallet state:

A 1024 Tribute: The Simple Chain

Transfer:

A 1024 Tribute: The Simple Chain

A 1024 Tribute: The Simple Chain

A 1024 Tribute: The Simple Chain

Tendermint block:

A 1024 Tribute: The Simple Chain

State after the transfer completes:

A 1024 Tribute: The Simple Chain

The main technologies this Simple Chain uses:

  1. Tendermint and ex_abci, naturally
  2. The MPT implementation in Elixir: merkle_patricia_tree
  3. Tony’s protobuf implementation. We store accounts in the MPT, and their values are also defined with protobuf
  4. keccakf1600: the implementation of Ethereum’s sha3, used to generate account addresses and anywhere else a hash is needed (note: we do not use double hashing here)
  5. libsecp256k1: the ECDSA implementation, used mainly to generate wallets and to sign and verify transactions

The code currently sits under 400 lines, essentially transparent end to end — perfect for understanding Tendermint and the basic logic of blockchain technology.

I’d originally meant to publish this before 1024 Day (Programmer’s Day) — last night I botched the crash recovery, and this morning, driving through the fog on Highway 90, the idea suddenly came to me, so the article is late. Those interested in these technologies can sign up for our future Tech Talks at https://hack.arcblock.io/learning/, and follow the ArcBlock YouTube channel for our past knowledge-sharing sessions.

Happy 1024 Day, everyone!

MORE IN Systems & Architecture

Further Reading in This Column

View all essays in “Systems & Architecture” →

The Future of Logs: Rectifying Names

For a decade we built observability into a beautiful tower on a foundation of drifting strings—field names by convention, cardinality by luck, bills by endurance. This essay proposes a radical fix: use protobuf to give every observed event a proper name, unify logs, metrics, and audit into one versioned, owner-tagged, retention-aware event catalog, and keep an escape hatch called ForensicEvent for the unknown unknowns.

New Hope (2025–2026)10,772 chars · 24 min read

Abandoning Multi-Environment Entirely: Reshaping the Next-Generation Serverless Architecture with Rust and Pingora

When we return to first principles and reconsider what "compute" really is, we find that multi-environment setups are an illusion, Kubernetes is an over-abstraction, and Serverless cold starts and connection-pool storms are self-inflicted. This essay dissects an environment-less architecture built on Baggage Header routing, a Pingora smart gateway, Firecracker microVMs, and a Rust Data Bus — an attempt to answer: what should compute look like in the post-Kubernetes era?

New Hope (2025–2026)23,788 chars · 53 min read