Browse Source

Simplify daemon's header download logic

refactor-mempool
Roman Zeyde 6 years ago
parent
commit
175e4cd4fc
No known key found for this signature in database GPG Key ID: 87CAE5FA46917CBB
  1. 105
      src/daemon.rs

105
src/daemon.rs

@ -1,7 +1,6 @@
use base64;
use bitcoin::blockdata::block::{Block, BlockHeader};
use bitcoin::blockdata::transaction::Transaction;
use bitcoin::network::serialize::BitcoinHash;
use bitcoin::network::serialize::{deserialize, serialize};
use bitcoin::util::hash::Sha256dHash;
use hex;
@ -11,7 +10,7 @@ use std::fs;
use std::io::{BufRead, BufReader, Write};
use std::net::TcpStream;
use util::{HeaderList, HeaderMap};
use util::{HeaderEntry, HeaderList};
use errors::*;
@ -132,26 +131,6 @@ impl Daemon {
Ok(reply["result"].take())
}
fn requests(&self, method: &str, params_list: &[Value]) -> Result<Vec<Value>> {
let reqs = params_list
.iter()
.map(|params| json!({"method": method, "params": params}))
.collect();
let mut result = vec![];
for reply in self.call_jsonrpc(&reqs)
.chain_err(|| format!("RPC failed: {}", reqs))?
.as_array_mut()
.chain_err(|| "non-array response")?
{
let err = reply["error"].take();
if !err.is_null() {
bail!("{} RPC error: {}", method, err);
}
result.push(reply["result"].take())
}
Ok(result)
}
// bitcoind JSONRPC API:
pub fn getblockchaininfo(&self) -> Result<BlockchainInfo> {
@ -163,29 +142,6 @@ impl Daemon {
parse_hash(&self.request("getbestblockhash", json!([]))?).chain_err(|| "invalid blockhash")
}
pub fn getblockheaders(&self, heights: &[usize]) -> Result<Vec<BlockHeader>> {
let heights: Vec<Value> = heights.iter().map(|height| json!([height])).collect();
let hashes: Vec<Value> = self.requests("getblockhash", &heights)?
.into_iter()
.map(|hash| json!([hash, /*verbose=*/ false]))
.collect();
let headers: Vec<Value> = self.requests("getblockheader", &hashes)?;
fn header_from_value(value: Value) -> Result<BlockHeader> {
let header_hex = value
.as_str()
.chain_err(|| format!("non-string header: {}", value))?;
let header_bytes = hex::decode(header_hex).chain_err(|| "non-hex header")?;
Ok(deserialize(&header_bytes)
.chain_err(|| format!("failed to parse blockheader {}", header_hex))?)
}
let mut result = vec![];
for h in headers {
result.push(header_from_value(h)?);
}
Ok(result)
}
pub fn getblockheader(&self, blockhash: &Sha256dHash) -> Result<BlockHeader> {
let header_hex: Value = self.request(
"getblockheader",
@ -257,55 +213,26 @@ impl Daemon {
)
}
pub fn get_all_headers(&self) -> Result<HeaderMap> {
let info: Value = self.request("getblockchaininfo", json!([]))?;
let max_height = info.get("blocks")
.expect("missing `blocks` attribute")
.as_u64()
.expect("`blocks` should be number") as usize;
let all_heights: Vec<usize> = (0..max_height).collect();
let chunk_size = 100_000;
let mut result = HeaderMap::new();
pub fn get_new_headers(
&self,
indexed_headers: &HeaderList,
bestblockhash: &Sha256dHash,
) -> Result<Vec<HeaderEntry>> {
// Iterate back over headers until known blockash is found:
let null_hash = Sha256dHash::default();
let mut blockhash = null_hash;
for heights in all_heights.chunks(chunk_size) {
let headers = self.getblockheaders(&heights)?;
assert!(headers.len() == heights.len());
debug!("downloaded {} headers", headers.len());
for header in headers {
blockhash = header.bitcoin_hash();
result.insert(blockhash, header);
}
}
let mut blockhash = *bestblockhash;
let mut new_headers = Vec::<BlockHeader>::new();
while blockhash != null_hash {
blockhash = result
.get(&blockhash)
.chain_err(|| format!("missing block header {}", blockhash))?
.prev_blockhash;
}
Ok(result)
}
pub fn get_latest_headers(&self, indexed_headers: &HeaderList) -> Result<HeaderList> {
let mut header_map = if indexed_headers.headers().is_empty() {
self.get_all_headers()
.chain_err(|| "failed to download all headers")?
} else {
indexed_headers.as_map()
};
// Get current best blockhash (using JSONRPC API)
let bestblockhash = self.getbestblockhash()?;
// Iterate back over headers until known blockash is found:
let mut blockhash = bestblockhash;
while !header_map.contains_key(&blockhash) {
if indexed_headers.header_by_blockhash(&blockhash).is_some() {
break;
}
let header = self.getblockheader(&blockhash)
.chain_err(|| format!("failed to get {} header", blockhash))?;
debug!("downloaded {} block header", blockhash);
header_map.insert(blockhash, header);
trace!("downloaded {} block header", blockhash);
new_headers.push(header);
blockhash = header.prev_blockhash;
}
Ok(HeaderList::build(header_map, bestblockhash))
new_headers.reverse(); // so the tip is the last vector entry
Ok(indexed_headers.order(new_headers))
}
}

Loading…
Cancel
Save