Skip to content

Commit 8627a4e

Browse files
committed
fix bip69_sort, nsequence
1 parent 358d892 commit 8627a4e

File tree

4 files changed

+32
-25
lines changed

4 files changed

+32
-25
lines changed

electrum/coinchooser.py

+20-17
Original file line numberDiff line numberDiff line change
@@ -225,14 +225,17 @@ def _change_outputs(self, tx: PartialTransaction, change_addrs, fee_estimator_nu
225225
c.is_change = True
226226
return change
227227

228-
def _construct_tx_from_selected_buckets(self, *, buckets: Sequence[Bucket],
229-
base_tx: PartialTransaction, change_addrs,
230-
fee_estimator_w, dust_threshold,
231-
base_weight) -> Tuple[PartialTransaction, List[PartialTxOutput]]:
228+
def _construct_tx_from_selected_buckets(
229+
self, *, buckets: Sequence[Bucket],
230+
base_tx: PartialTransaction, change_addrs,
231+
fee_estimator_w, dust_threshold,
232+
base_weight,
233+
BIP69_sort: bool,
234+
) -> Tuple[PartialTransaction, List[PartialTxOutput]]:
232235
# make a copy of base_tx so it won't get mutated
233-
tx = PartialTransaction.from_io(base_tx.inputs()[:], base_tx.outputs()[:])
236+
tx = PartialTransaction.from_io(base_tx.inputs()[:], base_tx.outputs()[:], BIP69_sort=BIP69_sort)
234237

235-
tx.add_inputs([coin for b in buckets for coin in b.coins])
238+
tx.add_inputs([coin for b in buckets for coin in b.coins], BIP69_sort=BIP69_sort)
236239
tx_weight = self._get_tx_weight(buckets, base_weight=base_weight)
237240

238241
# change is sent back to sending address unless specified
@@ -246,7 +249,7 @@ def _construct_tx_from_selected_buckets(self, *, buckets: Sequence[Bucket],
246249
output_weight = 4 * Transaction.estimated_output_size_for_address(change_addrs[0])
247250
fee_estimator_numchange = lambda count: fee_estimator_w(tx_weight + count * output_weight)
248251
change = self._change_outputs(tx, change_addrs, fee_estimator_numchange, dust_threshold)
249-
tx.add_outputs(change)
252+
tx.add_outputs(change, BIP69_sort=BIP69_sort)
250253

251254
return tx, change
252255

@@ -296,7 +299,7 @@ def make_tx(
296299
self.p = PRNG(b''.join(sorted(utxos)))
297300

298301
# Copy the outputs so when adding change we don't modify "outputs"
299-
base_tx = PartialTransaction.from_io(inputs[:], outputs[:])
302+
base_tx = PartialTransaction.from_io(inputs[:], outputs[:], BIP69_sort=BIP69_sort)
300303
input_value = base_tx.input_value()
301304

302305
# Weight of the transaction with no inputs and no change
@@ -327,13 +330,15 @@ def sufficient_funds(buckets, *, bucket_value_sum):
327330
return total_input >= spent_amount + fee_estimator_w(total_weight)
328331

329332
def tx_from_buckets(buckets):
330-
return self._construct_tx_from_selected_buckets(buckets=buckets,
331-
base_tx=base_tx,
332-
change_addrs=change_addrs,
333-
fee_estimator_w=fee_estimator_w,
334-
dust_threshold=dust_threshold,
335-
base_weight=base_weight)
336-
333+
return self._construct_tx_from_selected_buckets(
334+
buckets=buckets,
335+
base_tx=base_tx,
336+
change_addrs=change_addrs,
337+
fee_estimator_w=fee_estimator_w,
338+
dust_threshold=dust_threshold,
339+
base_weight=base_weight,
340+
BIP69_sort=BIP69_sort,
341+
)
337342
# Collect the coins into buckets
338343
all_buckets = self.bucketize_coins(coins, fee_estimator_vb=fee_estimator_vb)
339344
# Filter some buckets out. Only keep those that have positive effective value.
@@ -349,8 +354,6 @@ def tx_from_buckets(buckets):
349354
self.logger.info(f"using {len(tx.inputs())} inputs")
350355
self.logger.info(f"using buckets: {[bucket.desc for bucket in scored_candidate.buckets]}")
351356

352-
if BIP69_sort:
353-
tx.BIP69_sort()
354357
return tx
355358

356359
def choose_buckets(self, buckets: List[Bucket],

electrum/transaction.py

+6-4
Original file line numberDiff line numberDiff line change
@@ -2164,16 +2164,18 @@ def inputs(self) -> Sequence[PartialTxInput]:
21642164
def outputs(self) -> Sequence[PartialTxOutput]:
21652165
return self._outputs
21662166

2167-
def add_inputs(self, inputs: List[PartialTxInput]) -> None:
2167+
def add_inputs(self, inputs: List[PartialTxInput], BIP69_sort=True) -> None:
21682168
self._inputs.extend(inputs)
2169-
self.BIP69_sort(outputs=False)
2169+
if BIP69_sort:
2170+
self.BIP69_sort(outputs=False)
21702171
self.invalidate_ser_cache()
21712172

2172-
def add_outputs(self, outputs: List[PartialTxOutput], *, merge_duplicates: bool = False) -> None:
2173+
def add_outputs(self, outputs: List[PartialTxOutput], *, merge_duplicates: bool = False, BIP69_sort: bool = True) -> None:
21732174
self._outputs.extend(outputs)
21742175
if merge_duplicates:
21752176
self._outputs = merge_duplicate_tx_outputs(self._outputs)
2176-
self.BIP69_sort(inputs=False)
2177+
if BIP69_sort:
2178+
self.BIP69_sort(inputs=False)
21772179
self.invalidate_ser_cache()
21782180

21792181
def set_rbf(self, rbf: bool) -> None:

electrum/wallet.py

+5-4
Original file line numberDiff line numberDiff line change
@@ -1852,8 +1852,10 @@ def make_unsigned_transaction(
18521852
if fee is None and self.config.fee_per_kb() is None:
18531853
raise NoDynamicFeeEstimates()
18541854

1855-
for item in coins:
1856-
self.add_input_info(item)
1855+
for txin in coins:
1856+
self.add_input_info(txin)
1857+
nSequence = 0xffffffff - (2 if rbf else 1)
1858+
txin.nsequence = nSequence
18571859

18581860
# Fee estimator
18591861
if fee is None:
@@ -1944,7 +1946,6 @@ def fee_estimator(size: Union[int, float, Decimal]) -> int:
19441946
# Timelock tx to current height.
19451947
tx.locktime = get_locktime_for_new_transaction(self.network)
19461948
tx.rbf_merge_txid = rbf_merge_txid
1947-
#tx.set_rbf(rbf) # this overwrites nsequence
19481949
tx.add_info_from_wallet(self)
19491950
run_hook('make_unsigned_transaction', self, tx)
19501951
return tx
@@ -3390,7 +3391,7 @@ async def manage_batch_payments(self):
33903391
self.start_new_batch(tx)
33913392

33923393
base_tx = self.batch_txs[-1] if self.batch_txs else None
3393-
# group by locktime
3394+
# todo: group by locktime
33943395
htlcs = self.htlcs_after(base_tx) if base_tx else self.batch_htlcs
33953396
inputs = [copy.deepcopy(h[0]) for h in htlcs.values()]
33963397
to_pay = [h[1] for h in htlcs.values()]

tests/test_commands.py

+1
Original file line numberDiff line numberDiff line change
@@ -342,6 +342,7 @@ async def test_bumpfee(self, mock_save_db):
342342
orig_rawtx = "02000000000101b9723dfc69af058ef6613539a000d2cd098a2c8a74e802b6d8739db708ba8c9a0100000000fdffffff02a00f00000000000016001429e1fd187f0cac845946ae1b11dc136c536bfc0fe8b2000000000000160014100611bcb3aee7aad176936cf4ed56ade03027aa02473044022063c05e2347f16251922830ccc757231247b3c2970c225f988e9204844a1ab7b802204652d2c4816707e3d3bea2609b83b079001a435bad2a99cc2e730f276d07070c012102ee3f00141178006c78b0b458aab21588388335078c655459afe544211f15aee050721f00"
343343
orig_tx = tx_from_any(orig_rawtx)
344344
orig_txid = orig_tx.txid()
345+
self.maxDiff = 1000
345346
self.assertEqual("02000000000101b9723dfc69af058ef6613539a000d2cd098a2c8a74e802b6d8739db708ba8c9a0100000000fdffffff02a00f00000000000016001429e1fd187f0cac845946ae1b11dc136c536bfc0f84b2000000000000160014100611bcb3aee7aad176936cf4ed56ade03027aa0247304402203aa63539b673a3bd70a76482b17f35f8843974fab28f84143a00450789010bc40220779c2ce2d0217f973f1f6c9f718e19fc7ebd14dd8821a962f002437cda3082ec012102ee3f00141178006c78b0b458aab21588388335078c655459afe544211f15aee000000000",
346347
await cmds.bumpfee(tx=orig_rawtx, new_fee_rate='1.6', wallet=wallet))
347348
# test txid as first arg

0 commit comments

Comments
 (0)