Browse Source

fix incorrect txid for partial segwit txns

follow-up #4405
3.2.x
SomberNight 7 years ago
parent
commit
e8b5bcf31e
No known key found for this signature in database GPG Key ID: B33B5F232C6271E9
  1. 32
      lib/tests/test_transaction.py
  2. 6
      lib/tests/test_wallet_vertical.py
  3. 10
      lib/transaction.py

32
lib/tests/test_transaction.py

@ -5,7 +5,7 @@ from lib.bitcoin import TYPE_ADDRESS
from lib.keystore import xpubkey_to_address from lib.keystore import xpubkey_to_address
from lib.util import bh2u, bfh from lib.util import bh2u, bfh
from . import SequentialTestCase from . import SequentialTestCase, TestCaseForTestnet
from .test_bitcoin import needs_test_with_all_ecc_implementations from .test_bitcoin import needs_test_with_all_ecc_implementations
unsigned_blob = '45505446ff0001000000012a5c9a94fcde98f5581cd00162c60a13936ceb75389ea65bf38633b424eb4031000000005701ff4c53ff0488b21e03ef2afea18000000089689bff23e1e7fb2f161daa37270a97a3d8c2e537584b2d304ecb47b86d21fc021b010d3bd425f8cf2e04824bfdf1f1f5ff1d51fadd9a41f9e3fb8dd3403b1bfe00000000ffffffff0140420f00000000001976a914230ac37834073a42146f11ef8414ae929feaafc388ac00000000' unsigned_blob = '45505446ff0001000000012a5c9a94fcde98f5581cd00162c60a13936ceb75389ea65bf38633b424eb4031000000005701ff4c53ff0488b21e03ef2afea18000000089689bff23e1e7fb2f161daa37270a97a3d8c2e537584b2d304ecb47b86d21fc021b010d3bd425f8cf2e04824bfdf1f1f5ff1d51fadd9a41f9e3fb8dd3403b1bfe00000000ffffffff0140420f00000000001976a914230ac37834073a42146f11ef8414ae929feaafc388ac00000000'
@ -768,6 +768,36 @@ class TestTransaction(SequentialTestCase):
# txns from Bitcoin Core ends <--- # txns from Bitcoin Core ends <---
class TestTransactionTestnet(TestCaseForTestnet):
def _run_naive_tests_on_tx(self, raw_tx, txid):
tx = transaction.Transaction(raw_tx)
self.assertEqual(txid, tx.txid())
self.assertEqual(raw_tx, tx.serialize())
self.assertTrue(tx.estimated_size() >= 0)
# partial txns using our partial format --->
# NOTE: our partial format contains xpubs, and xpubs have version bytes,
# and version bytes encode the network as well; so these are network-sensitive!
def test_txid_partial_segwit_p2wpkh(self):
raw_tx = '45505446ff000100000000010115a847356cbb44be67f345965bb3f2589e2fec1c9a0ada21fd28225dcc602e8f0100000000fdffffff02f6fd1200000000001600149c756aa33f4f89418b33872a973274b5445c727b80969800000000001600140f9de573bc679d040e763d13f0250bd03e625f6ffeffffffff9095ab000000000000000201ff53ff045f1cf6014af5fa07800000002fa3f450ba41799b9b62642979505817783a9b6c656dc11cd0bb4fa362096808026adc616c25a4d0a877d1741eb1db9cef65c15118bd7d5f31bf65f319edda81840100c8000f391400'
txid = '63ff7e99d85d8e33f683e6ec84574bdf8f5111078a5fe900893e019f9a7f95c3'
self._run_naive_tests_on_tx(raw_tx, txid)
def test_txid_partial_segwit_p2wpkh_p2sh_simple(self):
raw_tx = '45505446ff0001000000000101d0d23a6fbddb21cc664cb81cca96715baa4d6dbe5b7b9bcc6632f1005a7b0b840100000017160014a78a91261e71a681b6312cd184b14503a21f856afdffffff0134410f000000000017a914d6514ca17ecc31952c990daf96e307fbc58529cd87feffffffff40420f000000000000000201ff53ff044a5262033601222e800000001618aa51e49a961f63fd111f64cd4a7e792c1d7168be7a07703de505ebed2cf70286ebbe755767adaa5835f4d78dec1ee30849d69eacfe80b7ee6b1585279536c30000020011391400'
txid = '2739f2e7fde9b8ec73fce4aee53722cc7683312d1321ded073284c51fadf44df'
self._run_naive_tests_on_tx(raw_tx, txid)
def test_txid_partial_segwit_p2wpkh_p2sh_mixed_outputs(self):
raw_tx = '45505446ff00010000000001011dcac788f24b84d771b60c44e1f9b6b83429e50f06e1472d47241922164013b00100000017160014801d28ca6e2bde551112031b6cb75de34f10851ffdffffff0440420f00000000001600140f9de573bc679d040e763d13f0250bd03e625f6fc0c62d000000000017a9142899f6484e477233ce60072fc185ef4c1f2c654487809698000000000017a914d40f85ba3c8fa0f3615bcfa5d6603e36dfc613ef87712d19040000000017a914e38c0cffde769cb65e72cda1c234052ae8d2254187feffffffff6ad1ee040000000000000201ff53ff044a5262033601222e800000001618aa51e49a961f63fd111f64cd4a7e792c1d7168be7a07703de505ebed2cf70286ebbe755767adaa5835f4d78dec1ee30849d69eacfe80b7ee6b1585279536c301000c000f391400'
txid = 'ba5c88e07a4025a39ad3b85247cbd4f556a70d6312b18e04513c7cec9d45d6ac'
self._run_naive_tests_on_tx(raw_tx, txid)
# end partial txns <---
class NetworkMock(object): class NetworkMock(object):
def __init__(self, unspent): def __init__(self, unspent):

