A Bitcoin full node in Rust 2024, built for fast initial block download and a small resident set, running script verification through the same library Bitcoin Core uses.
Script verification runs through libbitcoinkernel, the same library Bitcoin Core uses, so the hardest part of consensus is not reimplemented here. The block-level rules around it (BIP30, BIP34, weight and coinbase checks, and the rest) are this project's own code, and are covered by its own tests.
Four storage backends are selectable at runtime: fjall, RocksDB, MDBX, and redb. An equivalence test replays the same chain through all four and requires an identical aggregate hash.
The wallet is PSBT only. The node never handles a private key; signing happens behind an external signer trait.
Building the default configuration links libbitcoinkernel, which needs cmake
and libboost-dev on the system.
cargo build --release -p bitcoin-rs
./target/release/bitcoin-rs --data-dir .bitcoin-rsThat starts a mainnet node storing state in .bitcoin-rs and serving JSON-RPC
on 127.0.0.1:8332. See docs/getting-started.md for
backend selection, RPC authentication, and checking sync progress.
Running bitcoin-rs alongside the BIP300/301 enforcer is a separate deployment path with
its own Compose example: see tools/bip300301-enforcer for
the stack and docs/rest-interface.md for the REST surface the
enforcer consumes. It builds the production fjall plus bitcoinkernel profile and
binds RPC to the Docker host's loopback only.
Full verification replay of mainnet blocks 0 to 150,000 (1,718,407
transactions) from local block files, with --assume-valid-height 0 so no
script verification is skipped. Host: 80-CPU Intel Xeon Gold 6138, pinned to 32
physical cores with taskset -c 0-31. Three interleaved runs per contender,
medians reported. Bitcoin Core 31.0 was run with -reindex-chainstate -assumevalid=0 -connect=0 -dbcache=450.
| contender | wall | CPU | peak RSS |
|---|---|---|---|
| bitcoin-rs | 55.3s | 389.1s | 558 MB |
| Bitcoin Core 31.0 | 61.1s | 469.9s | 659 MB |
Measured at commit 686379a with the host near idle: 1.10x faster on
wall-clock, 1.21x less CPU, and a 1.18x smaller resident set. Both nodes reach
the same tip hash.
Full measurement conditions, session variance, and the comparative data against Bitcoin Core and GoCoin are documented in docs/benchmarks/end-to-end-sync.md. Read it before reusing any number here: only runs interleaved with Core inside one session are comparable.
Against GoCoin on the same harness: 2.6x faster on replay and 3.03x on peer-to-peer sync.
- Consensus verification via bitcoinkernel (libbitcoinkernel), covering both script-path and key-path spends.
- A 256-shard UTXO set: each shard is a
hashbrown::HashTableof compact records (ThinRecordBuf, one pointer-sized heap allocation per record) behind aparking_lot::RwLock, with a snapshot format and checkpoint-based crash recovery. - Block application in windows: consecutive blocks share one script verification dispatch, while each block still commits in order, so every rule that depends on committed state sees the real chain.
- Optional utreexo (Pollard, Stump, MemForest) for stateless validation.
- A native ScriptIndex with an Esplora HTTP surface, BIP157/158 filters, coinstats over MuHash, and pruning with Core's 288-block reorg-safety floor.
getblocktemplatefor mining.- Synchronous HTTP/1.1 JSON-RPC over sonic-rs using Core's method names. Signing methods return -32603, "wallet has no private keys; use external signer".
- mimalloc as the global allocator, over a crossbeam-channel event loop.
The defaults target mainnet initial block download.
| setting | default |
|---|---|
| storage backend | fjall |
| database cache | 450 MiB, matching Bitcoin Core |
| multi-peer download | on: 8 outbound peers, 128-block pending budget, 16 blocks in flight per peer |
| transaction index | off |
| block filter index | off |
| pruning | off |
| utreexo | off |
Mainnet also skips historical script verification up to height 938343, block
00000000000000000000ccebd6d74d9194d8dcdc1d177c478e094bfad51ba5ac. Checks are
skipped only once the node confirms the active header chain contains that exact
block, so a diverged chain or a tip below the anchor gets full verification.
Pass --assume-valid-height 0 to verify everything. Other networks default
to 0.
cargo build --release -p bitcoin-rsThe default features are rocksdb, fjall, redb, mdbx, and kernel.
cargo build --release -p bitcoin-rs --no-default-features --features fjallThe portable verifier supports only Taproot key-path spends, so a mainnet sync stops early; use it for development only. For portable builds without C++ dependencies and their verification trade-offs, see docs/getting-started.md.
cargo testGates that need live infrastructure are #[ignore]d. Run them individually
with -- --ignored once the documented environment is in place.
The node syncs, verifies, serves, and reorganises. The sync loop compares the header tip against the applied tip each tick and switches branches when the applied chain is outweighed.
It is still not the node to depend on. A disconnected block's transactions do
not return to the mempool, and the filter index is not backfilled across a gap.
The ZMQ pubsequence stream now publishes block connect/disconnect events, but
does not emit mempool A/R events. docs/README.md lists the rest.
- docs/getting-started.md — clone to synced node
- docs/ — the documentation index
- CONCEPTS.md — project vocabulary
- PLAN.md — roadmap and the G1-G15 verification gates
MIT OR Apache-2.0