Module bitcoin_block_parser::blocks
source · Expand description
The BlockParser
trait allows you to implement a custom parser or use one of the predefined ones.
For example, imagine you want to take the biggest tx using Transaction::total_size
from the
first 600K blocks and sum their output [Amount
].
You can use the DefaultParser
to simply iterate over the Block
:
use bitcoin_block_parser::*;
let mut headers = HeaderParser::parse("/path/to/blocks")?;
let mut amount = bitcoin::Amount::ZERO;
for block in DefaultParser.parse(&headers[..600_000]) {
let txs = block?.txdata;
let max = txs.into_iter().max_by_key(|tx| tx.total_size());
for output in max.unwrap().output {
amount += output.value;
}
}
println!("Sum of txids: {}", amount);
If you wish to increase performance you may need to implement your own parser. This example
uses ~2x less memory and time since BlockParser::extract
and BlockParser::batch
reduce
the data size and both run on multiple threads. The more compute and memory your algorithm uses,
the more you may benefit from this.
use bitcoin::*;
use bitcoin_block_parser::*;
#[derive(Clone)]
struct AmountParser;
impl BlockParser<Transaction, Amount> for AmountParser {
fn extract(&self, block: Block) -> Option<Transaction> {
block.txdata.into_iter().max_by_key(|tx| tx.total_size())
}
fn batch(&self, items: Vec<Transaction>) -> Vec<Amount> {
let outputs = items.into_iter().flat_map(|tx| tx.output);
vec![outputs.map(|output| output.value).sum()]
}
}
let mut headers = HeaderParser::parse("/path/to/blocks")?;
let receiver = AmountParser.parse(&headers[..600_000]);
let amounts: anyhow::Result<Vec<Amount>> = receiver.iter().collect();
println!("Sum of txids: {}", amounts?.into_iter().sum::<Amount>());
You can also cache data within your BlockParser
by using an Arc
that will be shared
across all threads.
use std::sync::Arc;
use std::sync::atomic::*;
use bitcoin::*;
use bitcoin_block_parser::*;
#[derive(Clone, Default)]
struct AmountParser(Arc<AtomicU64>);
impl BlockParser<Transaction, Amount> for AmountParser {
fn extract(&self, block: bitcoin::Block) -> Option<Transaction> {
block.txdata.into_iter().max_by_key(|tx| tx.total_size())
}
fn batch(&self, items: Vec<Transaction>) -> Vec<Amount> {
let outputs = items.into_iter().flat_map(|tx| tx.output);
let sum = outputs.map(|output| output.value.to_sat()).sum();
// Aggregation occurs here
self.0.fetch_add(sum, Ordering::Relaxed);
vec![]
}
}
let mut headers = HeaderParser::parse("/path/to/blocks")?;
let parser = AmountParser::default();
for _ in parser.parse(&headers[..600_000]) {}
let sum = Amount::from_sat(parser.0.fetch_add(0, Ordering::Relaxed));
println!("Sum of txids: {}", sum);
Structs§
- Parser that returns
Block
for users that don’t implement a customBlockParser
- Options to tune the performance of the parser, generally you can stick to the defaults unless you run into memory issues.
Traits§
- Implement this trait to create a custom
Block
parser.