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
return change
def _construct_tx_from_selected_buckets(self, *, buckets: Sequence[Bucket],
base_tx: PartialTransaction, change_addrs,
fee_estimator_w, dust_threshold,
base_weight) -> Tuple[PartialTransaction, List[PartialTxOutput]]:
def _construct_tx_from_selected_buckets(
self, *, buckets: Sequence[Bucket],
base_tx: PartialTransaction, change_addrs,
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
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)
# 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])
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)
tx.add_outputs(change, BIP69_sort=BIP69_sort)
return tx, change
@@ -270,9 +273,16 @@ class CoinChooserBase(Logger):
return total_weight
def make_tx(self, *, coins: Sequence[PartialTxInput], inputs: List[PartialTxInput],
outputs: List[PartialTxOutput], change_addrs: Sequence[str],
fee_estimator_vb: Callable, dust_threshold: int) -> PartialTransaction:
def make_tx(
self, *,
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
greater than dust_threshold (after adding the change output to
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)))
# 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()
# 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)
def tx_from_buckets(buckets):
return self._construct_tx_from_selected_buckets(buckets=buckets,
base_tx=base_tx,
change_addrs=change_addrs,
fee_estimator_w=fee_estimator_w,
dust_threshold=dust_threshold,
base_weight=base_weight)
return self._construct_tx_from_selected_buckets(
buckets=buckets,
base_tx=base_tx,
change_addrs=change_addrs,
fee_estimator_w=fee_estimator_w,
dust_threshold=dust_threshold,
base_weight=base_weight,
BIP69_sort=BIP69_sort,
)
# Collect the coins into buckets
all_buckets = self.bucketize_coins(coins, fee_estimator_vb=fee_estimator_vb)
# 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]:
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.BIP69_sort(outputs=False)
if BIP69_sort:
self.BIP69_sort(outputs=False)
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)
if merge_duplicates:
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()
def set_rbf(self, rbf: bool) -> None: