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 custom BlockParser
  • Options to tune the performance of the parser, generally you can stick to the defaults unless you run into memory issues.

Traits§