Browse Source

coinchooser: clear up what "fee_estimator" expects

dependabot/pip/contrib/deterministic-build/ecdsa-0.13.3
SomberNight 6 years ago
parent
commit
fd5d1dab4f
No known key found for this signature in database GPG Key ID: B33B5F232C6271E9
  1. 26
      electrum/coinchooser.py

26
electrum/coinchooser.py

@ -111,14 +111,14 @@ class CoinChooserBase(Logger):
def keys(self, coins):
raise NotImplementedError
def bucketize_coins(self, coins, *, fee_estimator):
def bucketize_coins(self, coins, *, fee_estimator_vb):
keys = self.keys(coins)
buckets = defaultdict(list)
for key, coin in zip(keys, coins):
buckets[key].append(coin)
# fee_estimator returns fee to be paid, for given vbytes.
# guess whether it is just returning a constant as follows.
constant_fee = fee_estimator(2000) == fee_estimator(200)
constant_fee = fee_estimator_vb(2000) == fee_estimator_vb(200)
def make_Bucket(desc, coins):
witness = any(Transaction.is_segwit_input(coin, guess_for_address=True) for coin in coins)
@ -136,7 +136,7 @@ class CoinChooserBase(Logger):
else:
# when converting from weight to vBytes, instead of rounding up,
# keep fractional part, to avoid overestimating fee
fee = fee_estimator(Decimal(weight) / 4)
fee = fee_estimator_vb(Decimal(weight) / 4)
effective_value = value - fee
return Bucket(desc=desc,
weight=weight,
@ -151,7 +151,7 @@ class CoinChooserBase(Logger):
def penalty_func(self, base_tx, *, tx_from_buckets) -> Callable[[List[Bucket]], ScoredCandidate]:
raise NotImplementedError
def _change_amounts(self, tx, count, fee_estimator):
def _change_amounts(self, tx, count, fee_estimator_numchange):
# Break change up if bigger than max_change
output_amounts = [o.value for o in tx.outputs()]
# Don't split change of less than 0.02 BTC
@ -160,7 +160,7 @@ class CoinChooserBase(Logger):
# Use N change outputs
for n in range(1, count + 1):
# How much is left if we add this many change outputs?
change_amount = max(0, tx.get_fee() - fee_estimator(n))
change_amount = max(0, tx.get_fee() - fee_estimator_numchange(n))
if change_amount // n <= max_change:
break
@ -205,8 +205,8 @@ class CoinChooserBase(Logger):
return amounts
def _change_outputs(self, tx, change_addrs, fee_estimator, dust_threshold):
amounts = self._change_amounts(tx, len(change_addrs), fee_estimator)
def _change_outputs(self, tx, change_addrs, fee_estimator_numchange, dust_threshold):
amounts = self._change_amounts(tx, len(change_addrs), fee_estimator_numchange)
assert min(amounts) >= 0
assert len(change_addrs) >= len(amounts)
# If change is above dust threshold after accounting for the
@ -233,8 +233,8 @@ class CoinChooserBase(Logger):
# This takes a count of change outputs and returns a tx fee
output_weight = 4 * Transaction.estimated_output_size(change_addrs[0])
fee = lambda count: fee_estimator_w(tx_weight + count * output_weight)
change = self._change_outputs(tx, change_addrs, fee, dust_threshold)
fee_estimator_numchange = lambda count: fee_estimator_w(tx_weight + count * output_weight)
change = self._change_outputs(tx, change_addrs, fee_estimator_numchange, dust_threshold)
tx.add_outputs(change)
return tx, change
@ -259,14 +259,14 @@ class CoinChooserBase(Logger):
return total_weight
def make_tx(self, coins, inputs, outputs, change_addrs, fee_estimator,
def make_tx(self, coins, inputs, outputs, change_addrs, fee_estimator_vb,
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.
Note: fee_estimator expects virtual bytes
Note: fee_estimator_vb expects virtual bytes
"""
# Deterministic randomness from coins
@ -286,7 +286,7 @@ class CoinChooserBase(Logger):
spent_amount = base_tx.output_value()
def fee_estimator_w(weight):
return fee_estimator(Transaction.virtual_size_from_weight(weight))
return fee_estimator_vb(Transaction.virtual_size_from_weight(weight))
def sufficient_funds(buckets, *, bucket_value_sum):
'''Given a list of buckets, return True if it has enough
@ -309,7 +309,7 @@ class CoinChooserBase(Logger):
base_weight=base_weight)
# Collect the coins into buckets
all_buckets = self.bucketize_coins(coins, fee_estimator=fee_estimator)
all_buckets = self.bucketize_coins(coins, fee_estimator_vb=fee_estimator_vb)
# Filter some buckets out. Only keep those that have positive effective value.
# Note that this filtering is intentionally done on the bucket level
# instead of per-coin, as each bucket should be either fully spent or not at all.

Loading…
Cancel
Save