Skip to content

Commit

Permalink
Fix #60, fix #48 -- Finally addressed 'Spend Coins' wonkiness
Browse files Browse the repository at this point in the history
There were bugs when selecting coins from the coins tab and doing
'spend' while CashShuffle was running.  The coins list would not get
properly maintained and would default to an empty list, despite the UI
showing coins.

The bugs have been fixed and in addition, the UI now indicates WHICH
coins in the spend-from list are actually being considered by graying
out ineligible coins.

Thanks @sploit and @emergentreasons for bringing this to my attention!
  • Loading branch information
cculianu committed Feb 23, 2019
1 parent c035295 commit 5284cfb
Show file tree
Hide file tree
Showing 3 changed files with 37 additions and 4 deletions.
23 changes: 20 additions & 3 deletions gui/qt/main_window.py
Original file line number Diff line number Diff line change
Expand Up @@ -1452,7 +1452,13 @@ def set_pay_from(self, coins):
self.pay_from = list(coins)
self.redraw_from_list()

def redraw_from_list(self):
def redraw_from_list(self, *, spendable=None):
''' Optional kwarg spendable indicates *which* of the UTXOs in the
self.pay_from list are actually spendable. If this arg is specifid,
coins in the self.pay_from list that aren't also in the 'spendable' list
will be grayed out in the UI, to indicate that they will not be used.
Otherwise all coins will be non-gray (default).
(Added for CashShuffle 02/23/2019) '''
self.from_list.clear()
self.from_label.setHidden(len(self.pay_from) == 0)
self.from_list.setHidden(len(self.pay_from) == 0)
Expand All @@ -1461,9 +1467,17 @@ def format(x):
h = x['prevout_hash']
return '{}...{}:{:d}\t{}'.format(h[0:10], h[-10:],
x['prevout_n'], x['address'])
def grayify(twi):
b = twi.foreground(0)
b.setColor(Qt.gray)
for i in range(twi.columnCount()):
twi.setForeground(i, b)

for item in self.pay_from:
self.from_list.addTopLevelItem(QTreeWidgetItem( [format(item), self.format_amount(item['value']) ]))
twi = QTreeWidgetItem( [format(item), self.format_amount(item['value']) ])
if spendable is not None and item not in spendable:
grayify(twi)
self.from_list.addTopLevelItem(twi)

def get_contact_payto(self, key):
_type, label = self.contacts.get(key)
Expand Down Expand Up @@ -1955,10 +1969,13 @@ def remove_address(self, addr):
def get_coins(self, isInvoice = False):
coins = []
if self.pay_from:
coins = self.pay_from
coins = self.pay_from.copy()
else:
coins = self.wallet.get_spendable_coins(None, self.config, isInvoice)
run_hook("spendable_coin_filter", self, coins) # may modify coins -- used by CashShuffle if in shuffle = ENABLED mode.
if self.pay_from:
# coins may have been filtered, so indicate this in the UI
self.redraw_from_list(spendable=coins)
return coins

def spend_coins(self, coins):
Expand Down
12 changes: 12 additions & 0 deletions plugins/shuffle/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -592,6 +592,18 @@ def get_coin_for_shuffling(scale, coins):
thr.start()
return True

def is_coin_busy_shuffling(self, utxo_name_or_dict):
''' Checks the extant running threads (if any) for a match to coin.
This is a very accurate real-time indication that a coins is busy
shuffling. Used by the spendable_coin_filter in qt.py.'''
if isinstance(utxo_name_or_dict, dict):
name = get_name(utxo_name_or_dict)
else:
name = utxo_name_or_dict
# name must be an str at this point!
with self.wallet.lock, self.wallet.transaction_lock:
return any(thr for thr in self.threads.values() if thr and thr.coin == name)

def is_wallet_ready(self):
return bool( self.wallet and self.wallet.is_up_to_date()
and self.wallet.network and self.wallet.network.is_connected()
Expand Down
6 changes: 5 additions & 1 deletion plugins/shuffle/qt.py
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,10 @@ def doChk():
cache[name] = answer
return answer

def is_coin_busy_shuffling(window, utxo_or_name):
''' Convenience wrapper for BackgroundProcess.is_coin_busy_shuffling '''
bp = getattr(window, 'background_process', None)
return bool(bp and bp.is_coin_busy_shuffling(utxo_or_name))

def get_shuffled_and_unshuffled_coin_totals(wallet, exclude_frozen = False, mature = False, confirmed_only = False):
''' Returns a 3-tuple of tuples of (amount_total, num_utxos) that are 'shuffled', 'unshuffled' and 'unshuffled_but_in_progress', respectively. '''
Expand Down Expand Up @@ -619,7 +623,7 @@ def spendable_coin_filter(self, window, coins):
elif spend_mode == extra.SpendingModeUnshuffled:
# in Cash-Shuffle mode + unshuffled spending we can ONLY spend unshuffled coins!
for coin in coins.copy():
if is_coin_shuffled(window.wallet, coin):
if is_coin_shuffled(window.wallet, coin) or is_coin_busy_shuffling(window, coin):
coins.remove(coin)


Expand Down

0 comments on commit 5284cfb

Please sign in to comment.