Developers

How BitLooper is built, and how it gets updated

One Rust program, bitlooper, is the node, the validator and the wallet. This page shows its structure, how to run everything locally, and how changes reach the network.

Architecture

Wallet / CLImain.rs Website & explorerswebsite/ HTTP APIrpc.rs Consensus & mempoolnode.rs Other nodesp2p.rs (TCP) State machinestate.rs · types.rs Storagestore.rs Post-quantum cryptocrypto.rs Rules & genesisparams.rs · genesis.rs

Wallets and the website talk to a node's HTTP API. The node orders blocks with other nodes, and applies them through the state machine, which is the only place the rules live. Blocks, snapshots and the double-sign guard are stored on disk.

Run everything locally

  1. Install Rust (once)

    curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
  2. Start the development network and this website

    Builds the node, creates a 4-validator network in devnet/ (kept between runs), starts it, and serves this site at http://localhost:8090.

    scripts/dev.sh            # start (Ctrl-C stops everything)
    scripts/dev.sh --reset    # wipe the chain and start from a new genesis
  3. Use it

    Open the Explorer, get faucet coins, and follow How to use.

How code changes are made

  1. Change the code

    Rules live in node/src/state.rs and params.rs, consensus in node.rs, the website in website/. The web wallet compiles the node's own crypto.rs and types.rs to WebAssembly, so it signs exactly as nodes verify. After changing either file, run scripts/build-wallet.sh.

  2. Test

    cd node && cargo test --release

    Every rule change needs a unit test. The supply invariant (C + R = 100,000,000) is checked after every block in tests and in production.

  3. Try it on the devnet

    Restart scripts/dev.sh. Rule changes that alter state need --reset, because old blocks were made under old rules. Website changes only need a browser refresh.

  4. Review

    Every change is reviewed by someone other than its author before release.

How the live network gets updated

There are no admin keys, so no one can push an update into the network. Updates spread only because node operators choose to run them.

Kind of changeExampleProcess
Non-consensusFaster sync, better logs, API additionsRelease any time. Operators upgrade at their convenience, and old and new nodes interoperate.
Consensus ruleNew transaction type, new signature algorithmPublished specification, review, audit, then a release naming an activation height at least 6 months ahead. Operators who disagree keep the old rules.
Monetary rulesSupply cap, emission rate, fee ruleNot changeable by vote. Only a chain split by operators choosing different software could change them, and users can stay on the original chain.
Activation heights: every block header carries an app_version, and each release compiles in a schedule of (height, version) pairs (APP_VERSION_SCHEDULE, SPEC 3.13). A rule change ships as a release that adds a future height; upgraded nodes switch rules at exactly that block, and a node that did not upgrade refuses the block instead of forking silently. Headers also have a version and a reserved proof slot for future validity proofs.

HTTP API

EndpointReturns
GET /statusChain id, height, peers, base fee, supply (circulating, reserve, staked, issued)
GET /blocks/recent?n=20Summaries of the latest blocks
GET /block/{height}A full block and its commit certificate
GET /account/{address}Balance, nonce, key, safety settings, pending actions, recovery, name; ?proof=1 adds a Merkle proof
GET /proof/account/{address}A Merkle proof of the account against the latest state root (also /proof/validator/, /proof/name/, /proof/asset/{id}/)
GET /name/{name}Who owns a name, with a proof (wallets resolve @name here, then sign to the address)
GET /header/{height}A header and its commit certificate, for light clients
GET /stripped/{height}A block without signatures (history nodes)
GET /validatorsStake, power, signed blocks (uptime), rewards, jailed status
GET /checkpointsSnapshot heights and hashes a node can serve to new nodes
POST /txSubmit a signed transaction (JSON); returns its tx_id (stable, without signatures) and witness_hash
POST /faucet/{address}Testnet coins, if the node runs a faucet

Addresses in paths may be written in the checksummed form (tblpr1… on testnets, blpr1… on mainnet; a mistyped one is refused) or as 66 hex characters. JSON responses give the hex form in address and the checksummed one in display.

Formats (frozen for mainnet)

Everything hashed or signed uses one binary encoding (big-endian integers, length-prefixed byte strings, nothing skipped); JSON is only the transport. The byte-exact rules are in docs/SPEC.md sections 2-3, with test vectors in docs/test-vectors.json.

WhatFormat
SignaturesML-DSA-44/65, SLH-DSA-SHA2-128s with context bitlooper-v1; every signed message binds the chain id and the genesis hash, so a signature for one network never verifies on another
Transactionstx_id = SHA3 of the signing bytes (no signatures; stable); witness_hash covers both signatures, length-prefixed
Block headerVersion 2 (BLP-HDR-v2): version, app version, chain id, genesis hash, height, parent, time, proposer, and roots of transactions, witnesses, evidence, state, validator sets, the last commit and late commits, plus a reserved proof slot
Lists in a blockRFC 6962 Merkle trees (tagged leaves and nodes, no duplication) with the count bound
StateA sparse Merkle tree per part of the state (accounts, validators, assets, names…) under one state root: any balance can be proven to a phone, and a block re-hashes only what it changed
Addresses33 bytes on chain; shown as Bech32m with the prefix blpr (mainnet) or tblpr (testnets)
Namesregister_name: 3-20 characters a-z 0-9, one per account, first come first served; 100 / 10 / 1 coins for 3 / 4 / 5+ characters, paid to the reserve

Repository layout

blockchain/
├── node/                 Rust node, validator and wallet (bitlooper)
│   ├── src/crypto.rs     ML-DSA / SLH-DSA, addresses (Bech32m), list trees (RFC 6962)
│   ├── src/smt.rs        the Merkle state tree (sparse Merkle trees, proofs)
│   ├── src/types.rs      transactions, blocks, votes, canonical encodings
│   ├── src/state.rs      the rules: balances, safe accounts, staking, emission, slashing
│   ├── src/node.rs       BFT consensus, mempool, sync, snapshots, pruning
│   ├── src/p2p.rs        peer-to-peer transport
│   ├── src/store.rs      blocks, snapshots, double-sign guard
│   ├── src/rpc.rs        HTTP API
│   └── README.md
├── wallet-wasm/          browser wallet core: node crypto + transactions compiled to WebAssembly
├── website/              this site (static HTML) and wallet/pkg (generated WebAssembly)
├── scripts/dev.sh        local devnet + website
├── scripts/build-wallet.sh  rebuild the browser wallet core
└── devnet/               local chain data (created by dev.sh)