Skip to content
This repository has been archived by the owner on May 13, 2022. It is now read-only.

Show confirmations for addresses in wallet-tool and show UTXOs instead of individual addresses (Implements #676 and #259) #677

Open
wants to merge 4 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 20 additions & 4 deletions joinmarket/blockchaininterface.py
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,10 @@ def estimate_fee_per_kb(self, N):
required for inclusion in the next N blocks.
'''

@abc.abstractmethod
def get_block_count(self):
"""Returns the amount of blocks"""


class BlockrInterface(BlockchainInterface):
BLOCKR_MAX_ADDR_REQ_COUNT = 20
Expand Down Expand Up @@ -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]
Expand All @@ -205,16 +212,16 @@ 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]
for dat in data:
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_count() - dat['confirmations']
}
for u in wallet.spent_utxos:
wallet.unspent.pop(u, None)
Expand Down Expand Up @@ -412,6 +419,11 @@ def estimate_fee_per_kb(self, N):

return fee_per_kb

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']


def bitcoincore_timeout_callback(uc_called, txout_set, txnotify_fun_list,
timeoutfun):
Expand Down Expand Up @@ -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_count() - u['confirmations']
}
et = time.time()
log.debug('bitcoind sync_unspent took ' + str((et - st)) + 'sec')
Expand Down Expand Up @@ -892,6 +905,9 @@ def estimate_fee_per_kb(self, N):
else:
return estimate

def get_block_count(self):
return self.rpc('getblockcount', [])


# class for regtest chain access
# running on local daemon. Only
Expand Down
72 changes: 66 additions & 6 deletions wallet-tool.py
Original file line number Diff line number Diff line change
Expand Up @@ -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, \
Expand All @@ -18,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, '
Expand Down Expand Up @@ -86,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']
Expand Down Expand Up @@ -134,7 +136,66 @@
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)

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_count() - 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))

elif method == 'displayold':

def cus_print(s):
if method != 'summary':
Expand Down Expand Up @@ -168,8 +229,7 @@ def cus_print(s):
if (method == 'displayall' or balance > 0 or
(used == ' new' and forchange == 0)):
cus_print(' m/0/%d/%d/%03d %-35s%s %.8f btc %s' %
(m, forchange, k, addr, used, balance / 1e8,
privkey))
(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]:
Expand Down Expand Up @@ -469,8 +529,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
Expand Down