1
0

coin_chooser: make BIP69_sort optional

This commit is contained in:
ThomasV
2024-12-03 18:25:45 +01:00
parent 8bf505fc4b
commit 62331aeb56
2 changed files with 36 additions and 22 deletions

View File

@@ -225,14 +225,17 @@ class CoinChooserBase(Logger):
c.is_change = True c.is_change = True
return change return change
def _construct_tx_from_selected_buckets(self, *, buckets: Sequence[Bucket], def _construct_tx_from_selected_buckets(
base_tx: PartialTransaction, change_addrs, self, *, buckets: Sequence[Bucket],
fee_estimator_w, dust_threshold, base_tx: PartialTransaction, change_addrs,
base_weight) -> Tuple[PartialTransaction, List[PartialTxOutput]]: fee_estimator_w, dust_threshold,
base_weight,
BIP69_sort: bool,
) -> Tuple[PartialTransaction, List[PartialTxOutput]]:
# make a copy of base_tx so it won't get mutated # make a copy of base_tx so it won't get mutated
tx = PartialTransaction.from_io(base_tx.inputs()[:], base_tx.outputs()[:]) tx = PartialTransaction.from_io(base_tx.inputs()[:], base_tx.outputs()[:], BIP69_sort=BIP69_sort)
tx.add_inputs([coin for b in buckets for coin in b.coins]) tx.add_inputs([coin for b in buckets for coin in b.coins], BIP69_sort=BIP69_sort)
tx_weight = self._get_tx_weight(buckets, base_weight=base_weight) tx_weight = self._get_tx_weight(buckets, base_weight=base_weight)
# change is sent back to sending address unless specified # change is sent back to sending address unless specified
@@ -246,7 +249,7 @@ class CoinChooserBase(Logger):
output_weight = 4 * Transaction.estimated_output_size_for_address(change_addrs[0]) output_weight = 4 * Transaction.estimated_output_size_for_address(change_addrs[0])
fee_estimator_numchange = 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_estimator_numchange, dust_threshold) change = self._change_outputs(tx, change_addrs, fee_estimator_numchange, dust_threshold)
tx.add_outputs(change) tx.add_outputs(change, BIP69_sort=BIP69_sort)
return tx, change return tx, change
@@ -270,9 +273,16 @@ class CoinChooserBase(Logger):
return total_weight return total_weight
def make_tx(self, *, coins: Sequence[PartialTxInput], inputs: List[PartialTxInput], def make_tx(
outputs: List[PartialTxOutput], change_addrs: Sequence[str], self, *,
fee_estimator_vb: Callable, dust_threshold: int) -> PartialTransaction: coins: Sequence[PartialTxInput],
inputs: List[PartialTxInput],
outputs: List[PartialTxOutput],
change_addrs: Sequence[str],
fee_estimator_vb: Callable,
dust_threshold: int,
BIP69_sort: bool = True,
) -> PartialTransaction:
"""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
@@ -289,7 +299,7 @@ class CoinChooserBase(Logger):
self.p = PRNG(b''.join(sorted(utxos))) self.p = PRNG(b''.join(sorted(utxos)))
# Copy the outputs so when adding change we don't modify "outputs" # Copy the outputs so when adding change we don't modify "outputs"
base_tx = PartialTransaction.from_io(inputs[:], outputs[:]) base_tx = PartialTransaction.from_io(inputs[:], outputs[:], BIP69_sort=BIP69_sort)
input_value = base_tx.input_value() input_value = base_tx.input_value()
# Weight of the transaction with no inputs and no change # Weight of the transaction with no inputs and no change
@@ -320,13 +330,15 @@ class CoinChooserBase(Logger):
return total_input >= spent_amount + fee_estimator_w(total_weight) return total_input >= spent_amount + fee_estimator_w(total_weight)
def tx_from_buckets(buckets): def tx_from_buckets(buckets):
return self._construct_tx_from_selected_buckets(buckets=buckets, return self._construct_tx_from_selected_buckets(
base_tx=base_tx, buckets=buckets,
change_addrs=change_addrs, base_tx=base_tx,
fee_estimator_w=fee_estimator_w, change_addrs=change_addrs,
dust_threshold=dust_threshold, fee_estimator_w=fee_estimator_w,
base_weight=base_weight) dust_threshold=dust_threshold,
base_weight=base_weight,
BIP69_sort=BIP69_sort,
)
# Collect the coins into buckets # Collect the coins into buckets
all_buckets = self.bucketize_coins(coins, fee_estimator_vb=fee_estimator_vb) 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.

View File

@@ -2161,16 +2161,18 @@ class PartialTransaction(Transaction):
def outputs(self) -> Sequence[PartialTxOutput]: def outputs(self) -> Sequence[PartialTxOutput]:
return self._outputs return self._outputs
def add_inputs(self, inputs: List[PartialTxInput]) -> None: def add_inputs(self, inputs: List[PartialTxInput], BIP69_sort=True) -> None:
self._inputs.extend(inputs) self._inputs.extend(inputs)
self.BIP69_sort(outputs=False) if BIP69_sort:
self.BIP69_sort(outputs=False)
self.invalidate_ser_cache() self.invalidate_ser_cache()
def add_outputs(self, outputs: List[PartialTxOutput], *, merge_duplicates: bool = False) -> None: def add_outputs(self, outputs: List[PartialTxOutput], *, merge_duplicates: bool = False, BIP69_sort: bool = True) -> None:
self._outputs.extend(outputs) self._outputs.extend(outputs)
if merge_duplicates: if merge_duplicates:
self._outputs = merge_duplicate_tx_outputs(self._outputs) self._outputs = merge_duplicate_tx_outputs(self._outputs)
self.BIP69_sort(inputs=False) if BIP69_sort:
self.BIP69_sort(inputs=False)
self.invalidate_ser_cache() self.invalidate_ser_cache()
def set_rbf(self, rbf: bool) -> None: def set_rbf(self, rbf: bool) -> None: