ttransaction: always sort i/o deterministically - electrum - Electrum Bitcoin wallet HTML git clone https://git.parazyd.org/electrum DIR Log DIR Files DIR Refs DIR Submodules --- DIR commit 53fd6a2df590e2acd1117a05e87e66d65843005d DIR parent 5e4a4ae16bdd9e9c7a7ce056a352531a8870b74b HTML Author: SomberNight <somber.night@protonmail.com> Date: Fri, 28 Sep 2018 19:17:45 +0200 ttransaction: always sort i/o deterministically tthis was previously the caller's responsibility; now it's done implicitly when creating a txn Diffstat: M electrum/transaction.py | 12 ++++++++---- M electrum/wallet.py | 5 ----- 2 files changed, 8 insertions(+), 9 deletions(-) --- DIR diff --git a/electrum/transaction.py b/electrum/transaction.py t@@ -747,6 +747,7 @@ class Transaction: self._inputs = inputs self._outputs = outputs self.locktime = locktime + self.BIP69_sort() return self @classmethod t@@ -981,10 +982,11 @@ class Transaction: for txin in self.inputs(): txin['sequence'] = nSequence - def BIP_LI01_sort(self): - # See https://github.com/kristovatlas/rfc/blob/master/bips/bip-li01.mediawiki - self._inputs.sort(key = lambda i: (i['prevout_hash'], i['prevout_n'])) - self._outputs.sort(key = lambda o: (o[2], self.pay_script(o[0], o[1]))) + def BIP69_sort(self, inputs=True, outputs=True): + if inputs: + self._inputs.sort(key = lambda i: (i['prevout_hash'], i['prevout_n'])) + if outputs: + self._outputs.sort(key = lambda o: (o[2], self.pay_script(o[0], o[1]))) def serialize_output(self, output): output_type, addr, amount = output t@@ -1070,10 +1072,12 @@ class Transaction: def add_inputs(self, inputs): self._inputs.extend(inputs) self.raw = None + self.BIP69_sort(outputs=False) def add_outputs(self, outputs): self._outputs.extend(outputs) self.raw = None + self.BIP69_sort(inputs=False) def input_value(self): return sum(x['value'] for x in self.inputs()) DIR diff --git a/electrum/wallet.py b/electrum/wallet.py t@@ -143,7 +143,6 @@ def sweep(privkeys, network, config, recipient, fee=None, imax=100): locktime = network.get_local_height() tx = Transaction.from_io(inputs, outputs, locktime=locktime) - tx.BIP_LI01_sort() tx.set_rbf(True) tx.sign(keypairs) return tx t@@ -608,8 +607,6 @@ class Abstract_Wallet(AddressSynchronizer): outputs[i_max] = outputs[i_max]._replace(value=amount) tx = Transaction.from_io(inputs, outputs[:]) - # Sort the inputs and outputs deterministically - tx.BIP_LI01_sort() # Timelock tx to current height. tx.locktime = self.get_local_height() run_hook('make_unsigned_transaction', self, tx) t@@ -714,7 +711,6 @@ class Abstract_Wallet(AddressSynchronizer): raise CannotBumpFee(_('Cannot bump fee') + ': ' + _('could not find suitable outputs')) locktime = self.get_local_height() tx_new = Transaction.from_io(inputs, outputs, locktime=locktime) - tx_new.BIP_LI01_sort() return tx_new def cpfp(self, tx, fee): t@@ -733,7 +729,6 @@ class Abstract_Wallet(AddressSynchronizer): inputs = [item] outputs = [TxOutput(TYPE_ADDRESS, address, value - fee)] locktime = self.get_local_height() - # note: no need to call tx.BIP_LI01_sort() here - single input/output return Transaction.from_io(inputs, outputs, locktime=locktime) def add_input_sig_info(self, txin, address):