WarpCoin Design
This document describes WarpCoin's consensus rules and the rationale behind the main design choices.
Goals
- Fast, cheap P2P payments. Short block times and an account-based ledger so balance/nonce checks are O(1) and transactions are small.
- Open mining. A proof of work that any CPU or GPU can compute, with a fair difficulty retarget so the network self-balances as hash power changes.
- Simplicity and auditability. Pure Go standard library, explicit serialization, and a small, readable codebase.
Ledger model: accounts, not UTXOs
WarpCoin uses an account/nonce model (like Ethereum) rather than Bitcoin's
UTXO set. Each address has a {balance, nonce} entry. A transaction spends from
the sender's balance and carries the sender's current nonce, which strictly
orders that sender's transactions and prevents replay.
Why accounts:
- Cheap validation. No UTXO set to scan or maintain; a transfer is two balance updates and a nonce bump.
- Small transactions. No input lists or change outputs — just
from → to, amount, fee, nonce. - Intuitive for payments. Balances map directly to what a wallet shows.
Transactions
A transaction is:
From, To, Amount, Fee, Nonce, Timestamp, PubKey, Signature
- The signing hash is
SHA256(SHA256(canonical-bytes-without-signature)). - Signatures are ECDSA over P-256, stored as a fixed 64-byte
r||s. - The sender's
PubKey(compressed, 33 bytes) must hash to theFromaddress, binding the key to the account. - Coinbase transactions (mining rewards) use the sentinel sender
WARP_COINBASE, mint new coins, and skip signature checks; their validity is enforced by the block rules (reward ≤ subsidy + fees).
Addresses
Base58Check( version(0x49) || RIPEMD-free-pubkey-hash(20) || checksum(4) ),
where the pubkey hash is the first 20 bytes of SHA256(SHA256(pubkey)) and the
checksum is the first 4 bytes of the double-SHA256 of the versioned payload.
Version 0x49 makes every address start with W.
Blocks and proof of work
A block has an 88-byte header plus a transaction list:
Version | PrevHash(32) | MerkleRoot(32) | Timestamp(8) | Height(8) | Bits(4) | Nonce(8)
- The PoW hash is
SHA256(SHA256(header)). A block is valid when that hash, read as a big-endian 256-bit integer, is<= target(Bits). Bitsis a Bitcoin-style compact target: high byte is the exponent, low three bytes the mantissa.- The Merkle root commits to every transaction, so a header alone proves which transactions a block contains.
SHA-256d is deliberately chosen because it is trivial to implement on CPUs and GPUs alike, maximizing who can participate in mining.
Difficulty retargeting
Every RetargetInterval (60) blocks, difficulty is recomputed from how long the
previous window actually took versus the target (60 × 30s = 30 min):
newTarget = oldTarget × (actualSpan / targetSpan)
The ratio is clamped to [1/4, 4] per retarget to resist timestamp
manipulation, and the target is never allowed to become easier than difficulty
1 (the genesis target). A fresh single-node network therefore starts easy and
ramps up automatically as miners join.
Fork choice and reorgs
Every block stores its cumulative work (Σ 2²⁵⁶ / (target+1)). The active
chain is the one with the most cumulative work. When a new block creates a
heavier chain that does not simply extend the current tip, the node performs a
reorg: it replays the heavier chain from the genesis state to rebuild the
account ledger, then switches the tip. Blocks whose parent is unknown are
treated as orphans and trigger a sync request for the missing ancestors.
Block reward and supply
The coinbase subsidy starts at 50 WARP and halves every 2,100,000 blocks (~2 years at 30s blocks), going to zero after 64 halvings. Miners also collect the fees of the transactions they include. A genesis premine of 20,000,000 WARP is allocated to founding holders in the genesis block.
Networking
Nodes speak a JSON-over-TCP gossip protocol:
- Handshake (
hello) exchanges protocol version, height, and listen address. - Discovery (
getpeers/peers) spreads known peer addresses. - Propagation relays new blocks (
newblock) and transactions (newtx), forwarding to all peers except the sender. - Sync uses
getblock/blockto pull successive blocks by height from a peer that advertises a greater height.
Locally accepted blocks (mined or received) are re-broadcast through a chain subscription hook, so the whole network converges on the most-work chain.
Security hardening
The implementation includes consensus, networking, and key-storage protections documented in full in SECURITY.md: overflow-safe accounting bounded by the maximum supply, duplicate-transaction rejection (closing the CVE-2012-2459 Merkle attack), low-S non-malleable signatures, monotonic timestamps, length-prefixed and size-capped P2P framing with deadlines, hardened HTTP servers with body limits and optional bearer-token RPC auth, and passphrase-encrypted keystores (PBKDF2-SHA256 + AES-256-GCM; automatic in the desktop app via the OS keychain).
Known simplifications
For a production/public launch the following would still be hardened (see the README roadmap):
- Coinbase maturity is defined (
CoinbaseMaturity = 100) but not yet enforced at spend time. - Reorg state rebuild replays from genesis rather than from the fork point; fine for the current scale, worth optimizing with state snapshots later.
- The P2P transport is unencrypted (all data is validated, but traffic is observable); optional encrypted transport is planned.
- Signatures are ECDSA (pre-quantum); a crypto-agility layer with hybrid post-quantum signatures is planned.
- No per-peer rate limiting / ban score yet.