URI: 
       tcoinchooser: better account for fees in penalty_func - electrum - Electrum Bitcoin wallet
  HTML git clone https://git.parazyd.org/electrum
   DIR Log
   DIR Files
   DIR Refs
   DIR Submodules
       ---
   DIR commit cb204dd969955e6ac6b23821500c406678a3ce97
   DIR parent e3c26d7c7a7e3b0e179b0274c12017f5bb04368d
  HTML Author: SomberNight <somber.night@protonmail.com>
       Date:   Mon, 17 Jun 2019 19:55:39 +0200
       
       coinchooser: better account for fees in penalty_func
       
       Diffstat:
         M electrum/coinchooser.py             |      21 ++++++++++++++++-----
       
       1 file changed, 16 insertions(+), 5 deletions(-)
       ---
   DIR diff --git a/electrum/coinchooser.py b/electrum/coinchooser.py
       t@@ -121,7 +121,7 @@ class CoinChooserBase(Logger):
        
                return list(map(make_Bucket, buckets.keys(), buckets.values()))
        
       -    def penalty_func(self, tx):
       +    def penalty_func(self, tx, *, fee_for_buckets):
                def penalty(candidate):
                    return 0
                return penalty
       t@@ -251,10 +251,19 @@ class CoinChooserBase(Logger):
                    total_weight = get_tx_weight(buckets)
                    return total_input >= spent_amount + fee_estimator_w(total_weight)
        
       +        def fee_for_buckets(buckets) -> int:
       +            """Given a list of buckets, return the total fee paid by the
       +            transaction, in satoshis.
       +            Note that the change output(s) are not yet known here,
       +            so fees for those are excluded and hence this is a lower bound.
       +            """
       +            total_weight = get_tx_weight(buckets)
       +            return fee_estimator_w(total_weight)
       +
                # Collect the coins into buckets, choose a subset of the buckets
                buckets = self.bucketize_coins(coins)
                buckets = self.choose_buckets(buckets, sufficient_funds,
       -                                      self.penalty_func(tx))
       +                                      self.penalty_func(tx, fee_for_buckets=fee_for_buckets))
        
                tx.add_inputs([coin for b in buckets for coin in b.coins])
                tx_weight = get_tx_weight(buckets)
       t@@ -379,7 +388,7 @@ class CoinChooserPrivacy(CoinChooserRandom):
            def keys(self, coins):
                return [coin['address'] for coin in coins]
        
       -    def penalty_func(self, tx):
       +    def penalty_func(self, tx, *, fee_for_buckets):
                min_change = min(o.value for o in tx.outputs()) * 0.75
                max_change = max(o.value for o in tx.outputs()) * 1.33
                spent_amount = sum(o.value for o in tx.outputs())
       t@@ -387,8 +396,10 @@ class CoinChooserPrivacy(CoinChooserRandom):
                def penalty(buckets):
                    badness = len(buckets) - 1
                    total_input = sum(bucket.value for bucket in buckets)
       -            # FIXME "change" here also includes fees
       -            change = float(total_input - spent_amount)
       +            # FIXME fee_for_buckets does not include fees needed to cover the change output(s)
       +            # so fee here is a lower bound
       +            fee = fee_for_buckets(buckets)
       +            change = float(total_input - spent_amount - fee)
                    # Penalize change not roughly in output range
                    if change < min_change:
                        badness += (min_change - change) / (min_change + 10000)