Unverified Commit ea31d17c authored by Roman Zeyde's avatar Roman Zeyde
Browse files

Implement get_merkle API

parent 909802e6
use bincode;
use bitcoin::blockdata::block::BlockHeader;
use bitcoin::blockdata::block::{Block, BlockHeader};
use bitcoin::blockdata::transaction::Transaction;
use bitcoin::network::serialize::deserialize;
use bitcoin::util::hash::Sha256dHash;
......@@ -41,6 +41,11 @@ struct TxnHeight {
height: u32,
}
fn merklize(left: Sha256dHash, right: Sha256dHash) -> Sha256dHash {
let data = [&left[..], &right[..]].concat();
Sha256dHash::from_data(&data)
}
impl<'a> Query<'a> {
pub fn new(store: &'a Store, daemon: &'a Daemon, index: &'a Index) -> Query<'a> {
Query {
......@@ -168,4 +173,35 @@ impl<'a> Query<'a> {
let header_list = self.index.headers_list();
Some(header_list.headers().last()?.clone())
}
// TODO: add error-handling logic
pub fn get_merkle_proof(
&self,
tx_hash: &Sha256dHash,
height: usize,
) -> Option<(Vec<Sha256dHash>, usize)> {
let header_list = self.index.headers_list();
let blockhash = header_list.headers().get(height)?.hash();
let buf = self.daemon
.get(&format!("block/{}.bin", blockhash.be_hex_string()));
let block: Block = deserialize(&buf).unwrap();
let mut txids: Vec<Sha256dHash> = block.txdata.iter().map(|tx| tx.txid()).collect();
let pos = txids.iter().position(|txid| txid == tx_hash)?;
let mut merkle = Vec::new();
let mut index = pos;
while txids.len() > 1 {
if txids.len() % 2 != 0 {
let last = txids.last().unwrap().clone();
txids.push(last);
}
index = if index % 2 == 0 { index + 1 } else { index - 1 };
merkle.push(txids[index]);
index = index / 2;
txids = txids
.chunks(2)
.map(|pair| merklize(pair[0], pair[1]))
.collect()
}
Some((merkle, pos))
}
}
......@@ -161,8 +161,21 @@ impl<'a> Handler<'a> {
Ok(json!(tx_hex))
}
fn blockchain_transaction_get_merkle(&self, _params: &[Value]) -> Result<Value> {
Ok(json!({"block_height": 123, "merkle": ["A", "B", "C"], "pos": 45}))
fn blockchain_transaction_get_merkle(&self, params: &[Value]) -> Result<Value> {
let tx_hash = hash_from_value(params.get(0)).chain_err(|| "bad tx_hash")?;
let height = params.get(1).chain_err(|| "missing height")?;
let height = height.as_u64().chain_err(|| "non-number height")? as usize;
let (merkle, pos) = self.query
.get_merkle_proof(&tx_hash, height)
.chain_err(|| "cannot create merkle proof")?;
let merkle: Vec<String> = merkle
.into_iter()
.map(|txid| txid.be_hex_string())
.collect();
Ok(json!({
"block_height": height,
"merkle": merkle,
"pos": pos}))
}
fn handle_command(&self, method: &str, params: &[Value], id: &Number) -> Result<Value> {
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment