Working notes for agents/developers. README.md covers the project overview and
dependencies; this file covers how to build, run, test, and reason about the code
efficiently.
bitc is a thin SPV bitcoin client, 100% C, with a home-grown async network stack,
poll loop, and bitcoin engine. Console UI via ncurses. leveldb for the tx db.
make # binary is ./bitc
make clean
- Compiler: clang (gcc on armv6l). Flags in
Makefile. - macOS/Apple Silicon: OpenSSL/leveldb/etc. come from Homebrew under
/opt/homebrew. The Makefile derives this viabrew --prefixon Darwin, so a plainmakeworks. If headers/libs aren't found, checkbrew --prefix. - Build is warning-clean except one pre-existing
hashtable.cset but unusedwarning.-Werrorwas removed, so warnings don't fail the build.
The default ./bitc launches the ncurses TUI, which panics without a real
TTY (e.g. when backgrounded/piped). For any headless/agent work use daemon mode:
./bitc -d # daemon, no UI
./bitc -d --connect <ip[,ip...]> # pin specific peer(s), skip DNS/addrbook
./bitc -d --sync-and-exit # exit the moment headers reach the tip
time ./bitc -d --connect <ip> --sync-and-exit # clean header-sync benchmark
- Known-good peers (real height, serve headers, reachable):
137.226.34.45(RWTH),116.202.223.108(Hetzner),85.26.102.232. - Full header sync (~957k headers) takes ~25–45s; it is ~75% network
round-trip latency (479 serial
getheadersto one peer), not CPU/disk. headers.datpersists (~76 MB), so re-runs are incremental/instant. Force a fresh sync withrm ~/.bitc/headers.dator a full./bitc -z(zaps blockstore + addrbook + txdb).
- leveldb lock: a
kill -9leaves the txdb locked, so the next run fails withtxdb/LOCK: Resource temporarily unavailableand won't sync. Always:pkill -9 bitc; rm -f ~/.bitc/txdb/LOCKbefore re-running. - Logs:
/tmp/bitc-$USER.log(log level 1, µs timestamps, subsystem prefixes likePEERG:/WALLET:/BLCK:). Rotated per run (.0...9), so the base filename is always the latest run. Panics + backtraces land here too. ./bitc -t 0(self-test) has a pre-existing, unrelated failure: it spends from an empty wallet and the test ignoreswallet_craft_tx's error, so it asserts. Not a regression — ignore unless working on that test.
~/.bitc/ : headers.dat (block headers), peers.dat (addrbook), txdb/
(leveldb), wallet.cfg, main.cfg, contacts.cfg, tx-labels.cfg.
apps/cli/— CLI entry (main.c), ncurses UI (ncui.c,bitc_ui.c).core/— the engine:peer.c/peergroup.c(p2p + peer management),block-store.c(header chain + checkpoints),btc-message.c/serialize.c(wire protocol),key.c/crypt.c/hash.c(crypto),wallet.c,txdb.c,script.c,base58.c,rpc.c.lib/— reusable infra:poll/(home-grownpoll(2)event loop),netasync/(async sockets),util/,file/,poolworker/,config/, etc.core/— app-wide shared headers and implementation:bitc.h(the globalstruct BITCApp *btc),bitc-defs.h(protocol constants/messages), plus
Threading model (important, non-obvious): a single-threaded poll(2) event
loop (lib/poll, select(2) fallback) drives all socket I/O and message
handling — peer_receive_cb and everything it calls (block-store writes, peergroup
state) runs on that one thread, so that shared state needs no locking. The
"multi-threaded" claim is the separate 10-thread poolworker (lib/poolworker)
used for CPU offload. During header sync CPU sits ~27%; the work is latency-bound.
SPV mechanism: uses BIP157/158 compact block filters (not BIP37 bloom filters).
The old BIP37 peergroup_download_filtered_blocks path is dead code that hits an
ASSERT(0) in blockstore_get_hash_from_birth.
Header sync: driven by a single peergroup->downloadPeer (parallel download
from multiple peers corrupts the shared counters). Sync loops getheaders until a
batch adds nothing new; it does not trust a peer's advertised startingHeight
(monitoring nodes report 0 and are rejected/evicted). Checkpoints in
block-store.c (cpt_main) only cover up to height ~275000.
Prioritized improvements:
- Harden parsers and make little-endian serialization explicit.
- Add comprehensive tests, sanitizers, fuzzing, and CI.
- Validate header proof of work, difficulty, timestamps, and chainwork.
- Make wallet accounting reorg-safe.
- Version persistence formats and support recovery.
- Improve compact filter download parallelism and reorg handling.
- Add SegWit, Bech32m, and Taproot support.
- Migrate to versioned AEAD wallet encryption.
- Add descriptors, BIP32, and PSBT support.
- Improve peer diversity, addrv2, and eclipse resistance.
- Make execution contexts and thread ownership explicit.
- Enforce resource limits and replace unsafe assertions with robust error handling.
Until consensus validation and reorg correctness are addressed, the current client should be considered experimental and not a secure wallet.