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

Loading…
Cancel
Save