From 1e258f4b3d9869f8636b34d7fd7e20c81741c1f0 Mon Sep 17 00:00:00 2001 From: Roman Zeyde Date: Thu, 12 Jul 2018 18:59:07 +0300 Subject: [PATCH] Allow vectorized fetch for mempool transactions --- src/daemon.rs | 27 +++++++++++++++++++++------ src/mempool.rs | 31 ++++++++++++++++--------------- 2 files changed, 37 insertions(+), 21 deletions(-) diff --git a/src/daemon.rs b/src/daemon.rs index b5f58b1..11618a7 100644 --- a/src/daemon.rs +++ b/src/daemon.rs @@ -46,6 +46,12 @@ fn block_from_value(value: Value) -> Result { Ok(deserialize(&block_bytes).chain_err(|| format!("failed to parse block {}", block_hex))?) } +fn tx_from_value(value: Value) -> Result { + let tx_hex = value.as_str().chain_err(|| "non-string tx")?; + let tx_bytes = hex::decode(tx_hex).chain_err(|| "non-hex tx")?; + Ok(deserialize(&tx_bytes).chain_err(|| format!("failed to parse tx {}", tx_hex))?) +} + fn parse_jsonrpc_reply(reply: &mut Value, method: &str) -> Result { let reply_obj = reply.as_object_mut().chain_err(|| "non-object reply")?; if let Some(err) = reply_obj.get("error") { @@ -337,12 +343,21 @@ impl Daemon { .unwrap() .push(json!(blockhash.be_hex_string())); } - let tx_hex: Value = self.request("getrawtransaction", args)?; - Ok( - deserialize(&hex::decode(tx_hex.as_str().chain_err(|| "non-string tx")?) - .chain_err(|| "non-hex tx")?) - .chain_err(|| format!("failed to parse tx {}", txhash))?, - ) + tx_from_value(self.request("getrawtransaction", args)?) + } + + pub fn gettransactions(&self, txhashes: &[Sha256dHash]) -> Result> { + let params_list: Vec = txhashes + .iter() + .map(|txhash| json!([txhash.be_hex_string(), /*verbose=*/ false])) + .collect(); + + let values = self.requests("getrawtransaction", ¶ms_list)?; + let mut txs = vec![]; + for value in values { + txs.push(tx_from_value(value)?); + } + Ok(txs) } pub fn getmempooltxids(&self) -> Result> { diff --git a/src/mempool.rs b/src/mempool.rs index ac00d7e..ea7fe8f 100644 --- a/src/mempool.rs +++ b/src/mempool.rs @@ -201,22 +201,23 @@ impl Tracker { timer.observe_duration(); let timer = self.stats.start_timer("add"); - for txid in new_txids.difference(&old_txids) { - let entry = match daemon.getmempoolentry(txid) { - Ok(entry) => entry, - Err(err) => { - warn!("no mempool entry {}: {}", txid, err); // e.g. new block or RBF - continue; + let txids_to_add: Vec = new_txids.difference(&old_txids).cloned().collect(); + let entries: Vec<(&Sha256dHash, MempoolEntry)> = txids_to_add + .iter() + .filter_map(|txid| { + match daemon.getmempoolentry(txid) { + Ok(entry) => Some((txid, entry)), + Err(err) => { + warn!("no mempool entry {}: {}", txid, err); // e.g. new block or RBF + None + } } - }; - // The following lookup should find the transaction in mempool. - let tx = match daemon.gettransaction(txid, /*blockhash=*/ None) { - Ok(tx) => tx, - Err(err) => { - warn!("missing tx {}: {}", txid, err); // e.g. new block or RBF - continue; - } - }; + }) + .collect(); + let txs = daemon.gettransactions(&txids_to_add)?; + assert_eq!(entries.len(), txs.len()); + for ((txid, entry), tx) in entries.into_iter().zip(txs.into_iter()) { + assert_eq!(tx.txid(), *txid); self.add(txid, tx, entry); } timer.observe_duration();