mirror of
https://github.com/LBRYFoundation/LBRY-Vault.git
synced 2025-08-23 17:47:31 +00:00
coinchooser: clear up what "fee_estimator" expects
This commit is contained in:
parent
cb69aa80f7
commit
fd5d1dab4f
1 changed files with 13 additions and 13 deletions
|
@ -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…
Add table
Reference in a new issue