Browse Source

implement BIP69 (lexicographical indexing of tx inputs and outputs)

MMGen 6 years ago
parent
commit
6b2c138f09
2 changed files with 16 additions and 0 deletions
  1. 3 0
      mmgen/main_txbump.py
  2. 13 0
      mmgen/tx.py

+ 3 - 0
mmgen/main_txbump.py

@@ -129,6 +129,9 @@ tx.update_fee(op_idx,fee)
 d = tx.get_fee_from_tx()
 d = tx.get_fee_from_tx()
 assert d == fee and d <= g.proto.max_tx_fee
 assert d == fee and d <= g.proto.max_tx_fee
 
 
+if g.proto.base_proto == 'Bitcoin':
+	tx.outputs.sort_bip69() # output amts have changed, so re-sort
+
 if not opt.yes:
 if not opt.yes:
 	tx.add_comment()   # edits an existing comment
 	tx.add_comment()   # edits an existing comment
 tx.create_raw()        # creates tx.hex, tx.txid
 tx.create_raw()        # creates tx.hex, tx.txid

+ 13 - 0
mmgen/tx.py

@@ -267,11 +267,21 @@ class MMGenTxInputList(list,MMGenObject):
 			if type(i.amt) != g.proto.coin_amt:
 			if type(i.amt) != g.proto.coin_amt:
 				die(2,'Coin mismatch in transaction: amount {} not of type {}!'.format(i.amt,g.proto.coin_amt))
 				die(2,'Coin mismatch in transaction: amount {} not of type {}!'.format(i.amt,g.proto.coin_amt))
 
 
+	# Lexicographical Indexing of Transaction Inputs and Outputs
+	# https://github.com/bitcoin/bips/blob/master/bip-0069.mediawiki
+	def sort_bip69(self):
+		from struct import pack
+		self.sort(key=lambda a: bytes.fromhex(a.txid) + pack('>i',a.vout))
+
 class MMGenTxOutputList(MMGenTxInputList):
 class MMGenTxOutputList(MMGenTxInputList):
 
 
 	desc = 'transaction outputs'
 	desc = 'transaction outputs'
 	member_type = 'MMGenTxOutput'
 	member_type = 'MMGenTxOutput'
 
 
+	def sort_bip69(self):
+		from struct import pack
+		self.sort(key=lambda a: pack('>q',a.amt.toSatoshi()) + bytes.fromhex(addr2scriptPubKey(a.addr)))
+
 class MMGenTX(MMGenObject):
 class MMGenTX(MMGenObject):
 
 
 	def __new__(cls,*args,**kwargs):
 	def __new__(cls,*args,**kwargs):
@@ -1430,6 +1440,9 @@ Selected non-{pnm} inputs: {{}}""".strip().format(pnm=g.proj_name,pnl=g.proj_nam
 		self.update_send_amt(change_amt)
 		self.update_send_amt(change_amt)
 
 
 		if g.proto.base_proto == 'Bitcoin':
 		if g.proto.base_proto == 'Bitcoin':
+			self.inputs.sort_bip69()
+			self.outputs.sort_bip69()
+			# do this only after inputs are sorted
 			if opt.rbf:  self.inputs[0].sequence = g.max_int - 2 # handles the locktime case too
 			if opt.rbf:  self.inputs[0].sequence = g.max_int - 2 # handles the locktime case too
 			elif locktime: self.inputs[0].sequence = g.max_int - 1
 			elif locktime: self.inputs[0].sequence = g.max_int - 1