2 changed files with 81 additions and 0 deletions
@ -0,0 +1,80 @@ |
|||||
|
use bitcoin::blockdata::block::Block; |
||||
|
use bitcoin::network::serialize::BitcoinHash; |
||||
|
use bitcoin::network::serialize::SimpleDecoder; |
||||
|
use bitcoin::network::serialize::{deserialize, RawDecoder}; |
||||
|
use std::fs; |
||||
|
use std::io::{Cursor, Seek, SeekFrom}; |
||||
|
use std::path::PathBuf; |
||||
|
use std::thread; |
||||
|
use std::time::Instant; |
||||
|
|
||||
|
use daemon::{list_blk_files, Network}; |
||||
|
use util::SyncChannel; |
||||
|
|
||||
|
use errors::*; |
||||
|
|
||||
|
/// An efficient parser for Bitcoin blk*.dat files.
|
||||
|
pub struct Parser { |
||||
|
files: Vec<PathBuf>, |
||||
|
} |
||||
|
|
||||
|
impl Parser { |
||||
|
pub fn new(network: Network) -> Result<Parser> { |
||||
|
Ok(Parser { |
||||
|
files: list_blk_files(network)?, |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
pub fn run(&self) -> Result<()> { |
||||
|
info!("reading {} files", self.files.len()); |
||||
|
let blobs = read_files(&self.files); |
||||
|
for blob in blobs.receiver().iter() { |
||||
|
let t = Instant::now(); |
||||
|
let blocks = parse_blk_file(&blob?); |
||||
|
debug!("parsing {} blocks took {:?}", blocks.len(), t.elapsed()); |
||||
|
} |
||||
|
Ok(()) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
fn read_files(files: &[PathBuf]) -> SyncChannel<Result<Vec<u8>>> { |
||||
|
let chan = SyncChannel::new(1); |
||||
|
let tx = chan.sender(); |
||||
|
let files = files.to_vec(); |
||||
|
thread::spawn(move || { |
||||
|
for f in &files { |
||||
|
let t = Instant::now(); |
||||
|
let msg = fs::read(f).chain_err(|| format!("failed to read {:?}", f)); |
||||
|
debug!("reading {:?} took {:?}", f, t.elapsed()); |
||||
|
tx.send(msg).unwrap(); |
||||
|
} |
||||
|
}); |
||||
|
chan |
||||
|
} |
||||
|
|
||||
|
fn parse_blk_file(data: &[u8]) -> Vec<Block> { |
||||
|
let mut cursor = Cursor::new(&data); |
||||
|
let mut result = vec![]; |
||||
|
let max_pos = data.len() as u64; |
||||
|
while cursor.position() < max_pos { |
||||
|
let mut decoder = RawDecoder::new(cursor); |
||||
|
match decoder.read_u32().expect("no magic") { |
||||
|
0 => break, |
||||
|
x => assert_eq!(x, 0xD9B4BEF9, "incorrect magic {:x}", x), |
||||
|
}; |
||||
|
let block_size = decoder.read_u32().expect("no block size"); |
||||
|
cursor = decoder.into_inner(); |
||||
|
|
||||
|
let start = cursor.position() as usize; |
||||
|
cursor |
||||
|
.seek(SeekFrom::Current(block_size as i64)) |
||||
|
.expect(&format!("seek {} failed", block_size)); |
||||
|
let end = cursor.position() as usize; |
||||
|
|
||||
|
let block: Block = deserialize(&data[start..end]) |
||||
|
.expect(&format!("failed to parse block at {}..{}", start, end)); |
||||
|
trace!("block {}, {} bytes", block.bitcoin_hash(), block_size); |
||||
|
result.push(block); |
||||
|
} |
||||
|
result |
||||
|
} |
Loading…
Reference in new issue