From 969364af00e1428cf819f0ac064395b497beeb85 Mon Sep 17 00:00:00 2001 From: "Dr. Maxim Orlovsky" Date: Sun, 19 Apr 2020 23:39:57 +0200 Subject: [PATCH 1/2] WIP on migrating to new bitcoin::hash_types All types are replaced; only work on merkle types left, which requires addition of the code --- Cargo.lock | 116 ++++++++++--------------------------------------- Cargo.toml | 4 +- src/app.rs | 6 +-- src/bulk.rs | 8 ++-- src/cache.rs | 29 ++++++------- src/daemon.rs | 49 +++++++++++---------- src/index.rs | 36 +++++++-------- src/mempool.rs | 14 +++--- src/notify.rs | 6 +-- src/query.rs | 48 ++++++++++---------- src/util.rs | 34 +++++++-------- 11 files changed, 140 insertions(+), 210 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e0500a8..8ab4f0e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -83,7 +83,7 @@ dependencies = [ [[package]] name = "bech32" -version = "0.7.1" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -119,23 +119,21 @@ dependencies = [ [[package]] name = "bitcoin" -version = "0.21.0" +version = "0.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "bech32 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", - "bitcoin_hashes 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", - "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "bech32 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", + "bitcoin_hashes 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)", "hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "secp256k1 0.15.5 (registry+https://github.com/rust-lang/crates.io-index)", + "secp256k1 0.17.2 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "bitcoin_hashes" -version = "0.7.1" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -337,8 +335,8 @@ version = "0.8.3" dependencies = [ "base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", "bincode 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "bitcoin 0.21.0 (registry+https://github.com/rust-lang/crates.io-index)", - "bitcoin_hashes 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", + "bitcoin 0.23.0 (registry+https://github.com/rust-lang/crates.io-index)", + "bitcoin_hashes 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)", "configure_me 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "configure_me_codegen 0.3.12 (registry+https://github.com/rust-lang/crates.io-index)", "crossbeam-channel 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", @@ -717,33 +715,6 @@ dependencies = [ "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "rand" -version = "0.6.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_isaac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_jitter 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_pcg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rand_chacha" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "rand_core" version = "0.3.1" @@ -757,32 +728,6 @@ name = "rand_core" version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "rand_hc" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rand_isaac" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rand_jitter" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "rand_os" version = "0.1.3" @@ -796,23 +741,6 @@ dependencies = [ "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "rand_pcg" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rand_xorshift" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "rayon" version = "1.2.0" @@ -946,11 +874,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "secp256k1" -version = "0.15.5" +version = "0.17.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "secp256k1-sys 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "secp256k1-sys" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cc 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1273,11 +1209,11 @@ dependencies = [ "checksum backtrace 0.3.40 (registry+https://github.com/rust-lang/crates.io-index)" = "924c76597f0d9ca25d762c25a4d369d51267536465dc5064bdf0eb073ed477ea" "checksum backtrace-sys 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)" = "5d6575f128516de27e3ce99689419835fce9643a9b215a14d2b5b685be018491" "checksum base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0b25d992356d2eb0ed82172f5248873db5560c4721f564b13cb5193bda5e668e" -"checksum bech32 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9e0089c35ab7c6f2bc55ab23f769913f0ac65b1023e7e74638a1f43128dd5df2" +"checksum bech32 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "cdcf67bb7ba7797a081cd19009948ab533af7c355d5caf1d08c777582d351e9c" "checksum bincode 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b8ab639324e3ee8774d296864fbc0dbbb256cf1a41c490b94cba90c082915f92" "checksum bindgen 0.47.3 (registry+https://github.com/rust-lang/crates.io-index)" = "df683a55b54b41d5ea8ebfaebb5aa7e6b84e3f3006a78f010dadc9ca88469260" -"checksum bitcoin 0.21.0 (registry+https://github.com/rust-lang/crates.io-index)" = "dc34f963060a2091b4e285d8082e1946be35caf467e73b3155262c8357fb4595" -"checksum bitcoin_hashes 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "db6b697833d852acea530c9e815e6adc724267856b6506bc500362a068a39c7b" +"checksum bitcoin 0.23.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6a32c9d2fa897cfbb0db45d71e3d2838666194abc4828c0f994e4b5c3bf85ba4" +"checksum bitcoin_hashes 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)" = "b375d62f341cef9cd9e77793ec8f1db3fc9ce2e4d57e982c8fe697a2c16af3b6" "checksum bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" "checksum blake2b_simd 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)" = "5850aeee1552f495dd0250014cf64b82b7c8879a89d83b33bbdace2cc4f63182" "checksum byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a7c3dd8985a7111efc5c80b44e23ecdd8c007de8ade3b96595387e812b957cf5" @@ -1347,16 +1283,9 @@ dependencies = [ "checksum quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "053a8c8bcc71fcce321828dc897a98ab9760bef03a4fc36693c231e5b3216cfe" "checksum rand 0.3.23 (registry+https://github.com/rust-lang/crates.io-index)" = "64ac302d8f83c0c1974bf758f6b041c6c8ada916fbb44a609158ca8b064cc76c" "checksum rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "552840b97013b1a26992c11eac34bdd778e464601a4c2054b5f0bff7c6761293" -"checksum rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca" -"checksum rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef" "checksum rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" "checksum rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc" -"checksum rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7b40677c7be09ae76218dc623efbf7b18e34bced3f38883af07bb75630a21bc4" -"checksum rand_isaac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ded997c9d5f13925be2a6fd7e66bf1872597f759fd9dd93513dd7e92e5a5ee08" -"checksum rand_jitter 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "1166d5c91dc97b88d1decc3285bb0a99ed84b05cfd0bc2341bdf2d43fc41e39b" "checksum rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7b75f676a1e053fc562eafbb47838d67c84801e38fc1ba459e8f180deabd5071" -"checksum rand_pcg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "abf9b09b01790cfe0364f52bf32995ea3c39f4d2dd011eac241d2914146d0b44" -"checksum rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cbf7e9e623549b0e21f6e97cf8ecf247c1a8fd2e8a992ae265314300b2455d5c" "checksum rayon 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "83a27732a533a1be0a0035a111fe76db89ad312f6f0347004c220c57f209a123" "checksum rayon-core 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "98dcf634205083b17d0861252431eb2acbfb698ab7478a2d20de07954f47ec7b" "checksum rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" @@ -1374,7 +1303,8 @@ dependencies = [ "checksum ryu 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "bfa8506c1de11c9c4e4c38863ccbe02a305c8188e85a05a784c9e11e1c3910c8" "checksum scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "94258f53601af11e6a49f722422f6e3425c52b06245a5cf9bc09908b174f5e27" "checksum scopeguard 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b42e15e59b18a828bbf5c58ea01debb36b9b096346de35d941dcb89009f24a0d" -"checksum secp256k1 0.15.5 (registry+https://github.com/rust-lang/crates.io-index)" = "4d311229f403d64002e9eed9964dfa5a0a0c1ac443344f7546bf48e916c6053a" +"checksum secp256k1 0.17.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2932dc07acd2066ff2e3921a4419606b220ba6cd03a9935123856cc534877056" +"checksum secp256k1-sys 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7ab2c26f0d3552a0f12e639ae8a64afc2e3db9c52fe32f5fc6c289d38519f220" "checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" "checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" "checksum serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)" = "9796c9b7ba2ffe7a9ce53c2287dfc48080f4b2b362fcc245a259b3a7201119dd" diff --git a/Cargo.toml b/Cargo.toml index a5f2ca5..fa21354 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -24,8 +24,8 @@ latest_rust = [] # use latest Rust features (otherwise, support Rust 1.34) [dependencies] base64 = "0.10" bincode = "1.0" -bitcoin = { version = "0.21", features = ["use-serde"] } -bitcoin_hashes = "0.7.1" +bitcoin = { version = "0.23", features = ["use-serde"] } +bitcoin_hashes = "0.7.6" configure_me = "0.3.3" crossbeam-channel = "0.3" dirs = "1.0" diff --git a/src/app.rs b/src/app.rs index 54d46e2..0e4f275 100644 --- a/src/app.rs +++ b/src/app.rs @@ -1,4 +1,4 @@ -use bitcoin_hashes::sha256d::Hash as Sha256dHash; +use bitcoin::hash_types::BlockHash; use std::sync::{Arc, Mutex}; use crate::{config::Config, daemon, errors::*, index, signal::Waiter, store}; @@ -8,7 +8,7 @@ pub struct App { index: index::Index, daemon: daemon::Daemon, banner: String, - tip: Mutex, + tip: Mutex, } impl App { @@ -23,7 +23,7 @@ impl App { index, daemon: daemon.reconnect()?, banner: config.server_banner.clone(), - tip: Mutex::new(Sha256dHash::default()), + tip: Mutex::new(BlockHash::default()), })) } diff --git a/src/bulk.rs b/src/bulk.rs index 8b7e0e6..51b4d69 100644 --- a/src/bulk.rs +++ b/src/bulk.rs @@ -1,7 +1,6 @@ +use bitcoin::hash_types::BlockHash; use bitcoin::blockdata::block::Block; use bitcoin::consensus::encode::{deserialize, Decodable}; -use bitcoin::util::hash::BitcoinHash; -use bitcoin_hashes::sha256d::Hash as Sha256dHash; use libc; use std::collections::HashSet; use std::fs; @@ -20,11 +19,12 @@ use crate::metrics::{CounterVec, Histogram, HistogramOpts, HistogramVec, MetricO use crate::signal::Waiter; use crate::store::{DBStore, Row, WriteStore}; use crate::util::{spawn_thread, HeaderList, SyncChannel}; +use bitcoin::BitcoinHash; struct Parser { magic: u32, current_headers: HeaderList, - indexed_blockhashes: Mutex>, + indexed_blockhashes: Mutex>, // metrics duration: HistogramVec, block_count: CounterVec, @@ -35,7 +35,7 @@ impl Parser { fn new( daemon: &Daemon, metrics: &Metrics, - indexed_blockhashes: HashSet, + indexed_blockhashes: HashSet, ) -> Result> { Ok(Arc::new(Parser { magic: daemon.magic(), diff --git a/src/cache.rs b/src/cache.rs index 5a59bb2..26b5f56 100644 --- a/src/cache.rs +++ b/src/cache.rs @@ -1,9 +1,9 @@ use crate::errors::*; use crate::metrics::{CounterVec, MetricOpts, Metrics}; +use bitcoin::hash_types::{BlockHash, Txid}; use bitcoin::blockdata::transaction::Transaction; use bitcoin::consensus::encode::deserialize; -use bitcoin_hashes::sha256d::Hash as Sha256dHash; use lru::LruCache; use prometheus::IntGauge; use std::hash::Hash; @@ -62,7 +62,7 @@ impl SizedLruCache { } pub struct BlockTxIDsCache { - map: Mutex>>, + map: Mutex>>, } impl BlockTxIDsCache { @@ -85,11 +85,11 @@ impl BlockTxIDsCache { pub fn get_or_else( &self, - blockhash: &Sha256dHash, + blockhash: &BlockHash, load_txids_func: F, - ) -> Result> + ) -> Result> where - F: FnOnce() -> Result>, + F: FnOnce() -> Result>, { if let Some(txids) = self.map.lock().unwrap().get(blockhash) { return Ok(txids.clone()); @@ -107,7 +107,7 @@ impl BlockTxIDsCache { pub struct TransactionCache { // Store serialized transaction (should use less RAM). - map: Mutex>>, + map: Mutex>>, } impl TransactionCache { @@ -128,7 +128,7 @@ impl TransactionCache { } } - pub fn get_or_else(&self, txid: &Sha256dHash, load_txn_func: F) -> Result + pub fn get_or_else(&self, txid: &Txid, load_txn_func: F) -> Result where F: FnOnce() -> Result>, { @@ -201,17 +201,17 @@ mod tests { assert_eq!(usage.get(), 100); } - fn gen_hash(seed: u8) -> Sha256dHash { + fn gen_hash(seed: u8) -> T { let bytes: Vec = (seed..seed + 32).collect(); - Sha256dHash::hash(&bytes[..]) + ::hash(&bytes[..]) } #[test] fn test_blocktxids_cache_hit_and_miss() { - let block1 = gen_hash(1); - let block2 = gen_hash(2); - let block3 = gen_hash(3); - let txids = vec![gen_hash(4), gen_hash(5)]; + let block1: BlockHash = gen_hash(1); + let block2: BlockHash = gen_hash(2); + let block3: BlockHash = gen_hash(3); + let txids: Vec = vec![gen_hash(4), gen_hash(5)]; let misses: Mutex = Mutex::new(0); let miss_func = || { @@ -249,7 +249,6 @@ mod tests { #[test] fn test_txn_cache() { - use bitcoin::util::hash::BitcoinHash; use hex; let dummy_metrics = Metrics::new("127.0.0.1:60000".parse().unwrap()); @@ -257,7 +256,7 @@ mod tests { let tx_bytes = hex::decode("0100000001a15d57094aa7a21a28cb20b59aab8fc7d1149a3bdbcddba9c622e4f5f6a99ece010000006c493046022100f93bb0e7d8db7bd46e40132d1f8242026e045f03a0efe71bbb8e3f475e970d790221009337cd7f1f929f00cc6ff01f03729b069a7c21b59b1736ddfee5db5946c5da8c0121033b9b137ee87d5a812d6f506efdd37f0affa7ffc310711c06c7f3e097c9447c52ffffffff0100e1f505000000001976a9140389035a9225b3839e2bbf32d826a1e222031fd888ac00000000").unwrap(); let tx: Transaction = deserialize(&tx_bytes).unwrap(); - let txid = tx.bitcoin_hash(); + let txid = tx.txid(); let mut misses = 0; assert_eq!( diff --git a/src/daemon.rs b/src/daemon.rs index c049d46..f9ad8f2 100644 --- a/src/daemon.rs +++ b/src/daemon.rs @@ -1,11 +1,11 @@ use base64; +use bitcoin_hashes::Hash; +use bitcoin::hash_types::{BlockHash, Txid}; use bitcoin::blockdata::block::{Block, BlockHeader}; use bitcoin::blockdata::transaction::Transaction; use bitcoin::consensus::encode::{deserialize, serialize}; use bitcoin::network::constants::Network; -use bitcoin::util::hash::BitcoinHash; use bitcoin_hashes::hex::{FromHex, ToHex}; -use bitcoin_hashes::sha256d::Hash as Sha256dHash; use glob; use hex; use serde_json::{from_str, from_value, Map, Value}; @@ -22,9 +22,10 @@ use crate::errors::*; use crate::metrics::{HistogramOpts, HistogramVec, Metrics}; use crate::signal::Waiter; use crate::util::HeaderList; +use bitcoin::BitcoinHash; -fn parse_hash(value: &Value) -> Result { - Ok(Sha256dHash::from_hex( +fn parse_hash(value: &Value) -> Result { + Ok(T::from_hex( value .as_str() .chain_err(|| format!("non-string value: {}", value))?, @@ -460,11 +461,11 @@ impl Daemon { Ok(self.getnetworkinfo()?.relayfee) } - pub fn getbestblockhash(&self) -> Result { + pub fn getbestblockhash(&self) -> Result { parse_hash(&self.request("getbestblockhash", json!([]))?).chain_err(|| "invalid blockhash") } - pub fn getblockheader(&self, blockhash: &Sha256dHash) -> Result { + pub fn getblockheader(&self, blockhash: &BlockHash) -> Result { header_from_value(self.request( "getblockheader", json!([blockhash.to_hex(), /*verbose=*/ false]), @@ -485,7 +486,7 @@ impl Daemon { Ok(result) } - pub fn getblock(&self, blockhash: &Sha256dHash) -> Result { + pub fn getblock(&self, blockhash: &BlockHash) -> Result { let block = block_from_value( self.request("getblock", json!([blockhash.to_hex(), /*verbose=*/ false]))?, )?; @@ -493,7 +494,7 @@ impl Daemon { Ok(block) } - fn load_blocktxids(&self, blockhash: &Sha256dHash) -> Result> { + fn load_blocktxids(&self, blockhash: &BlockHash) -> Result> { self.request("getblock", json!([blockhash.to_hex(), /*verbose=*/ 1]))? .get("tx") .chain_err(|| "block missing txids")? @@ -501,15 +502,15 @@ impl Daemon { .chain_err(|| "invalid block txids")? .iter() .map(parse_hash) - .collect::>>() + .collect::>>() } - pub fn getblocktxids(&self, blockhash: &Sha256dHash) -> Result> { + pub fn getblocktxids(&self, blockhash: &BlockHash) -> Result> { self.blocktxids_cache .get_or_else(&blockhash, || self.load_blocktxids(blockhash)) } - pub fn getblocks(&self, blockhashes: &[Sha256dHash]) -> Result> { + pub fn getblocks(&self, blockhashes: &[BlockHash]) -> Result> { let params_list: Vec = blockhashes .iter() .map(|hash| json!([hash.to_hex(), /*verbose=*/ false])) @@ -524,8 +525,8 @@ impl Daemon { pub fn gettransaction( &self, - txhash: &Sha256dHash, - blockhash: Option, + txhash: &Txid, + blockhash: Option, ) -> Result { let mut args = json!([txhash.to_hex(), /*verbose=*/ false]); if let Some(blockhash) = blockhash { @@ -536,8 +537,8 @@ impl Daemon { pub fn gettransaction_raw( &self, - txhash: &Sha256dHash, - blockhash: Option, + txhash: &Txid, + blockhash: Option, verbose: bool, ) -> Result { let mut args = json!([txhash.to_hex(), verbose]); @@ -547,7 +548,7 @@ impl Daemon { Ok(self.request("getrawtransaction", args)?) } - pub fn gettransactions(&self, txhashes: &[&Sha256dHash]) -> Result> { + pub fn gettransactions(&self, txhashes: &[&Txid]) -> Result> { let params_list: Vec = txhashes .iter() .map(|txhash| json!([txhash.to_hex(), /*verbose=*/ false])) @@ -562,7 +563,7 @@ impl Daemon { Ok(txs) } - pub fn getmempooltxids(&self) -> Result> { + pub fn getmempooltxids(&self) -> Result> { let txids: Value = self.request("getrawmempool", json!([/*verbose=*/ false]))?; let mut result = HashSet::new(); for value in txids.as_array().chain_err(|| "non-array result")? { @@ -571,7 +572,7 @@ impl Daemon { Ok(result) } - pub fn getmempoolentry(&self, txid: &Sha256dHash) -> Result { + pub fn getmempoolentry(&self, txid: &Txid) -> Result { let entry = self.request("getmempoolentry", json!([txid.to_hex()]))?; let fee = (entry .get("fee") @@ -588,16 +589,16 @@ impl Daemon { Ok(MempoolEntry::new(fee, vsize)) } - pub fn broadcast(&self, tx: &Transaction) -> Result { + pub fn broadcast(&self, tx: &Transaction) -> Result { let tx = hex::encode(serialize(tx)); let txid = self.request("sendrawtransaction", json!([tx]))?; Ok( - Sha256dHash::from_hex(txid.as_str().chain_err(|| "non-string txid")?) + Txid::from_hex(txid.as_str().chain_err(|| "non-string txid")?) .chain_err(|| "failed to parse txid")?, ) } - fn get_all_headers(&self, tip: &Sha256dHash) -> Result> { + fn get_all_headers(&self, tip: &BlockHash) -> Result> { let info: Value = self.request("getblockheader", json!([tip.to_hex()]))?; let tip_height = info .get("height") @@ -607,7 +608,7 @@ impl Daemon { let all_heights: Vec = (0..=tip_height).collect(); let chunk_size = 100_000; let mut result = vec![]; - let null_hash = Sha256dHash::default(); + let null_hash = BlockHash::default(); for heights in all_heights.chunks(chunk_size) { trace!("downloading {} block headers", heights.len()); let mut headers = self.getblockheaders(&heights)?; @@ -628,7 +629,7 @@ impl Daemon { pub fn get_new_headers( &self, indexed_headers: &HeaderList, - bestblockhash: &Sha256dHash, + bestblockhash: &BlockHash, ) -> Result> { // Iterate back over headers until known blockash is found: if indexed_headers.is_empty() { @@ -640,7 +641,7 @@ impl Daemon { bestblockhash, ); let mut new_headers = vec![]; - let null_hash = Sha256dHash::default(); + let null_hash = BlockHash::default(); let mut blockhash = *bestblockhash; while blockhash != null_hash { if indexed_headers.header_by_blockhash(&blockhash).is_some() { diff --git a/src/index.rs b/src/index.rs index 2234a65..2187233 100644 --- a/src/index.rs +++ b/src/index.rs @@ -1,9 +1,8 @@ use bincode; +use bitcoin::hash_types::{BlockHash, Txid}; use bitcoin::blockdata::block::{Block, BlockHeader}; use bitcoin::blockdata::transaction::{Transaction, TxIn, TxOut}; use bitcoin::consensus::encode::{deserialize, serialize}; -use bitcoin::util::hash::BitcoinHash; -use bitcoin_hashes::sha256d::Hash as Sha256dHash; use crypto::digest::Digest; use crypto::sha2::Sha256; use std::collections::{HashMap, HashSet}; @@ -21,6 +20,7 @@ use crate::util::{ full_hash, hash_prefix, spawn_thread, Bytes, FullHash, HashPrefix, HeaderEntry, HeaderList, HeaderMap, SyncChannel, HASH_PREFIX_LEN, }; +use bitcoin::BitcoinHash; #[derive(Serialize, Deserialize)] pub struct TxInKey { @@ -36,7 +36,7 @@ pub struct TxInRow { } impl TxInRow { - pub fn new(txid: &Sha256dHash, input: &TxIn) -> TxInRow { + pub fn new(txid: &Txid, input: &TxIn) -> TxInRow { TxInRow { key: TxInKey { code: b'I', @@ -47,7 +47,7 @@ impl TxInRow { } } - pub fn filter(txid: &Sha256dHash, output_index: usize) -> Bytes { + pub fn filter(txid: &Txid, output_index: usize) -> Bytes { bincode::serialize(&TxInKey { code: b'I', prev_hash_prefix: hash_prefix(&txid[..]), @@ -81,7 +81,7 @@ pub struct TxOutRow { } impl TxOutRow { - pub fn new(txid: &Sha256dHash, output: &TxOut) -> TxOutRow { + pub fn new(txid: &Txid, output: &TxOut) -> TxOutRow { TxOutRow { key: TxOutKey { code: b'O', @@ -123,7 +123,7 @@ pub struct TxRow { } impl TxRow { - pub fn new(txid: &Sha256dHash, height: u32) -> TxRow { + pub fn new(txid: &Txid, height: u32) -> TxRow { TxRow { key: TxKey { code: b'T', @@ -137,7 +137,7 @@ impl TxRow { [b"T", &txid_prefix[..]].concat() } - pub fn filter_full(txid: &Sha256dHash) -> Bytes { + pub fn filter_full(txid: &Txid) -> Bytes { [b"T", &txid[..]].concat() } @@ -174,8 +174,8 @@ pub fn index_transaction<'a>( txn: &'a Transaction, height: usize, ) -> impl 'a + Iterator { - let null_hash = Sha256dHash::default(); - let txid: Sha256dHash = txn.txid(); + let null_hash = Txid::default(); + let txid = txn.txid(); let inputs = txn.input.iter().filter_map(move |input| { if input.previous_output.txid == null_hash { @@ -213,7 +213,7 @@ pub fn index_block<'a>(block: &'a Block, height: usize) -> impl 'a + Iterator Row { +pub fn last_indexed_block(blockhash: &BlockHash) -> Row { // Store last indexed block (i.e. all previous blocks were indexed) Row { key: b"L".to_vec(), @@ -221,7 +221,7 @@ pub fn last_indexed_block(blockhash: &Sha256dHash) -> Row { } } -pub fn read_indexed_blockhashes(store: &dyn ReadStore) -> HashSet { +pub fn read_indexed_blockhashes(store: &dyn ReadStore) -> HashSet { let mut result = HashSet::new(); for row in store.scan(b"B") { let key: BlockKey = bincode::deserialize(&row.key).unwrap(); @@ -231,10 +231,10 @@ pub fn read_indexed_blockhashes(store: &dyn ReadStore) -> HashSet { } fn read_indexed_headers(store: &dyn ReadStore) -> HeaderList { - let latest_blockhash: Sha256dHash = match store.get(b"L") { + let latest_blockhash: BlockHash = match store.get(b"L") { // latest blockheader persisted in the DB. Some(row) => deserialize(&row).unwrap(), - None => Sha256dHash::default(), + None => BlockHash::default(), }; trace!("latest indexed blockhash: {}", latest_blockhash); let mut map = HeaderMap::new(); @@ -244,7 +244,7 @@ fn read_indexed_headers(store: &dyn ReadStore) -> HeaderList { map.insert(deserialize(&key.hash).unwrap(), header); } let mut headers = vec![]; - let null_hash = Sha256dHash::default(); + let null_hash = BlockHash::default(); let mut blockhash = latest_blockhash; while blockhash != null_hash { let header = map @@ -264,7 +264,7 @@ fn read_indexed_headers(store: &dyn ReadStore) -> HeaderList { assert_eq!( headers .last() - .map(BitcoinHash::bitcoin_hash) + .map(BlockHeader::bitcoin_hash) .unwrap_or(null_hash), latest_blockhash ); @@ -370,7 +370,7 @@ impl Index { .cloned() } - pub fn update(&self, store: &impl WriteStore, waiter: &Waiter) -> Result { + pub fn update(&self, store: &impl WriteStore, waiter: &Waiter) -> Result { let daemon = self.daemon.reconnect()?; let tip = daemon.getbestblockhash()?; let new_headers: Vec = { @@ -380,13 +380,13 @@ impl Index { if let Some(latest_header) = new_headers.last() { info!("{:?} ({} left to index)", latest_header, new_headers.len()); }; - let height_map = HashMap::::from_iter( + let height_map = HashMap::::from_iter( new_headers.iter().map(|h| (*h.hash(), h.height())), ); let chan = SyncChannel::new(1); let sender = chan.sender(); - let blockhashes: Vec = new_headers.iter().map(|h| *h.hash()).collect(); + let blockhashes: Vec = new_headers.iter().map(|h| *h.hash()).collect(); let batch_size = self.batch_size; let fetcher = spawn_thread("fetcher", move || { for chunk in blockhashes.chunks(batch_size) { diff --git a/src/mempool.rs b/src/mempool.rs index 5ac88c6..65f8f27 100644 --- a/src/mempool.rs +++ b/src/mempool.rs @@ -1,5 +1,5 @@ +use bitcoin::hash_types::Txid; use bitcoin::blockdata::transaction::Transaction; -use bitcoin_hashes::sha256d::Hash as Sha256dHash; use hex; use std::collections::{BTreeMap, HashMap, HashSet}; use std::iter::FromIterator; @@ -139,7 +139,7 @@ impl Stats { } pub struct Tracker { - items: HashMap, + items: HashMap, index: MempoolStore, histogram: Vec<(f32, u32)>, stats: Stats, @@ -175,7 +175,7 @@ impl Tracker { } } - pub fn get_txn(&self, txid: &Sha256dHash) -> Option { + pub fn get_txn(&self, txid: &Txid) -> Option { self.items.get(txid).map(|stats| stats.tx.clone()) } @@ -200,7 +200,7 @@ impl Tracker { let timer = self.stats.start_timer("add"); let txids_iter = new_txids.difference(&old_txids); - let entries: Vec<(&Sha256dHash, MempoolEntry)> = txids_iter + let entries: Vec<(&Txid, MempoolEntry)> = txids_iter .filter_map(|txid| { match daemon.getmempoolentry(txid) { Ok(entry) => Some((txid, entry)), @@ -212,7 +212,7 @@ impl Tracker { }) .collect(); if !entries.is_empty() { - let txids: Vec<&Sha256dHash> = entries.iter().map(|(txid, _)| *txid).collect(); + let txids: Vec<&Txid> = entries.iter().map(|(txid, _)| *txid).collect(); let txs = match daemon.gettransactions(&txids) { Ok(txs) => txs, Err(err) => { @@ -241,12 +241,12 @@ impl Tracker { Ok(()) } - fn add(&mut self, txid: &Sha256dHash, tx: Transaction, entry: MempoolEntry) { + fn add(&mut self, txid: &Txid, tx: Transaction, entry: MempoolEntry) { self.index.add(&tx); self.items.insert(*txid, Item { tx, entry }); } - fn remove(&mut self, txid: &Sha256dHash) { + fn remove(&mut self, txid: &Txid) { let stats = self .items .remove(txid) diff --git a/src/notify.rs b/src/notify.rs index 710aea7..e695dfc 100644 --- a/src/notify.rs +++ b/src/notify.rs @@ -4,7 +4,7 @@ use bitcoin::network::constants::Network; use bitcoin::network::message::NetworkMessage; use bitcoin::network::message_blockdata::InvType; use bitcoin::network::socket::Socket; -use bitcoin::util::hash::Sha256dHash; +use bitcoin::hash_types::Txid; use bitcoin::util::Error; use std::sync::mpsc::Sender; @@ -19,7 +19,7 @@ fn connect() -> Result { Ok(sock) } -fn handle(mut sock: Socket, tx: Sender) { +fn handle(mut sock: Socket, tx: Sender) { let mut outgoing = vec![sock.version_message(0).unwrap()]; loop { for msg in outgoing.split_off(0) { @@ -53,7 +53,7 @@ fn handle(mut sock: Socket, tx: Sender) { } } -pub fn run() -> util::Channel { +pub fn run() -> util::Channel { let chan = util::Channel::new(); let tx = chan.sender(); diff --git a/src/query.rs b/src/query.rs index bb6877d..554904e 100644 --- a/src/query.rs +++ b/src/query.rs @@ -1,7 +1,7 @@ use bitcoin::blockdata::transaction::Transaction; use bitcoin::consensus::encode::deserialize; +use bitcoin::hash_types::{Txid, BlockHash, TxMerkleNode}; use bitcoin_hashes::hex::ToHex; -use bitcoin_hashes::sha256d::Hash as Sha256dHash; use bitcoin_hashes::Hash; use crypto::digest::Digest; use crypto::sha2::Sha256; @@ -19,16 +19,16 @@ use crate::store::{ReadStore, Row}; use crate::util::{FullHash, HashPrefix, HeaderEntry}; pub struct FundingOutput { - pub txn_id: Sha256dHash, + pub txn_id: Txid, pub height: u32, pub output_index: usize, pub value: u64, } -type OutPoint = (Sha256dHash, usize); // (txid, output_index) +type OutPoint = (Txid, usize); // (txid, output_index) struct SpendingInput { - txn_id: Sha256dHash, + txn_id: Txid, height: u32, funding_output: OutPoint, value: u64, @@ -62,15 +62,15 @@ impl Status { calc_balance(&self.mempool) } - pub fn history(&self) -> Vec<(i32, Sha256dHash)> { - let mut txns_map = HashMap::::new(); + pub fn history(&self) -> Vec<(i32, Txid)> { + let mut txns_map = HashMap::::new(); for f in self.funding() { txns_map.insert(f.txn_id, f.height as i32); } for s in self.spending() { txns_map.insert(s.txn_id, s.height as i32); } - let mut txns: Vec<(i32, Sha256dHash)> = + let mut txns: Vec<(i32, Txid)> = txns_map.into_iter().map(|item| (item.1, item.0)).collect(); txns.sort_unstable(); txns @@ -116,15 +116,15 @@ struct TxnHeight { height: u32, } -fn merklize(left: Sha256dHash, right: Sha256dHash) -> Sha256dHash { +fn merklize(left: TxMerkleNode, right: TxMerkleNode) -> TxMerkleNode { let data = [&left[..], &right[..]].concat(); - Sha256dHash::hash(&data) + TxMerkleNode::hash(&data) } fn create_merkle_branch_and_root( - mut hashes: Vec, + mut hashes: Vec, mut index: usize, -) -> (Vec, Sha256dHash) { +) -> (Vec, TxMerkleNode) { let mut merkle = vec![]; while hashes.len() > 1 { if hashes.len() % 2 != 0 { @@ -143,7 +143,7 @@ fn create_merkle_branch_and_root( } // TODO: the functions below can be part of ReadStore. -fn txrow_by_txid(store: &dyn ReadStore, txid: &Sha256dHash) -> Option { +fn txrow_by_txid(store: &dyn ReadStore, txid: &Txid) -> Option { let key = TxRow::filter_full(&txid); let value = store.get(&key)?; Some(TxRow::from_row(&Row { key, value })) @@ -167,7 +167,7 @@ fn txids_by_script_hash(store: &dyn ReadStore, script_hash: &[u8]) -> Vec Vec { store @@ -215,7 +215,7 @@ impl Query { let mut txns = vec![]; for txid_prefix in prefixes { for tx_row in txrows_by_prefix(store, txid_prefix) { - let txid: Sha256dHash = deserialize(&tx_row.key.txid).unwrap(); + let txid: Txid = deserialize(&tx_row.key.txid).unwrap(); let txn = self.load_txn(&txid, Some(tx_row.height))?; txns.push(TxnHeight { txn, @@ -345,9 +345,9 @@ impl Query { fn lookup_confirmed_blockhash( &self, - tx_hash: &Sha256dHash, + tx_hash: &Txid, block_height: Option, - ) -> Result> { + ) -> Result> { let blockhash = if self.tracker.read().unwrap().get_txn(&tx_hash).is_some() { None // found in mempool (as unconfirmed transaction) } else { @@ -371,7 +371,7 @@ impl Query { } // Internal API for transaction retrieval - fn load_txn(&self, txid: &Sha256dHash, block_height: Option) -> Result { + fn load_txn(&self, txid: &Txid, block_height: Option) -> Result { let _timer = self.duration.with_label_values(&["load_txn"]).start_timer(); self.tx_cache.get_or_else(&txid, || { let blockhash = self.lookup_confirmed_blockhash(txid, block_height)?; @@ -385,7 +385,7 @@ impl Query { } // Public API for transaction retrieval (for Electrum RPC) - pub fn get_transaction(&self, tx_hash: &Sha256dHash, verbose: bool) -> Result { + pub fn get_transaction(&self, tx_hash: &Txid, verbose: bool) -> Result { let _timer = self .duration .with_label_values(&["get_transaction"]) @@ -415,9 +415,9 @@ impl Query { pub fn get_merkle_proof( &self, - tx_hash: &Sha256dHash, + tx_hash: &Txid, height: usize, - ) -> Result<(Vec, usize)> { + ) -> Result<(Vec, usize)> { let header_entry = self .app .index() @@ -436,7 +436,7 @@ impl Query { &self, height: usize, cp_height: usize, - ) -> Result<(Vec, Sha256dHash)> { + ) -> Result<(Vec, TxMerkleNode)> { if cp_height < height { bail!("cp_height #{} < height #{}", cp_height, height); } @@ -451,7 +451,7 @@ impl Query { } let heights: Vec = (0..=cp_height).collect(); - let header_hashes: Vec = self + let header_hashes: Vec = self .get_headers(&heights) .into_iter() .map(|h| *h.hash()) @@ -465,7 +465,7 @@ impl Query { height: usize, tx_pos: usize, want_merkle: bool, - ) -> Result<(Sha256dHash, Vec)> { + ) -> Result<(Txid, Vec)> { let header_entry = self .app .index() @@ -485,7 +485,7 @@ impl Query { Ok((txid, branch)) } - pub fn broadcast(&self, txn: &Transaction) -> Result { + pub fn broadcast(&self, txn: &Transaction) -> Result { self.app.daemon().broadcast(txn) } diff --git a/src/util.rs b/src/util.rs index bdc9d0a..907a0e5 100644 --- a/src/util.rs +++ b/src/util.rs @@ -1,6 +1,6 @@ -use bitcoin::blockdata::block::BlockHeader; +use bitcoin::hash_types::BlockHash; use bitcoin::util::hash::BitcoinHash; -use bitcoin_hashes::sha256d::Hash as Sha256dHash; +use bitcoin::blockdata::block::BlockHeader; use std::collections::HashMap; use std::convert::TryInto; use std::fmt; @@ -11,7 +11,7 @@ use std::thread; use time; pub type Bytes = Vec; -pub type HeaderMap = HashMap; +pub type HeaderMap = HashMap; // TODO: consolidate serialization/deserialize code for bincode/bitcoin. const HASH_LEN: usize = 32; @@ -33,12 +33,12 @@ pub fn full_hash(hash: &[u8]) -> FullHash { #[derive(Eq, PartialEq, Clone)] pub struct HeaderEntry { height: usize, - hash: Sha256dHash, + hash: BlockHash, header: BlockHeader, } impl HeaderEntry { - pub fn hash(&self) -> &Sha256dHash { + pub fn hash(&self) -> &BlockHash { &self.hash } @@ -66,7 +66,7 @@ impl fmt::Debug for HeaderEntry { } struct HashedHeader { - blockhash: Sha256dHash, + blockhash: BlockHash, header: BlockHeader, } @@ -88,7 +88,7 @@ fn hash_headers(headers: Vec) -> Vec { pub struct HeaderList { headers: Vec, - heights: HashMap, + heights: HashMap, } impl HeaderList { @@ -106,7 +106,7 @@ impl HeaderList { Some(h) => h.header.prev_blockhash, None => return vec![], // hashed_headers is empty }; - let null_hash = Sha256dHash::default(); + let null_hash = BlockHash::default(); let new_height: usize = if prev_blockhash == null_hash { 0 } else { @@ -125,8 +125,8 @@ impl HeaderList { .collect() } - pub fn apply(&mut self, new_headers: Vec, tip: Sha256dHash) { - if tip == Sha256dHash::default() { + pub fn apply(&mut self, new_headers: Vec, tip: BlockHash) { + if tip == BlockHash::default() { assert!(new_headers.is_empty()); self.heights.clear(); self.headers.clear(); @@ -150,7 +150,7 @@ impl HeaderList { let expected_prev_blockhash = if height > 0 { *self.headers[height - 1].hash() } else { - Sha256dHash::default() + BlockHash::default() }; assert_eq!(entry.header().prev_blockhash, expected_prev_blockhash); // First new header's height (may override existing headers) @@ -182,7 +182,7 @@ impl HeaderList { assert!(self.heights.contains_key(&tip)); } - pub fn header_by_blockhash(&self, blockhash: &Sha256dHash) -> Option<&HeaderEntry> { + pub fn header_by_blockhash(&self, blockhash: &BlockHash) -> Option<&HeaderEntry> { let height = self.heights.get(blockhash)?; let header = self.headers.get(*height)?; if *blockhash == *header.hash() { @@ -203,7 +203,7 @@ impl HeaderList { self.headers.last() == other.headers.last() } - pub fn tip(&self) -> Sha256dHash { + pub fn tip(&self) -> BlockHash { self.headers.last().map(|h| *h.hash()).unwrap_or_default() } @@ -285,24 +285,24 @@ mod tests { #[test] fn test_headers() { use bitcoin::blockdata::block::BlockHeader; + use bitcoin::hash_types::{BlockHash, TxMerkleNode}; use bitcoin::util::hash::BitcoinHash; - use bitcoin_hashes::sha256d::Hash as Sha256dHash; use bitcoin_hashes::Hash; use super::HeaderList; // Test an empty header list - let null_hash = Sha256dHash::default(); + let null_hash = BlockHash::default(); let mut header_list = HeaderList::empty(); assert_eq!(header_list.tip(), null_hash); let ordered = header_list.order(vec![]); assert_eq!(ordered.len(), 0); header_list.apply(vec![], null_hash); - let merkle_root = Sha256dHash::hash(&[255]); + let merkle_root = TxMerkleNode::hash(&[255]); let mut headers = vec![BlockHeader { version: 1, - prev_blockhash: Sha256dHash::default(), + prev_blockhash: BlockHash::default(), merkle_root, time: 0, bits: 0, From 0ccdf44181c16af53db514beb16d691003b94351 Mon Sep 17 00:00:00 2001 From: "Dr. Maxim Orlovsky" Date: Sun, 19 Apr 2020 23:57:05 +0200 Subject: [PATCH 2/2] 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. --- src/query.rs | 32 +++++++++++++++++++++++--------- src/rpc.rs | 14 +++++++------- 2 files changed, 30 insertions(+), 16 deletions(-) diff --git a/src/query.rs b/src/query.rs index 554904e..e15bb07 100644 --- a/src/query.rs +++ b/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(left: T, right: T) -> T { let data = [&left[..], &right[..]].concat(); - TxMerkleNode::hash(&data) + ::hash(&data) } -fn create_merkle_branch_and_root( - mut hashes: Vec, +fn create_merkle_branch_and_root( + mut hashes: Vec, mut index: usize, -) -> (Vec, TxMerkleNode) { +) -> (Vec, 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 = 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, TxMerkleNode)> { + ) -> Result<(Vec, 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 = 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![] }; diff --git a/src/rpc.rs b/src/rpc.rs index c38e0bb..dadc856 100644 --- a/src/rpc.rs +++ b/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 { +fn hash_from_value(val: Option<&Value>) -> Result { 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 { - let script_hash = hash_from_value(params.get(0)).chain_err(|| "bad script_hash")?; + let script_hash = hash_from_value::(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 { - let script_hash = hash_from_value(params.get(0)).chain_err(|| "bad script_hash")?; + let script_hash = hash_from_value::(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 { - let script_hash = hash_from_value(params.get(0)).chain_err(|| "bad script_hash")?; + let script_hash = hash_from_value::(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 { - let script_hash = hash_from_value(params.get(0)).chain_err(|| "bad script_hash")?; + let script_hash = hash_from_value::(params.get(0)).chain_err(|| "bad script_hash")?; Ok(unspent_from_status(&self.query.status(&script_hash[..])?)) }