From 4c9ba86188ddbd60a69344bf82c30a16f766c8bd Mon Sep 17 00:00:00 2001 From: "Empty2k12 (Gero G.)" <11deutron11@gmail.com> Date: Wed, 30 Nov 2016 21:16:25 +0100 Subject: [PATCH 1/4] Show confirmations for address in wallet-tool --- wallet-tool.py | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/wallet-tool.py b/wallet-tool.py index af8c1ffa..904435da 100644 --- a/wallet-tool.py +++ b/wallet-tool.py @@ -6,6 +6,7 @@ import os import sys import sqlite3 +import json from optparse import OptionParser from joinmarket import load_program_config, get_network, Wallet, encryptData, \ @@ -140,6 +141,15 @@ def cus_print(s): if method != 'summary': print(s) + def json_obj_by_value(haystack, needle, value): + for item in haystack: + if item[needle] == value: + my_item = item + break + else: + my_item = None + return my_item + total_balance = 0 for m in range(wallet.max_mix_depth): cus_print('mixing depth %d m/0/%d/' % (m, m)) @@ -152,6 +162,7 @@ def cus_print(s): cus_print(' ' + ('external' if forchange == 0 else 'internal') + ' addresses m/0/%d/%d' % (m, forchange) + ' ' + xpub_key) + addressinfo = jm_single().bc_interface.rpc('listreceivedbyaddress', [0, False, True]) for k in range(wallet.index[m][forchange] + options.gaplimit): addr = wallet.get_addr(m, forchange, k) balance = 0.0 @@ -160,6 +171,11 @@ def cus_print(s): balance += addrvalue['value'] balance_depth += balance used = ('used' if k < wallet.index[m][forchange] else ' new') + addr_data = json_obj_by_value(addressinfo, 'address', addr) + if addr_data: + confs = '{0} confs'.format(addr_data['confirmations']) + else: + confs = '' #Leave empty since we don't want this showing for unused addresses if options.showprivkey: privkey = btc.wif_compressed_privkey( wallet.get_key(m, forchange, k), get_p2pk_vbyte()) @@ -167,9 +183,9 @@ def cus_print(s): privkey = '' if (method == 'displayall' or balance > 0 or (used == ' new' and forchange == 0)): - cus_print(' m/0/%d/%d/%03d %-35s%s %.8f btc %s' % + cus_print(' m/0/%d/%d/%03d %-35s%s %.8f btc %s %s' % (m, forchange, k, addr, used, balance / 1e8, - privkey)) + confs, privkey)) if m in wallet.imported_privkeys: cus_print(' import addresses') for privkey in wallet.imported_privkeys[m]: @@ -469,8 +485,8 @@ def skip_n1_btc(v): )['time'] except JsonRpcError: now = jm_single().bc_interface.rpc('getblock', [bestblockhash])['time'] - print(' %s best block is %s' % (datetime.datetime.fromtimestamp(now) - .strftime("%Y-%m-%d %H:%M"), bestblockhash)) + print(' %s best block is %s' % (datetime.datetime.fromtimestamp(now).strftime("%Y-%m-%d %H:%M"), bestblockhash)) + print('total profit = ' + str(float(balance - sum(deposits)) / float(100000000)) + ' BTC') try: #https://gist.github.com/chris-belcher/647da261ce718fc8ca10 import numpy as np From 05cc404a7df03e0c3c4426ba04a6681022c6769b Mon Sep 17 00:00:00 2001 From: "Empty2k12 (Gero G.)" <11deutron11@gmail.com> Date: Tue, 6 Dec 2016 20:21:24 +0100 Subject: [PATCH 2/4] Make wallet-tool show confs and UTXO for used addresses (Respects blockchaininterface) --- joinmarket/blockchaininterface.py | 24 +++++++-- wallet-tool.py | 82 ++++++++++++++++++++++++------- 2 files changed, 83 insertions(+), 23 deletions(-) diff --git a/joinmarket/blockchaininterface.py b/joinmarket/blockchaininterface.py index 96fa1170..2b8fdd1a 100644 --- a/joinmarket/blockchaininterface.py +++ b/joinmarket/blockchaininterface.py @@ -135,6 +135,10 @@ def estimate_fee_per_kb(self, N): required for inclusion in the next N blocks. ''' + @abc.abstractmethod + def get_block_height(self): + """Returns the amount of blocks""" + class BlockrInterface(BlockchainInterface): BLOCKR_MAX_ADDR_REQ_COUNT = 20 @@ -196,6 +200,9 @@ def sync_unspent(self, wallet): log.info('no tx used') return i = 0 + + blockr_base = 'https://' + self.blockr_domain + '.blockr.io/api/v1/' + while i < len(addrs): inc = min(len(addrs) - i, self.BLOCKR_MAX_ADDR_REQ_COUNT) req = addrs[i:i + inc] @@ -205,8 +212,7 @@ def sync_unspent(self, wallet): # unspent() doesnt tell you which address, you get a bunch of utxos # but dont know which privkey to sign with - blockr_url = 'https://' + self.blockr_domain + \ - '.blockr.io/api/v1/address/unspent/' + blockr_url = blockr_base + 'address/unspent/' data = btc.make_request_blockr(blockr_url + ','.join(req))['data'] if 'unspent' in data: data = [data] @@ -214,7 +220,8 @@ def sync_unspent(self, wallet): for u in dat['unspent']: wallet.unspent[u['tx'] + ':' + str(u['n'])] = { 'address': dat['address'], - 'value': int(u['amount'].replace('.', '')) + 'value': int(u['amount'].replace('.', '')), + 'blockheight': self.get_block_height() - dat['confirmations'] } for u in wallet.spent_utxos: wallet.unspent.pop(u, None) @@ -412,6 +419,11 @@ def estimate_fee_per_kb(self, N): return fee_per_kb + def get_block_height(self): + blockr_base = 'https://' + self.blockr_domain + '.blockr.io/api/v1/' + blockr_url = blockr_base + "block/info/last" + return btc.make_request_blockr(blockr_url)['data']['nb'] + def bitcoincore_timeout_callback(uc_called, txout_set, txnotify_fun_list, timeoutfun): @@ -820,7 +832,8 @@ def sync_unspent(self, wallet): continue wallet.unspent[u['txid'] + ':' + str(u['vout'])] = { 'address': u['address'], - 'value': int(Decimal(str(u['amount'])) * Decimal('1e8')) + 'value': int(Decimal(str(u['amount'])) * Decimal('1e8')), + 'blockheight': self.get_block_height() - u['confirmations'] } et = time.time() log.debug('bitcoind sync_unspent took ' + str((et - st)) + 'sec') @@ -892,6 +905,9 @@ def estimate_fee_per_kb(self, N): else: return estimate + def get_block_height(self): + return self.rpc('getblockcount', []) + # class for regtest chain access # running on local daemon. Only diff --git a/wallet-tool.py b/wallet-tool.py index 904435da..37e4f010 100644 --- a/wallet-tool.py +++ b/wallet-tool.py @@ -19,6 +19,7 @@ 'Does useful little tasks involving your bip32 wallet. The ' 'method is one of the following: (display) Shows addresses and ' 'balances. (displayall) Shows ALL addresses and balances. ' + '(displayold) Shows the wallet with addresses instead of UTXOs' '(summary) Shows a summary of mixing depth balances. (generate) ' 'Generates a new wallet. (recover) Recovers a wallet from the 12 ' 'word recovery seed. (showutxos) Shows all utxos in the wallet, ' @@ -87,7 +88,7 @@ options.maxmixdepth = 5 noseed_methods = ['generate', 'recover', 'listwallets'] -methods = ['display', 'displayall', 'summary', 'showseed', 'importprivkey', +methods = ['display', 'displayall', 'summary', 'displayold', 'showseed', 'importprivkey', 'history', 'showutxos'] methods.extend(noseed_methods) noscan_methods = ['showseed', 'importprivkey', 'dumpprivkey'] @@ -135,20 +136,70 @@ print(json.dumps(unsp, indent=4)) sys.exit(0) -if method == 'display' or method == 'displayall' or method == 'summary': +elif method == 'display' or method == 'displayall' or method == 'summary': def cus_print(s): if method != 'summary': print(s) - def json_obj_by_value(haystack, needle, value): - for item in haystack: - if item[needle] == value: - my_item = item - break - else: - my_item = None - return my_item + total_balance = 0 + for m in range(wallet.max_mix_depth): + cus_print('mixing depth %d m/0/%d/' % (m, m)) + balance_depth = 0 + for forchange in [0, 1]: + if forchange == 0: + xpub_key = btc.bip32_privtopub(wallet.keys[m][forchange]) + else: + xpub_key = '' + cus_print(' ' + ('external' if forchange == 0 else 'internal') + + ' addresses m/0/%d/%d' % (m, forchange) + ' ' + xpub_key) + + for k in range(wallet.index[m][forchange] + options.gaplimit): + addr = wallet.get_addr(m, forchange, k) + confs = '' + balance = 0.0 + for utxo, addrvalue in wallet.unspent.iteritems(): + if addr == addrvalue['address']: + balance += addrvalue['value'] + addr = utxo + confs = '{0} confs'.format(jm_single().bc_interface.get_block_height() - addrvalue['blockheight']) + balance_depth += balance + used = (' used' if k < wallet.index[m][forchange] else 'new') + if options.showprivkey: + privkey = btc.wif_compressed_privkey( + wallet.get_key(m, forchange, k), get_p2pk_vbyte()) + else: + privkey = '' + if (method == 'displayall' or balance > 0 or + (used == 'new' and forchange == 0)): + cus_print(' m/0/%d/%d/%03d %-35s%s %.8f btc %s %s' % + (m, forchange, k, addr, used, balance / 1e8, confs, privkey)) + if m in wallet.imported_privkeys: + cus_print(' import addresses') + for privkey in wallet.imported_privkeys[m]: + addr = btc.privtoaddr(privkey, magicbyte=get_p2pk_vbyte()) + balance = 0.0 + for addrvalue in wallet.unspent.values(): + if addr == addrvalue['address']: + balance += addrvalue['value'] + used = (' used' if balance > 0.0 else 'empty') + balance_depth += balance + if options.showprivkey: + wip_privkey = btc.wif_compressed_privkey( + privkey, get_p2pk_vbyte()) + else: + wip_privkey = '' + cus_print(' ' * 13 + '%-35s%s %.8f btc %s' % ( + addr, used, balance / 1e8, wip_privkey)) + total_balance += balance_depth + print('for mixdepth=%d balance=%.8fbtc' % (m, balance_depth / 1e8)) + print('total balance = %.8fbtc' % (total_balance / 1e8)) + +if method == 'displayold': + + def cus_print(s): + if method != 'summary': + print(s) total_balance = 0 for m in range(wallet.max_mix_depth): @@ -162,7 +213,6 @@ def json_obj_by_value(haystack, needle, value): cus_print(' ' + ('external' if forchange == 0 else 'internal') + ' addresses m/0/%d/%d' % (m, forchange) + ' ' + xpub_key) - addressinfo = jm_single().bc_interface.rpc('listreceivedbyaddress', [0, False, True]) for k in range(wallet.index[m][forchange] + options.gaplimit): addr = wallet.get_addr(m, forchange, k) balance = 0.0 @@ -171,11 +221,6 @@ def json_obj_by_value(haystack, needle, value): balance += addrvalue['value'] balance_depth += balance used = ('used' if k < wallet.index[m][forchange] else ' new') - addr_data = json_obj_by_value(addressinfo, 'address', addr) - if addr_data: - confs = '{0} confs'.format(addr_data['confirmations']) - else: - confs = '' #Leave empty since we don't want this showing for unused addresses if options.showprivkey: privkey = btc.wif_compressed_privkey( wallet.get_key(m, forchange, k), get_p2pk_vbyte()) @@ -183,9 +228,8 @@ def json_obj_by_value(haystack, needle, value): privkey = '' if (method == 'displayall' or balance > 0 or (used == ' new' and forchange == 0)): - cus_print(' m/0/%d/%d/%03d %-35s%s %.8f btc %s %s' % - (m, forchange, k, addr, used, balance / 1e8, - confs, privkey)) + cus_print(' m/0/%d/%d/%03d %-35s%s %.8f btc %s' % + (m, forchange, k, addr, used, balance / 1e8, privkey)) if m in wallet.imported_privkeys: cus_print(' import addresses') for privkey in wallet.imported_privkeys[m]: From a4e6cf3087f627e08110465835db9d44682c1004 Mon Sep 17 00:00:00 2001 From: "Empty2k12 (Gero G.)" <11deutron11@gmail.com> Date: Tue, 6 Dec 2016 21:29:08 +0100 Subject: [PATCH 3/4] Rename block height to block count in some cases --- joinmarket/blockchaininterface.py | 10 +++++----- wallet-tool.py | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/joinmarket/blockchaininterface.py b/joinmarket/blockchaininterface.py index 2b8fdd1a..277c36d7 100644 --- a/joinmarket/blockchaininterface.py +++ b/joinmarket/blockchaininterface.py @@ -136,7 +136,7 @@ def estimate_fee_per_kb(self, N): ''' @abc.abstractmethod - def get_block_height(self): + def get_block_count(self): """Returns the amount of blocks""" @@ -221,7 +221,7 @@ def sync_unspent(self, wallet): wallet.unspent[u['tx'] + ':' + str(u['n'])] = { 'address': dat['address'], 'value': int(u['amount'].replace('.', '')), - 'blockheight': self.get_block_height() - dat['confirmations'] + 'blockheight': self.get_block_count() - dat['confirmations'] } for u in wallet.spent_utxos: wallet.unspent.pop(u, None) @@ -419,7 +419,7 @@ def estimate_fee_per_kb(self, N): return fee_per_kb - def get_block_height(self): + def get_block_count(self): blockr_base = 'https://' + self.blockr_domain + '.blockr.io/api/v1/' blockr_url = blockr_base + "block/info/last" return btc.make_request_blockr(blockr_url)['data']['nb'] @@ -833,7 +833,7 @@ def sync_unspent(self, wallet): wallet.unspent[u['txid'] + ':' + str(u['vout'])] = { 'address': u['address'], 'value': int(Decimal(str(u['amount'])) * Decimal('1e8')), - 'blockheight': self.get_block_height() - u['confirmations'] + 'blockheight': self.get_block_count() - u['confirmations'] } et = time.time() log.debug('bitcoind sync_unspent took ' + str((et - st)) + 'sec') @@ -905,7 +905,7 @@ def estimate_fee_per_kb(self, N): else: return estimate - def get_block_height(self): + def get_block_count(self): return self.rpc('getblockcount', []) diff --git a/wallet-tool.py b/wallet-tool.py index 37e4f010..bcac300d 100644 --- a/wallet-tool.py +++ b/wallet-tool.py @@ -162,7 +162,7 @@ def cus_print(s): if addr == addrvalue['address']: balance += addrvalue['value'] addr = utxo - confs = '{0} confs'.format(jm_single().bc_interface.get_block_height() - addrvalue['blockheight']) + confs = '{0} confs'.format(jm_single().bc_interface.get_block_count() - addrvalue['blockheight']) balance_depth += balance used = (' used' if k < wallet.index[m][forchange] else 'new') if options.showprivkey: From db1dc28d10f4ad64696dc9e284ce24a528b547d7 Mon Sep 17 00:00:00 2001 From: "Empty2k12 (Gero G.)" <11deutron11@gmail.com> Date: Tue, 6 Dec 2016 21:44:00 +0100 Subject: [PATCH 4/4] Fix wrong (el)if --- wallet-tool.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wallet-tool.py b/wallet-tool.py index bcac300d..8761c0bc 100644 --- a/wallet-tool.py +++ b/wallet-tool.py @@ -195,7 +195,7 @@ def cus_print(s): print('for mixdepth=%d balance=%.8fbtc' % (m, balance_depth / 1e8)) print('total balance = %.8fbtc' % (total_balance / 1e8)) -if method == 'displayold': +elif method == 'displayold': def cus_print(s): if method != 'summary':