6
lib/tests/test_wallet_vertical.py

@ -646,7 +646,9 @@ class TestWalletSending(TestCaseForTestnet):
# wallet1 -> wallet2 # wallet1 -> wallet2
outputs = [(bitcoin.TYPE_ADDRESS, wallet2a.get_receiving_address(), 165000)] outputs = [(bitcoin.TYPE_ADDRESS, wallet2a.get_receiving_address(), 165000)]
tx = wallet1a.mktx(outputs=outputs, password=None, config=self.config, fee=5000) tx = wallet1a.mktx(outputs=outputs, password=None, config=self.config, fee=5000)
txid = tx.txid()
tx = Transaction(tx.serialize()) # simulates moving partial txn between cosigners tx = Transaction(tx.serialize()) # simulates moving partial txn between cosigners
self.assertEqual(txid, tx.txid())
self.assertFalse(tx.is_complete()) self.assertFalse(tx.is_complete())
wallet1b.sign_transaction(tx, password=None) wallet1b.sign_transaction(tx, password=None)
@ -662,6 +664,7 @@ class TestWalletSending(TestCaseForTestnet):
self.assertEqual('6e9c3cd8788bdb970a124ea06136d52bc01cec4f9b1e217627d5e90ebe77d049', tx_copy.txid()) self.assertEqual('6e9c3cd8788bdb970a124ea06136d52bc01cec4f9b1e217627d5e90ebe77d049', tx_copy.txid())
self.assertEqual('c58650fb77d04577fccb3e201deecbf691ab52ffb61cd2e57996c4d51f7e980b', tx_copy.wtxid()) self.assertEqual('c58650fb77d04577fccb3e201deecbf691ab52ffb61cd2e57996c4d51f7e980b', tx_copy.wtxid())
self.assertEqual(tx.wtxid(), tx_copy.wtxid()) self.assertEqual(tx.wtxid(), tx_copy.wtxid())
self.assertEqual(txid, tx_copy.txid())
wallet1a.receive_tx_callback(tx.txid(), tx, TX_HEIGHT_UNCONFIRMED) wallet1a.receive_tx_callback(tx.txid(), tx, TX_HEIGHT_UNCONFIRMED)
wallet2a.receive_tx_callback(tx.txid(), tx, TX_HEIGHT_UNCONFIRMED) wallet2a.receive_tx_callback(tx.txid(), tx, TX_HEIGHT_UNCONFIRMED)
@ -669,7 +672,9 @@ class TestWalletSending(TestCaseForTestnet):
# wallet2 -> wallet1 # wallet2 -> wallet1
outputs = [(bitcoin.TYPE_ADDRESS, wallet1a.get_receiving_address(), 100000)] outputs = [(bitcoin.TYPE_ADDRESS, wallet1a.get_receiving_address(), 100000)]
tx = wallet2a.mktx(outputs=outputs, password=None, config=self.config, fee=5000) tx = wallet2a.mktx(outputs=outputs, password=None, config=self.config, fee=5000)
txid = tx.txid()
tx = Transaction(tx.serialize()) # simulates moving partial txn between cosigners tx = Transaction(tx.serialize()) # simulates moving partial txn between cosigners
self.assertEqual(txid, tx.txid())
self.assertFalse(tx.is_complete()) self.assertFalse(tx.is_complete())
wallet2b.sign_transaction(tx, password=None) wallet2b.sign_transaction(tx, password=None)
@ -685,6 +690,7 @@ class TestWalletSending(TestCaseForTestnet):
self.assertEqual('84b0dcb43022385f7a10e2710e5625a2be3cd6e390387b6100b55500d5eea8f6', tx_copy.txid()) self.assertEqual('84b0dcb43022385f7a10e2710e5625a2be3cd6e390387b6100b55500d5eea8f6', tx_copy.txid())
self.assertEqual('7e561e25da843326e61fd20a40b72fcaeb8690176fc7c3fcbadb3a0146c8396c', tx_copy.wtxid()) self.assertEqual('7e561e25da843326e61fd20a40b72fcaeb8690176fc7c3fcbadb3a0146c8396c', tx_copy.wtxid())
self.assertEqual(tx.wtxid(), tx_copy.wtxid()) self.assertEqual(tx.wtxid(), tx_copy.wtxid())
self.assertEqual(txid, tx_copy.txid())
wallet1a.receive_tx_callback(tx.txid(), tx, TX_HEIGHT_UNCONFIRMED) wallet1a.receive_tx_callback(tx.txid(), tx, TX_HEIGHT_UNCONFIRMED)
wallet2a.receive_tx_callback(tx.txid(), tx, TX_HEIGHT_UNCONFIRMED) wallet2a.receive_tx_callback(tx.txid(), tx, TX_HEIGHT_UNCONFIRMED)

10
lib/transaction.py

@ -978,19 +978,17 @@ class Transaction:
else: else:
return nVersion + txins + txouts + nLocktime return nVersion + txins + txouts + nLocktime
def hash(self):
print("warning: deprecated tx.hash()")
return self.txid()
def txid(self): def txid(self):
self.deserialize()
all_segwit = all(self.is_segwit_input(x) for x in self.inputs()) all_segwit = all(self.is_segwit_input(x) for x in self.inputs())
if not all_segwit and not self.is_complete(): if not all_segwit and not self.is_complete():
return None return None
ser = self.serialize(witness=False) ser = self.serialize_to_network(witness=False)
return bh2u(Hash(bfh(ser))[::-1]) return bh2u(Hash(bfh(ser))[::-1])
def wtxid(self): def wtxid(self):
ser = self.serialize(witness=True) self.deserialize()
ser = self.serialize_to_network(witness=True)
return bh2u(Hash(bfh(ser))[::-1]) return bh2u(Hash(bfh(ser))[::-1])
def add_inputs(self, inputs): def add_inputs(self, inputs):

Loading…
Cancel
Save