Browse Source

implement wallet-tools display[all] extended usage status

master
undeath 7 years ago
parent
commit
596261a723
  1. 100
      jmclient/jmclient/wallet_utils.py
  2. 2
      scripts/joinmarket-qt.py

100
jmclient/jmclient/wallet_utils.py

@ -10,6 +10,7 @@ import binascii
from datetime import datetime from datetime import datetime
from optparse import OptionParser from optparse import OptionParser
from numbers import Integral from numbers import Integral
from collections import Counter
from jmclient import (get_network, WALLET_IMPLEMENTATIONS, Storage, podle, from jmclient import (get_network, WALLET_IMPLEMENTATIONS, Storage, podle,
jm_single, BitcoinCoreInterface, JsonRpcError, sync_wallet, WalletError, jm_single, BitcoinCoreInterface, JsonRpcError, sync_wallet, WalletError,
VolatileStorage, StoragePasswordError, VolatileStorage, StoragePasswordError,
@ -291,6 +292,39 @@ class WalletView(WalletViewBase):
return self.serclass(entryseparator.join([header] + [ return self.serclass(entryseparator.join([header] + [
x.serialize(entryseparator, summarize=False) for x in self.accounts] + [footer])) x.serialize(entryseparator, summarize=False) for x in self.accounts] + [footer]))
def get_tx_info(txid):
"""
Retrieve some basic information about the given transaction.
:param txid: txid as hex-str
:return: tuple
is_coinjoin: bool
cj_amount: int, only useful if is_coinjoin==True
cj_n: int, number of cj participants, only useful if is_coinjoin==True
output_script_values: {script: value} dict including all outputs
blocktime: int, blocktime this tx was mined
txd: deserialized transaction object (hex-encoded data)
"""
rpctx = jm_single().bc_interface.rpc('gettransaction', [txid])
txhex = str(rpctx['hex'])
txd = btc.deserialize(txhex)
output_script_values = {binascii.unhexlify(sv['script']): sv['value']
for sv in txd['outs']}
value_freq_list = sorted(
Counter(output_script_values.values()).most_common(),
key=lambda x: -x[1])
non_cj_freq = (0 if len(value_freq_list) == 1 else
sum(next(islice(zip(*value_freq_list[1:]), 1, None))))
is_coinjoin = (value_freq_list[0][1] > 1 and
value_freq_list[0][1] in
[non_cj_freq, non_cj_freq + 1])
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['blocktime'], txd
def get_imported_privkey_branch(wallet, m, showprivkey): def get_imported_privkey_branch(wallet, m, showprivkey):
entries = [] entries = []
for path in wallet.yield_imported_paths(m): for path in wallet.yield_imported_paths(m):
@ -338,13 +372,41 @@ def wallet_showutxos(wallet, showprivkey):
return json.dumps(unsp, indent=4) return json.dumps(unsp, indent=4)
def wallet_display(wallet, gaplimit, showprivkey, displayall=False, def wallet_display(wallet, gaplimit, showprivkey, displayall=False,
serialized=True, summarized=False): serialized=True, summarized=False):
"""build the walletview object, """build the walletview object,
then return its serialization directly if serialized, then return its serialization directly if serialized,
else return the WalletView object. else return the WalletView object.
""" """
def get_addr_status(addr_path, utxos, is_new, is_internal):
addr_balance = 0
status = []
for utxo, utxodata in iteritems(utxos):
if addr_path != utxodata['path']:
continue
addr_balance += utxodata['value']
is_coinjoin, cj_amount, cj_n = \
get_tx_info(binascii.hexlify(utxo[0]).decode('ascii'))[:3]
if is_coinjoin and utxodata['value'] == cj_amount:
status.append('cj-out')
elif is_coinjoin:
status.append('change-out')
elif is_internal:
status.append('non-cj-change')
else:
status.append('deposit')
out_status = 'new' if is_new else 'used'
if len(status) > 1:
out_status = 'reused'
elif len(status) == 1:
out_status = status[0]
return addr_balance, out_status
acctlist = [] acctlist = []
utxos = wallet.get_utxos_by_mixdepth_()
for m in range(wallet.mixdepth + 1): for m in range(wallet.mixdepth + 1):
branchlist = [] branchlist = []
for forchange in [0, 1]: for forchange in [0, 1]:
@ -359,11 +421,8 @@ def wallet_display(wallet, gaplimit, showprivkey, displayall=False,
for k in range(unused_index + gaplimit): for k in range(unused_index + gaplimit):
path = wallet.get_path(m, forchange, k) path = wallet.get_path(m, forchange, k)
addr = wallet.get_addr_path(path) addr = wallet.get_addr_path(path)
balance = 0 balance, used = get_addr_status(
for utxodata in wallet.get_utxos_by_mixdepth_()[m].values(): path, utxos[m], k >= unused_index, forchange)
if path == utxodata['path']:
balance += utxodata['value']
used = 'used' if k < unused_index else 'new'
if showprivkey: if showprivkey:
privkey = wallet.get_wif_path(path) privkey = wallet.get_wif_path(path)
else: else:
@ -582,23 +641,11 @@ def wallet_fetch_history(wallet, options):
deposit_times = [] deposit_times = []
tx_number = 0 tx_number = 0
for tx in txes: for tx in txes:
rpctx = jm_single().bc_interface.rpc('gettransaction', [tx['txid']]) is_coinjoin, cj_amount, cj_n, output_script_values, blocktime, txd =\
txhex = str(rpctx['hex']) get_tx_info(tx['txid'])
txd = btc.deserialize(txhex)
output_script_values = {binascii.unhexlify(sv['script']): sv['value']
for sv in txd['outs']}
our_output_scripts = wallet_script_set.intersection( our_output_scripts = wallet_script_set.intersection(
output_script_values.keys()) output_script_values.keys())
from collections import Counter
value_freq_list = sorted(Counter(output_script_values.values())
.most_common(), key=lambda x: -x[1])
non_cj_freq = 0 if len(value_freq_list)==1 else sum(list(zip(
*value_freq_list[1:]))[1])
is_coinjoin = (value_freq_list[0][1] > 1 and value_freq_list[0][1] in
[non_cj_freq, non_cj_freq+1])
cj_amount = value_freq_list[0][0]
cj_n = value_freq_list[0][1]
rpc_inputs = [] rpc_inputs = []
for ins in txd['ins']: for ins in txd['ins']:
@ -686,15 +733,12 @@ def wallet_fetch_history(wallet, options):
utxo_count += (len(our_output_scripts) - utxos_consumed) utxo_count += (len(our_output_scripts) - utxos_consumed)
index = '%4d'%(tx_number) index = '%4d'%(tx_number)
tx_number += 1 tx_number += 1
timestamp = datetime.fromtimestamp(rpctx['blocktime']
).strftime("%Y-%m-%d %H:%M")
utxo_count_str = '% 3d' % (utxo_count)
if options.verbosity > 0: if options.verbosity > 0:
if options.verbosity <= 2: if options.verbosity <= 2:
n = cj_batch[0] n = cj_batch[0]
if tx_type == 'cj internal': if tx_type == 'cj internal':
cj_batch[0] += 1 cj_batch[0] += 1
cj_batch[1] += rpctx['blocktime'] cj_batch[1] += blocktime
cj_batch[2] += amount cj_batch[2] += amount
cj_batch[3] += delta_balance cj_batch[3] += delta_balance
cj_batch[4] = balance cj_batch[4] = balance
@ -712,18 +756,18 @@ def wallet_fetch_history(wallet, options):
min(cj_batch[8]), max(cj_batch[9]), '...') min(cj_batch[8]), max(cj_batch[9]), '...')
cj_batch = [0]*8 + [[]]*2 # reset the batch collector cj_batch = [0]*8 + [[]]*2 # reset the batch collector
# print batch terminating row # print batch terminating row
print_row(index, rpctx['blocktime'], tx_type, amount, print_row(index, blocktime, tx_type, amount,
delta_balance, balance, cj_n, fees, utxo_count, delta_balance, balance, cj_n, fees, utxo_count,
mixdepth_src, mixdepth_dst, tx['txid']) mixdepth_src, mixdepth_dst, tx['txid'])
elif options.verbosity >= 5 or \ elif options.verbosity >= 5 or \
(options.verbosity >= 3 and tx_type != 'unknown type'): (options.verbosity >= 3 and tx_type != 'unknown type'):
print_row(index, rpctx['blocktime'], tx_type, amount, print_row(index, blocktime, tx_type, amount,
delta_balance, balance, cj_n, fees, utxo_count, delta_balance, balance, cj_n, fees, utxo_count,
mixdepth_src, mixdepth_dst, tx['txid']) mixdepth_src, mixdepth_dst, tx['txid'])
if tx_type != 'cj internal': if tx_type != 'cj internal':
deposits.append(delta_balance) deposits.append(delta_balance)
deposit_times.append(rpctx['blocktime']) deposit_times.append(blocktime)
# we could have a leftover batch! # we could have a leftover batch!
if options.verbosity <= 2: if options.verbosity <= 2:

2
scripts/joinmarket-qt.py

@ -1093,7 +1093,7 @@ class JMWalletTab(QWidget):
for j in range(len(rows[i][forchange])): for j in range(len(rows[i][forchange])):
item = QTreeWidgetItem(rows[i][forchange][j]) item = QTreeWidgetItem(rows[i][forchange][j])
item.setFont(0, QFont(MONOSPACE_FONT)) item.setFont(0, QFont(MONOSPACE_FONT))
if rows[i][forchange][j][3] == 'used': if rows[i][forchange][j][3] != 'new':
item.setForeground(3, QBrush(QColor('red'))) item.setForeground(3, QBrush(QColor('red')))
seq_item.addChild(item) seq_item.addChild(item)

Loading…
Cancel
Save