Browse Source

Completed migration to new bitcoin::hash_types

This commits contains fixes to merklization function arguments
and return types. New hash type system from bitcoin crate does
not cover all cases for merkle values; and the same function
may be applied to different hash types. Thus, I have used generic
types to abstract the logic.

`Txid` merklization operates with TxMerkleNode type;
`BlockHash` merklization does not introduce a new type: the same
design decision was made in the original work on new bitcoin
crate type system since it is used in a single case, and there is
no point in introducing a special designated hash type.

Script hashes (used in RPC queries) are left of Sha256dHash type
since there is no corresponding type defined in bitcoin crate;
this type is specific to Electrum X protocol. Corresponding
new type can be implemented in the project later with `hash_newtype!`
macro in the same way it was done in bitcoin crate.
android-patches
Dr. Maxim Orlovsky 5 years ago
parent
commit
0ccdf44181
  1. 32
      src/query.rs
  2. 14
      src/rpc.rs

32
src/query.rs

@ -1,6 +1,7 @@
use bitcoin::blockdata::transaction::Transaction;
use bitcoin::consensus::encode::deserialize;
use bitcoin::hash_types::{Txid, BlockHash, TxMerkleNode};
use bitcoin::hashes::sha256d::Hash as Sha256dHash;
use bitcoin_hashes::hex::ToHex;
use bitcoin_hashes::Hash;
use crypto::digest::Digest;
@ -116,15 +117,15 @@ struct TxnHeight {
height: u32,
}
fn merklize(left: TxMerkleNode, right: TxMerkleNode) -> TxMerkleNode {
fn merklize<T: Hash>(left: T, right: T) -> T {
let data = [&left[..], &right[..]].concat();
TxMerkleNode::hash(&data)
<T as Hash>::hash(&data)
}
fn create_merkle_branch_and_root(
mut hashes: Vec<TxMerkleNode>,
fn create_merkle_branch_and_root<T: Hash>(
mut hashes: Vec<T>,
mut index: usize,
) -> (Vec<TxMerkleNode>, TxMerkleNode) {
) -> (Vec<T>, T) {
let mut merkle = vec![];
while hashes.len() > 1 {
if hashes.len() % 2 != 0 {
@ -428,7 +429,11 @@ impl Query {
.iter()
.position(|txid| txid == tx_hash)
.chain_err(|| format!("missing txid {}", tx_hash))?;
let (branch, _root) = create_merkle_branch_and_root(txids, pos);
let tx_nodes: Vec<TxMerkleNode> = txids
.into_iter()
.map(|txid| TxMerkleNode::from_inner(txid.into_inner()))
.collect();
let (branch, _root) = create_merkle_branch_and_root(tx_nodes, pos);
Ok((branch, pos))
}
@ -436,7 +441,7 @@ impl Query {
&self,
height: usize,
cp_height: usize,
) -> Result<(Vec<BlockHash>, TxMerkleNode)> {
) -> Result<(Vec<Sha256dHash>, Sha256dHash)> {
if cp_height < height {
bail!("cp_height #{} < height #{}", cp_height, height);
}
@ -456,8 +461,12 @@ impl Query {
.into_iter()
.map(|h| *h.hash())
.collect();
let merkle_nodes: Vec<Sha256dHash> = header_hashes
.iter()
.map(|block_hash| Sha256dHash::from_inner(block_hash.into_inner()))
.collect();
assert_eq!(header_hashes.len(), heights.len());
Ok(create_merkle_branch_and_root(header_hashes, height))
Ok(create_merkle_branch_and_root(merkle_nodes, height))
}
pub fn get_id_from_pos(
@ -477,8 +486,13 @@ impl Query {
.get(tx_pos)
.chain_err(|| format!("No tx in position #{} in block #{}", tx_pos, height))?;
let tx_nodes = txids
.into_iter()
.map(|txid| TxMerkleNode::from_inner(txid.into_inner()))
.collect();
let branch = if want_merkle {
create_merkle_branch_and_root(txids, tx_pos).0
create_merkle_branch_and_root(tx_nodes, tx_pos).0
} else {
vec![]
};

14
src/rpc.rs

@ -1,7 +1,7 @@
use bitcoin::blockdata::transaction::Transaction;
use bitcoin::consensus::encode::{deserialize, serialize};
use bitcoin_hashes::hex::{FromHex, ToHex};
use bitcoin_hashes::sha256d::Hash as Sha256dHash;
use bitcoin_hashes::{Hash, sha256d::Hash as Sha256dHash};
use error_chain::ChainedError;
use hex;
use serde_json::{from_str, Value};
@ -21,10 +21,10 @@ const ELECTRS_VERSION: &str = env!("CARGO_PKG_VERSION");
const PROTOCOL_VERSION: &str = "1.4";
// TODO: Sha256dHash should be a generic hash-container (since script hash is single SHA256)
fn hash_from_value(val: Option<&Value>) -> Result<Sha256dHash> {
fn hash_from_value<T: Hash>(val: Option<&Value>) -> Result<T> {
let script_hash = val.chain_err(|| "missing hash")?;
let script_hash = script_hash.as_str().chain_err(|| "non-string hash")?;
let script_hash = Sha256dHash::from_hex(script_hash).chain_err(|| "non-hex hash")?;
let script_hash = T::from_hex(script_hash).chain_err(|| "non-hex hash")?;
Ok(script_hash)
}
@ -202,7 +202,7 @@ impl Connection {
}
fn blockchain_scripthash_subscribe(&mut self, params: &[Value]) -> Result<Value> {
let script_hash = hash_from_value(params.get(0)).chain_err(|| "bad script_hash")?;
let script_hash = hash_from_value::<Sha256dHash>(params.get(0)).chain_err(|| "bad script_hash")?;
let status = self.query.status(&script_hash[..])?;
let result = status.hash().map_or(Value::Null, |h| json!(hex::encode(h)));
self.status_hashes.insert(script_hash, result.clone());
@ -210,7 +210,7 @@ impl Connection {
}
fn blockchain_scripthash_get_balance(&self, params: &[Value]) -> Result<Value> {
let script_hash = hash_from_value(params.get(0)).chain_err(|| "bad script_hash")?;
let script_hash = hash_from_value::<Sha256dHash>(params.get(0)).chain_err(|| "bad script_hash")?;
let status = self.query.status(&script_hash[..])?;
Ok(
json!({ "confirmed": status.confirmed_balance(), "unconfirmed": status.mempool_balance() }),
@ -218,7 +218,7 @@ impl Connection {
}
fn blockchain_scripthash_get_history(&self, params: &[Value]) -> Result<Value> {
let script_hash = hash_from_value(params.get(0)).chain_err(|| "bad script_hash")?;
let script_hash = hash_from_value::<Sha256dHash>(params.get(0)).chain_err(|| "bad script_hash")?;
let status = self.query.status(&script_hash[..])?;
Ok(json!(Value::Array(
status
@ -230,7 +230,7 @@ impl Connection {
}
fn blockchain_scripthash_listunspent(&self, params: &[Value]) -> Result<Value> {
let script_hash = hash_from_value(params.get(0)).chain_err(|| "bad script_hash")?;
let script_hash = hash_from_value::<Sha256dHash>(params.get(0)).chain_err(|| "bad script_hash")?;
Ok(unspent_from_status(&self.query.status(&script_hash[..])?))
}

Loading…
Cancel
Save