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 optparse import OptionParser
from numbers import Integral
from collections import Counter
from jmclient import (get_network, WALLET_IMPLEMENTATIONS, Storage, podle,
jm_single, BitcoinCoreInterface, JsonRpcError, sync_wallet, WalletError,
VolatileStorage, StoragePasswordError,
@ -291,6 +292,39 @@ class WalletView(WalletViewBase):
return self.serclass(entryseparator.join([header] + [
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):
entries = []
for path in wallet.yield_imported_paths(m):
@ -338,13 +372,41 @@ def wallet_showutxos(wallet, showprivkey):
return json.dumps(unsp, indent=4)
def wallet_display(wallet, gaplimit, showprivkey, displayall=False,
serialized=True, summarized=False):
"""build the walletview object,
then return its serialization directly if serialized,
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 = []
utxos = wallet.get_utxos_by_mixdepth_()
for m in range(wallet.mixdepth + 1):
branchlist = []
for forchange in [0, 1]:
@ -359,11 +421,8 @@ def wallet_display(wallet, gaplimit, showprivkey, displayall=False,
for k in range(unused_index + gaplimit):
path = wallet.get_path(m, forchange, k)
addr = wallet.get_addr_path(path)
balance = 0
for utxodata in wallet.get_utxos_by_mixdepth_()[m].values():
if path == utxodata['path']:
balance += utxodata['value']
used = 'used' if k < unused_index else 'new'
balance, used = get_addr_status(
path, utxos[m], k >= unused_index, forchange)
if showprivkey:
privkey = wallet.get_wif_path(path)
else:
@ -582,23 +641,11 @@ def wallet_fetch_history(wallet, options):
deposit_times = []
tx_number = 0
for tx in txes:
rpctx = jm_single().bc_interface.rpc('gettransaction', [tx['txid']])
txhex = str(rpctx['hex'])
txd = btc.deserialize(txhex)
output_script_values = {binascii.unhexlify(sv['script']): sv['value']
for sv in txd['outs']}
is_coinjoin, cj_amount, cj_n, output_script_values, blocktime, txd =\
get_tx_info(tx['txid'])
our_output_scripts = wallet_script_set.intersection(
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]
output_script_values.keys())
rpc_inputs = []
for ins in txd['ins']:
@ -686,15 +733,12 @@ def wallet_fetch_history(wallet, options):
utxo_count += (len(our_output_scripts) - utxos_consumed)
index = '%4d'%(tx_number)
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 <= 2:
n = cj_batch[0]
if tx_type == 'cj internal':
cj_batch[0] += 1
cj_batch[1] += rpctx['blocktime']
cj_batch[1] += blocktime
cj_batch[2] += amount
cj_batch[3] += delta_balance
cj_batch[4] = balance
@ -712,18 +756,18 @@ def wallet_fetch_history(wallet, options):
min(cj_batch[8]), max(cj_batch[9]), '...')
cj_batch = [0]*8 + [[]]*2 # reset the batch collector
# 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,
mixdepth_src, mixdepth_dst, tx['txid'])
elif options.verbosity >= 5 or \
(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,
mixdepth_src, mixdepth_dst, tx['txid'])
if tx_type != 'cj internal':
deposits.append(delta_balance)
deposit_times.append(rpctx['blocktime'])
deposit_times.append(blocktime)
# we could have a leftover batch!
if options.verbosity <= 2:

2
scripts/joinmarket-qt.py

@ -1093,7 +1093,7 @@ class JMWalletTab(QWidget):
for j in range(len(rows[i][forchange])):
item = QTreeWidgetItem(rows[i][forchange][j])
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')))
seq_item.addChild(item)

Loading…
Cancel
Save