commit e8b5bcf31e33900aa574867eb4722c014d687a42
parent 12c5474cf126f8bcb01a5cf90b582189f1297cb0
Author: SomberNight <somber.night@protonmail.com>
Date: Wed, 13 Jun 2018 15:54:45 +0200
fix incorrect txid for partial segwit txns
follow-up #4405
Diffstat:
3 files changed, 41 insertions(+), 7 deletions(-)
diff --git a/lib/tests/test_transaction.py b/lib/tests/test_transaction.py
@@ -5,7 +5,7 @@ from lib.bitcoin import TYPE_ADDRESS
from lib.keystore import xpubkey_to_address
from lib.util import bh2u, bfh
-from . import SequentialTestCase
+from . import SequentialTestCase, TestCaseForTestnet
from .test_bitcoin import needs_test_with_all_ecc_implementations
unsigned_blob = '45505446ff0001000000012a5c9a94fcde98f5581cd00162c60a13936ceb75389ea65bf38633b424eb4031000000005701ff4c53ff0488b21e03ef2afea18000000089689bff23e1e7fb2f161daa37270a97a3d8c2e537584b2d304ecb47b86d21fc021b010d3bd425f8cf2e04824bfdf1f1f5ff1d51fadd9a41f9e3fb8dd3403b1bfe00000000ffffffff0140420f00000000001976a914230ac37834073a42146f11ef8414ae929feaafc388ac00000000'
@@ -768,6 +768,36 @@ class TestTransaction(SequentialTestCase):
# 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):
def __init__(self, unspent):
diff --git a/lib/tests/test_wallet_vertical.py b/lib/tests/test_wallet_vertical.py
@@ -646,7 +646,9 @@ class TestWalletSending(TestCaseForTestnet):
# wallet1 -> wallet2
outputs = [(bitcoin.TYPE_ADDRESS, wallet2a.get_receiving_address(), 165000)]
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
+ self.assertEqual(txid, tx.txid())
self.assertFalse(tx.is_complete())
wallet1b.sign_transaction(tx, password=None)
@@ -662,6 +664,7 @@ class TestWalletSending(TestCaseForTestnet):
self.assertEqual('6e9c3cd8788bdb970a124ea06136d52bc01cec4f9b1e217627d5e90ebe77d049', tx_copy.txid())
self.assertEqual('c58650fb77d04577fccb3e201deecbf691ab52ffb61cd2e57996c4d51f7e980b', 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)
wallet2a.receive_tx_callback(tx.txid(), tx, TX_HEIGHT_UNCONFIRMED)
@@ -669,7 +672,9 @@ class TestWalletSending(TestCaseForTestnet):
# wallet2 -> wallet1
outputs = [(bitcoin.TYPE_ADDRESS, wallet1a.get_receiving_address(), 100000)]
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
+ self.assertEqual(txid, tx.txid())
self.assertFalse(tx.is_complete())
wallet2b.sign_transaction(tx, password=None)
@@ -685,6 +690,7 @@ class TestWalletSending(TestCaseForTestnet):
self.assertEqual('84b0dcb43022385f7a10e2710e5625a2be3cd6e390387b6100b55500d5eea8f6', tx_copy.txid())
self.assertEqual('7e561e25da843326e61fd20a40b72fcaeb8690176fc7c3fcbadb3a0146c8396c', 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)
wallet2a.receive_tx_callback(tx.txid(), tx, TX_HEIGHT_UNCONFIRMED)
diff --git a/lib/transaction.py b/lib/transaction.py
@@ -978,19 +978,17 @@ class Transaction:
else:
return nVersion + txins + txouts + nLocktime
- def hash(self):
- print("warning: deprecated tx.hash()")
- return self.txid()
-
def txid(self):
+ self.deserialize()
all_segwit = all(self.is_segwit_input(x) for x in self.inputs())
if not all_segwit and not self.is_complete():
return None
- ser = self.serialize(witness=False)
+ ser = self.serialize_to_network(witness=False)
return bh2u(Hash(bfh(ser))[::-1])
def wtxid(self):
- ser = self.serialize(witness=True)
+ self.deserialize()
+ ser = self.serialize_to_network(witness=True)
return bh2u(Hash(bfh(ser))[::-1])
def add_inputs(self, inputs):