From 84914319cc5b779700ffe97754df837efd031e60 Mon Sep 17 00:00:00 2001 From: Adam Gibson Date: Fri, 29 Dec 2023 12:46:07 -0600 Subject: [PATCH] cache deserialized form of txs in history method Prior to this commit, while the result of the gettransaction rpc call was being cached so as to not have to repeat these rpc calls, the deserialized form of the transaction created by a call to CMutableTransaction.deserialize, was not, and since this call is rather expensive, the history method was running more slowly than needed. After this commit, we cache the deserialized form also, resulting in a speedup to the wallet_utils.wallet_fetch_history method. --- src/jmclient/wallet_utils.py | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/src/jmclient/wallet_utils.py b/src/jmclient/wallet_utils.py index 43210e1a8..686ab16e1 100644 --- a/src/jmclient/wallet_utils.py +++ b/src/jmclient/wallet_utils.py @@ -9,6 +9,7 @@ from numbers import Integral from collections import Counter, defaultdict from itertools import islice, chain +from typing import Optional, Tuple from jmclient import (get_network, WALLET_IMPLEMENTATIONS, Storage, podle, jm_single, WalletError, BaseWallet, VolatileStorage, StoragePasswordError, is_segwit_mode, SegwitLegacyWallet, LegacyWallet, @@ -364,7 +365,8 @@ def serialize_json(self, summarize=False): json_serialized.update(self.get_fmt_balance_json()) return json_serialized -def get_tx_info(txid, tx_cache=None): +def get_tx_info(txid: str, tx_cache: Optional[dict] = None) -> Tuple[ + bool, int, int, dict, int, btc.CTransaction]: """ Retrieve some basic information about the given transaction. @@ -379,14 +381,14 @@ def get_tx_info(txid, tx_cache=None): txd: deserialized transaction object (hex-encoded data) """ if tx_cache is not None and txid in tx_cache: - rpctx = tx_cache[txid] + rpctx, rpctx_deser = tx_cache[txid] else: rpctx = jm_single().bc_interface.get_transaction(txid) + txhex = str(rpctx['hex']) + rpctx_deser = btc.CMutableTransaction.deserialize(hextobin(txhex)) if tx_cache is not None: - tx_cache[txid] = rpctx - txhex = str(rpctx['hex']) - tx = btc.CMutableTransaction.deserialize(hextobin(txhex)) - output_script_values = {x.scriptPubKey: x.nValue for x in tx.vout} + tx_cache[txid] = (rpctx, rpctx_deser) + output_script_values = {x.scriptPubKey: x.nValue for x in rpctx_deser.vout} value_freq_list = sorted( Counter(output_script_values.values()).most_common(), key=lambda x: -x[1]) @@ -398,7 +400,7 @@ def get_tx_info(txid, tx_cache=None): cj_amount = value_freq_list[0][0] cj_n = value_freq_list[0][1] return is_coinjoin, cj_amount, cj_n, output_script_values,\ - rpctx.get('blocktime', 0), tx + rpctx.get('blocktime', 0), rpctx_deser def get_imported_privkey_branch(wallet_service, m, showprivkey): @@ -846,7 +848,6 @@ def wallet_fetch_history(wallet, options): 'blocktme' not in tx) tx_db.executemany('INSERT INTO transactions VALUES(?, ?, ?, ?);', uc_tx_data) - txes = tx_db.execute( 'SELECT DISTINCT txid, blockhash, blocktime ' 'FROM transactions ' @@ -903,22 +904,23 @@ def print_row(index, time, tx_type, amount, delta, balance, cj_n, our_output_scripts = wallet_script_set.intersection( output_script_values.keys()) - rpc_inputs = [] for ins in txd.vin: if ins.prevout.hash[::-1] in tx_cache: - wallet_tx = tx_cache[ins.prevout.hash[::-1]] + wallet_tx, wallet_tx_deser = tx_cache[ins.prevout.hash[::-1]] else: wallet_tx = jm_single().bc_interface.get_transaction( ins.prevout.hash[::-1]) - tx_cache[ins.prevout.hash[::-1]] = wallet_tx + if wallet_tx: + wallet_tx_deser = btc.CMutableTransaction.deserialize( + hextobin(wallet_tx['hex'])) + tx_cache[ins.prevout.hash[::-1]] = (wallet_tx, + wallet_tx_deser) if wallet_tx is None: continue - inp = btc.CMutableTransaction.deserialize(hextobin( - wallet_tx['hex'])).vout[ins.prevout.n] + inp = wallet_tx_deser.vout[ins.prevout.n] input_dict = {"script": inp.scriptPubKey, "value": inp.nValue} rpc_inputs.append(input_dict) - rpc_input_scripts = set(ind['script'] for ind in rpc_inputs) our_input_scripts = wallet_script_set.intersection(rpc_input_scripts) our_input_values = [