Iterates over Bitcoin blocks, decoding data inside Bitcoin Core's blocks directory.
Features:
Config::max_reorg
] parameter)BlockExtra
] like all block's previous outputs, it allows computing
transactions fee or verifying
scripts in the blockchain.Note:
Bitcoin Core 28.0 introduced xoring of bitcoin blocks and this project doesn't yet support reading the blocks directory when xored. You can disable xoring in core via -blocksxor=0
.
Used as a library blocks could be iterated via the [iter()
] method like:
// "blocks" dir contains first 400 testnet blocks
let conf = blocks_iterator::Config::new("../blocks", bitcoin::Network::Testnet);
let mut total_fee = 0u64;
for b in blocks_iterator::iter(conf) {
total_fee += b.fee().expect("fee available cause we are keeping prevouts");
}
// Only a bunch of tx with fee exists on testnet with height < 400
// in blocks: 385, 387, 389, 390, 392, 394
assert_eq!(total_fee, 450_000u64);
When the task to be performed is computational costly, like verifying spending conditions, it is
suggested to parallelize the execution like it's done with rayon (or similar) in the
verify example
(note par_bridge()
call).
Other than inside Rust programs, ordered blocks with previous outputs could be iterated using Unix pipes.
$ cargo build --release
$ cargo build --release --examples
$ ./target/release/blocks_iterator_cli --blocks-dir ~/.bitcoin/testnet3/blocks --network testnet --max-reorg 40 --stop-at-height 200000 | ./target/release/examples/with_pipe
...
[2023-03-31T15:01:23Z INFO with_pipe] Max number of txs: 6287 block: 0000000000bc915505318327aa0f18568ce024702a024d7c4a3ecfe80a893d6c
[2023-03-31T15:01:23Z INFO with_pipe] total missing reward: 50065529986 in 100 blocks
[2023-03-31T15:01:23Z INFO with_pipe] most_output tx is 640e22b5ddee1f6d2d701e37877027221ba5b36027634a2e3c3ee1569b4aa179 with #outputs: 10001
If you have more consumer process you can concatenate pipes by passing stdout to PipeIterator::new
or using tee
utility to split the stdout of blocks_iterator. The latter is better because it doesn't require re-serialization of the data.
Running (cargo run --release -- --network X --blocks-dir Y >/dev/null
) on threadripper 1950X,
Testnet @ 2130k, Mainnet @ 705k. Spinning disk. Take following benchmarks with a grain of salt
since they refer to older versions.
Network | --skip--prevout |
--max-reorg |
utxo-db |
Memory | Time |
---|---|---|---|---|---|
Mainnet | true | 6 | no | 33MB | 1h:00m |
Mainnet | false | 6 | no | 5.3GB | 1h:29m |
Mainnet | false | 6 | 1 run | 201MB | 9h:42m |
Mainnet | false | 6 | 2 run | 113MB | 1h:05m |
Testnet | true | 40 | no | 123MB | 3m:03s |
Testnet | false | 40 | no | 1.4GB | 8m:02s |
Testnet | false | 40 | 1 run | 247MB | 16m:12s |
Testnet | false | 40 | 2 run | 221MB | 8m:32s |
To build docs:
RUSTDOCFLAGS="--cfg docsrs" cargo +nightly doc --all-features --open
Run examples with:
cargo run --release --example verify
The 1.0
is not to be intended as battle-tested production-ready library, the binary format of
BlockExtra
changed and I wanted to highlight it with major version rollout.
blocks*.dat
serially, while blocks_iterator is doing two passes in parallel.Check minimum rust version run in CI, as of Aug 2023 is:
1.60.0
without features (needs some pinning, check CI)1.67.0
with features.