electrum

Electrum Bitcoin wallet
git clone https://git.parazyd.org/electrum
Log | Files | Refs | Submodules

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:
Mlib/tests/test_transaction.py | 32+++++++++++++++++++++++++++++++-
Mlib/tests/test_wallet_vertical.py | 6++++++
Mlib/transaction.py | 10++++------
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):