bitcoin_block_parser

Module 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 every block and sum their output [Amount].

You can use the DefaultParser to simply iterate over the Block:

use bitcoin_block_parser::*;

let mut amount = bitcoin::Amount::ZERO;
for block in DefaultParser.parse_dir("/path/to/blocks").unwrap() {
    let txs = block.unwrap().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 only want to run on a subset of blocks use HeaderParser:

use bitcoin_block_parser::*;

let headers = HeaderParser::parse("/path/to/blocks").unwrap();
// Skip the first 200,000 blocks
for block in DefaultParser.parse(&headers[200_000..]) {
  // Do whatever you need with the blocks
}

If you wish to increase performance you may need to implement your own parser. This example uses ~2x less memory and less time since BlockParser::extract reduces the data size and runs 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<Amount> for AmountParser {
    fn extract(&self, block: Block) -> Vec<Amount> {
        let max = block.txdata.iter().max_by_key(|tx| tx.total_size());
        vec![max.unwrap().output.iter().map(|out| out.value).sum()]
    }
}

let receiver = AmountParser.parse_dir("/path/to/blocks").unwrap();
let amounts: anyhow::Result<Vec<Amount>> = receiver.iter().collect();
println!("Sum of txids: {}", amounts.unwrap().into_iter().sum::<Amount>());

You can also cache data within your BlockParser by using an Arc that will be shared across all threads. Updating any locked stated should take place in BlockParser::batch to reduce the contention on the lock.

use std::sync::*;
use bitcoin::*;
use bitcoin_block_parser::*;

#[derive(Clone, Default)]
struct AmountParser(Arc<Mutex<Amount>>);
impl BlockParser<Amount> for AmountParser {
    fn extract(&self, block: bitcoin::Block) -> Vec<Amount> {
        let max = block.txdata.iter().max_by_key(|tx| tx.total_size());
        vec![max.unwrap().output.iter().map(|out| out.value).sum()]
    }

    fn batch(&self, items: Vec<Amount>) -> Vec<Amount> {
        let mut sum = self.0.lock().unwrap();
        for item in items {
            *sum += item;
        }
        vec![]
    }
}

let parser = AmountParser::default();
for _ in parser.parse_dir("/path/to/blocks").unwrap() {}
println!("Sum of txids: {:?}", parser.0);

Structs§

  • Parser that returns Block for users that don’t implement a custom BlockParser
  • Parse all the blocks represented by the headers, ensuring the blocks are returned in the same order the ParsedHeader were passed in.
  • Options to tune the performance of the parser, generally you can stick to the defaults unless you run into memory issues.

Traits§