Roman Zeyde
7 years ago
3 changed files with 191 additions and 167 deletions
@ -0,0 +1,137 @@ |
|||
use bitcoin::blockdata::block::Block; |
|||
use bitcoin::network::serialize::BitcoinHash; |
|||
use bitcoin::network::serialize::{deserialize, serialize}; |
|||
use bitcoin::util::hash::Sha256dHash; |
|||
use byteorder::{LittleEndian, WriteBytesExt}; |
|||
use crypto::digest::Digest; |
|||
use crypto::sha2::Sha256; |
|||
|
|||
use daemon::Daemon; |
|||
use store::{Row, Store}; |
|||
use timer::Timer; |
|||
use pbr; |
|||
|
|||
use Bytes; |
|||
|
|||
const HASH_LEN: usize = 8; |
|||
|
|||
fn index_block(block: &Block, height: usize) -> Vec<Row> { |
|||
let null_hash = Sha256dHash::default(); |
|||
let mut rows = Vec::new(); |
|||
for tx in &block.txdata { |
|||
let txid: Sha256dHash = tx.txid(); |
|||
for input in &tx.input { |
|||
if input.prev_hash == null_hash { |
|||
continue; |
|||
} |
|||
let mut key = Vec::<u8>::new(); // ???
|
|||
key.push(b'I'); |
|||
key.extend_from_slice(&input.prev_hash[..HASH_LEN]); |
|||
key.write_u16::<LittleEndian>(input.prev_index as u16) |
|||
.unwrap(); |
|||
rows.push(Row { |
|||
key: key, |
|||
value: txid[..HASH_LEN].to_vec(), |
|||
}); |
|||
} |
|||
for output in &tx.output { |
|||
let mut script_hash = [0u8; 32]; |
|||
let mut sha2 = Sha256::new(); |
|||
sha2.input(&output.script_pubkey[..]); |
|||
sha2.result(&mut script_hash); |
|||
|
|||
let mut key = Vec::<u8>::new(); // ???
|
|||
key.push(b'O'); |
|||
key.extend_from_slice(&script_hash); |
|||
key.extend_from_slice(&txid[..HASH_LEN]); |
|||
rows.push(Row { |
|||
key: key, |
|||
value: vec![], |
|||
}); |
|||
} |
|||
// Persist transaction ID and confirmed height
|
|||
{ |
|||
let mut key = Vec::<u8>::new(); |
|||
key.push(b'T'); |
|||
key.extend_from_slice(&txid[..]); |
|||
let mut value = Vec::<u8>::new(); |
|||
value.write_u32::<LittleEndian>(height as u32).unwrap(); |
|||
rows.push(Row { |
|||
key: key, |
|||
value: value, |
|||
}) |
|||
} |
|||
} |
|||
// Persist block hash and header
|
|||
{ |
|||
let mut key = Vec::<u8>::new(); |
|||
key.push(b'B'); |
|||
key.extend_from_slice(&block.bitcoin_hash()[..]); |
|||
rows.push(Row { |
|||
key: key, |
|||
value: serialize(&block.header).unwrap(), |
|||
}) |
|||
} |
|||
rows |
|||
} |
|||
|
|||
fn get_missing_hashes(store: &mut Store, daemon: &Daemon) -> Vec<(usize, String)> { |
|||
let indexed_headers = store.read_headers(); |
|||
let mut hashes: Vec<(usize, String)> = daemon.enumerate_headers(); |
|||
info!( |
|||
"got {} headers (indexed {})", |
|||
hashes.len(), |
|||
indexed_headers.len(), |
|||
); |
|||
hashes.retain(|item| !indexed_headers.contains_key(&item.1)); |
|||
hashes |
|||
} |
|||
|
|||
pub fn update(store: &mut Store, daemon: &Daemon) { |
|||
let hashes = get_missing_hashes(store, daemon); |
|||
if hashes.is_empty() { |
|||
return; |
|||
} |
|||
|
|||
let mut timer = Timer::new(); |
|||
|
|||
let mut blocks_size = 0usize; |
|||
let mut rows_size = 0usize; |
|||
let mut num_of_rows = 0usize; |
|||
|
|||
let mut pb = pbr::ProgressBar::new(hashes.len() as u64); |
|||
for (height, blockhash) in hashes { |
|||
timer.start("get"); |
|||
let buf: Bytes = daemon.get(&format!("block/{}.bin", &blockhash)); |
|||
|
|||
timer.start("parse"); |
|||
let block: Block = deserialize(&buf).unwrap(); |
|||
assert_eq!(&block.bitcoin_hash().be_hex_string(), &blockhash); |
|||
|
|||
timer.start("index"); |
|||
let rows = index_block(&block, height); |
|||
for row in &rows { |
|||
rows_size += row.key.len() + row.value.len(); |
|||
} |
|||
num_of_rows += rows.len(); |
|||
|
|||
timer.start("store"); |
|||
store.persist(rows); |
|||
|
|||
timer.stop(); |
|||
blocks_size += buf.len(); |
|||
|
|||
pb.inc(); |
|||
debug!( |
|||
"{} @ {}: {:.3}/{:.3} MB, {} rows, {}", |
|||
blockhash, |
|||
height, |
|||
rows_size as f64 / 1e6_f64, |
|||
blocks_size as f64 / 1e6_f64, |
|||
num_of_rows, |
|||
timer.stats() |
|||
); |
|||
} |
|||
store.flush(); |
|||
pb.finish(); |
|||
} |
Loading…
Reference in new issue