From b52bc06acfead65c2b88ee4f64af44bc223656e8 Mon Sep 17 00:00:00 2001 From: chris-belcher Date: Thu, 6 Sep 2018 18:03:17 +0100 Subject: [PATCH] Switch over to using labels instead of accounts Bitcoin Core 0.17 deprecates the accounts feature and replaces it with labels. The RPC functions using accounts still work for use with older version of Core. --- jmclient/jmclient/blockchaininterface.py | 31 +++++++++++++++--------- jmclient/jmclient/wallet_utils.py | 29 +++++++++++----------- scripts/cli_options.py | 2 +- 3 files changed, 36 insertions(+), 26 deletions(-) diff --git a/jmclient/jmclient/blockchaininterface.py b/jmclient/jmclient/blockchaininterface.py index b0a1285..e3232db 100644 --- a/jmclient/jmclient/blockchaininterface.py +++ b/jmclient/jmclient/blockchaininterface.py @@ -57,6 +57,12 @@ class BlockchainInterface(object): def sync_unspent(self, wallet): """Finds the unspent transaction outputs belonging to this wallet""" + def is_address_imported(self, addr): + try: + return self.rpc('getaccount', [addr]) != '' + except JsonRpcError: + return len(self.rpc('getaddressinfo', [addr])['labels']) > 0 + def add_tx_notify(self, txd, unconfirmfun, confirmfun, notifyaddr, wallet_name=None, timeoutfun=None, spentfun=None, txid_flag=True, n=0, c=1, vb=None): @@ -83,7 +89,7 @@ class BlockchainInterface(object): for outs in txd['outs']: addr = btc.script_to_address(outs['script'], vb) try: - if self.rpc('getaccount', [addr]) != '': + if self.is_address_imported(addr): one_addr_imported = True break except JsonRpcError as e: @@ -350,7 +356,7 @@ class BitcoinCoreInterface(BlockchainInterface): Do NOT use for in-run imports, use rpc('importaddress',..) instead. """ log.debug('importing ' + str(len(addr_list)) + - ' addresses into account ' + wallet_name) + ' addresses with label ' + wallet_name) for addr in addr_list: try: self.rpc('importaddress', [addr, wallet_name, False]) @@ -492,7 +498,15 @@ class BitcoinCoreInterface(BlockchainInterface): wallet_name = self.get_wallet_name(wallet) addresses, saved_indices = self._collect_addresses_init(wallet) - imported_addresses = set(self.rpc('getaddressesbyaccount', [wallet_name])) + try: + imported_addresses = set(self.rpc('getaddressesbyaccount', + [wallet_name])) + except JsonRpcError: + if wallet_name in self.rpc('listlabels', []): + imported_addresses = set(self.rpc('getaddressesbylabel', + [wallet_name]).keys()) + else: + imported_addresses = set() if not addresses.issubset(imported_addresses): self.add_watchonly_addresses(addresses - imported_addresses, @@ -595,7 +609,7 @@ class BitcoinCoreInterface(BlockchainInterface): while True: new = self.rpc( 'listtransactions', - [wallet_name, batch_size, iteration * batch_size, True]) + ["*", batch_size, iteration * batch_size, True]) for tx in new: yield tx if len(new) < batch_size: @@ -621,10 +635,6 @@ class BitcoinCoreInterface(BlockchainInterface): unspent_list = self.rpc('listunspent', listunspent_args) for u in unspent_list: - if 'account' not in u: - continue - if u['account'] != wallet_name: - continue if not wallet.is_known_addr(u['address']): continue self._add_unspent_utxo(wallet, u) @@ -660,15 +670,14 @@ class BitcoinCoreInterface(BlockchainInterface): def outputs_watcher(self, wallet_name, notifyaddr, tx_output_set, unconfirmfun, confirmfun, timeoutfun): - """Given a key for the watcher loop (notifyaddr), a wallet name (account), + """Given a key for the watcher loop (notifyaddr), a wallet name (label), a set of outputs, and unconfirm, confirm and timeout callbacks, check to see if a transaction matching that output set has appeared in the wallet. Call the callbacks and update the watcher loop state. End the loop when the confirmation has been seen (no spent monitoring here). """ wl = self.tx_watcher_loops[notifyaddr] - account_name = wallet_name if wallet_name else "*" - txlist = self.rpc("listtransactions", [wallet_name, 100, 0, True]) + txlist = self.rpc("listtransactions", ["*", 100, 0, True]) for tx in txlist[::-1]: #changed syntax in 0.14.0; allow both syntaxes try: diff --git a/jmclient/jmclient/wallet_utils.py b/jmclient/jmclient/wallet_utils.py index 68ae484..837cfac 100644 --- a/jmclient/jmclient/wallet_utils.py +++ b/jmclient/jmclient/wallet_utils.py @@ -520,18 +520,17 @@ def wallet_fetch_history(wallet, options): "blockhash TEXT, blocktime INTEGER);") jm_single().debug_silence[0] = True wallet_name = jm_single().bc_interface.get_wallet_name(wallet) - for wn in [wallet_name, ""]: - buf = range(1000) - t = 0 - while len(buf) == 1000: - buf = jm_single().bc_interface.rpc('listtransactions', [wn, - 1000, t, True]) - t += len(buf) - tx_data = ((tx['txid'], tx['blockhash'], tx['blocktime']) for tx - in buf if 'txid' in tx and 'blockhash' in tx and 'blocktime' - in tx) - tx_db.executemany('INSERT INTO transactions VALUES(?, ?, ?);', - tx_data) + buf = range(1000) + t = 0 + while len(buf) == 1000: + buf = jm_single().bc_interface.rpc('listtransactions', ["*", + 1000, t, True]) + t += len(buf) + tx_data = ((tx['txid'], tx['blockhash'], tx['blocktime']) for tx + in buf if 'txid' in tx and 'blockhash' in tx and 'blocktime' + in tx) + tx_db.executemany('INSERT INTO transactions VALUES(?, ?, ?);', + tx_data) txes = tx_db.execute( 'SELECT DISTINCT txid, blockhash, blocktime ' @@ -572,7 +571,8 @@ def wallet_fetch_history(wallet, options): utxo_count = 0 deposits = [] deposit_times = [] - for i, tx in enumerate(txes): + tx_number = 0 + for tx in txes: rpctx = jm_single().bc_interface.rpc('gettransaction', [tx['txid']]) txhex = str(rpctx['hex']) txd = btc.deserialize(txhex) @@ -675,7 +675,8 @@ def wallet_fetch_history(wallet, options): + ' in, ' + str(len(our_output_scripts)) + ' out') balance += delta_balance utxo_count += (len(our_output_scripts) - utxos_consumed) - index = '% 4d'%(i) + index = '% 4d'%(tx_number) + tx_number += 1 timestamp = datetime.fromtimestamp(rpctx['blocktime'] ).strftime("%Y-%m-%d %H:%M") utxo_count_str = '% 3d' % (utxo_count) diff --git a/scripts/cli_options.py b/scripts/cli_options.py index fa9e0b0..a19d099 100644 --- a/scripts/cli_options.py +++ b/scripts/cli_options.py @@ -185,7 +185,7 @@ def get_tumbler_parser(): def get_sendpayment_parser(): parser = OptionParser( usage= - 'usage: %prog [options] [wallet file / fromaccount] [amount] [destaddr]', + 'usage: %prog [options] [wallet file] [amount] [destaddr]', description='Sends a single payment from a given mixing depth of your ' + 'wallet to an given address using coinjoin and then switches off. Also sends from bitcoinqt. '