electrum

Electrum Bitcoin wallet
git clone https://git.parazyd.org/electrum
Log | Files | Refs | Submodules

commit a6ea9a0c71ccb30913ef60b39616326d50965d3a
parent 90dee439985c119028f38e7f8c1aa7ced6f244af
Author: Neil Booth <kyuupichan@gmail.com>
Date:   Sat, 28 Nov 2015 22:08:00 +0900

Simplify interface to make_tx in coin chooser

Makes the coin chooser code simpler and easier to understand.

Diffstat:
Mlib/coinchooser.py | 47+++++++++++++++++++++--------------------------
Mlib/wallet.py | 15++++++++++++---
2 files changed, 33 insertions(+), 29 deletions(-)

diff --git a/lib/coinchooser.py b/lib/coinchooser.py @@ -27,21 +27,17 @@ class CoinChooser(PrintError): def __init__(self, wallet): self.wallet = wallet - def fee(self, tx, fixed_fee, fee_per_kb): - if fixed_fee is not None: - return fixed_fee - return tx.estimated_fee(fee_per_kb) - - def dust_threshold(self): - return 182 * 3 * MIN_RELAY_TX_FEE/1000 - - def make_tx(self, coins, outputs, change_addrs, fixed_fee, fee_per_kb): - '''Select unspent coins to spend to pay outputs.''' + def make_tx(self, coins, outputs, change_addrs, fee_estimator, + dust_threshold): + '''Select unspent coins to spend to pay outputs. If the change is + greater than dust_threshold (after adding the change output to + the transaction) it is kept, otherwise none is sent and it is + added to the transaction fee.''' amount = sum(map(lambda x: x[2], outputs)) total = 0 inputs = [] tx = Transaction.from_io(inputs, outputs) - fee = self.fee(tx, fixed_fee, fee_per_kb) + fee = fee_estimator(tx) # add inputs, sorted by age for item in coins: v = item.get('value') @@ -51,7 +47,7 @@ class CoinChooser(PrintError): # no need to estimate fee until we have reached desired amount if total < amount + fee: continue - fee = self.fee(tx, fixed_fee, fee_per_kb) + fee = fee_estimator(tx) if total >= amount + fee: break else: @@ -69,13 +65,13 @@ class CoinChooser(PrintError): else: break if removed: - fee = self.fee(tx, fixed_fee, fee_per_kb) + fee = fee_estimator(tx) for item in sorted(tx.inputs, key=itemgetter('value')): v = item.get('value') if total - v >= amount + fee: tx.inputs.remove(item) total -= v - fee = self.fee(tx, fixed_fee, fee_per_kb) + fee = fee_estimator(tx) continue break self.print_error("using %d inputs" % len(tx.inputs)) @@ -83,22 +79,21 @@ class CoinChooser(PrintError): # if change is above dust threshold, add a change output. change_addr = change_addrs[0] change_amount = total - (amount + fee) - if fixed_fee is not None and change_amount > 0: - tx.outputs.append(('address', change_addr, change_amount)) - elif change_amount > self.dust_threshold(): + + # See if change would still be greater than dust after adding + # the change to the transaction + if change_amount > dust_threshold: tx.outputs.append(('address', change_addr, change_amount)) - # recompute fee including change output - fee = tx.estimated_fee(fee_per_kb) + fee = fee_estimator(tx) # remove change output tx.outputs.pop() - # if change is still above dust threshold, re-add change output. change_amount = total - (amount + fee) - if change_amount > self.dust_threshold(): - tx.outputs.append(('address', change_addr, change_amount)) - self.print_error('change', change_amount) - else: - self.print_error('not keeping dust', change_amount) - else: + + # If change is still above dust threshold, keep the change. + if change_amount > dust_threshold: + tx.outputs.append(('address', change_addr, change_amount)) + self.print_error('change', change_amount) + elif change_amount: self.print_error('not keeping dust', change_amount) return tx diff --git a/lib/wallet.py b/lib/wallet.py @@ -905,8 +905,6 @@ class Abstract_Wallet(PrintError): if type == 'address': assert is_address(data), "Address " + data + " is invalid!" - fee_per_kb = self.fee_per_kb(config) - # change address if change_addr: change_addrs = [change_addr] @@ -926,9 +924,20 @@ class Abstract_Wallet(PrintError): else: change_addrs = [address] + fee_per_kb = self.fee_per_kb(config) + def fee_estimator(tx): + if fixed_fee is not None: + return fixed_fee + return tx.estimated_fee(fee_per_kb) + + # If a fixed fee is specified, keep even dust change + dust_threshold = 182 * 3 * MIN_RELAY_TX_FEE / 1000 + if fixed_fee is None: + dust_threshold = 0 + # Let the coin chooser select the coins to spend tx = self.coin_chooser.make_tx(coins, outputs, change_addrs, - fixed_fee, fee_per_kb) + fee_estimator, dust_threshold) # Sort the inputs and outputs deterministically tx.BIP_LI01_sort()