|
|
|
|
@ -1888,6 +1888,85 @@ class TestWalletSending(ElectrumTestCase):
|
|
|
|
|
self.assertEqual('02000000000102bbef0182c2c746bd28517b6fd27ba9eef9c7fb5982efd27bd612cc5a28615a3a0000000000fdffffffbbef0182c2c746bd28517b6fd27ba9eef9c7fb5982efd27bd612cc5a28615a3a0100000000fdffffff02602200000000000016001413fabce9be995554a722fc4e1c5ae53ebfd58164905f010000000000160014b266f4f1b9f0bc72f090573d049df66d4efa082c0247304402205c50b9ddb1b3ead6214d7d9707c74ba29ff547880d017aae2459db156bf85b9b022041134562fffa3dccf1ac05d9b07da62a8d57dd158d25d22d1965a011325e64aa012102c72b815ba00ccb0b469cc61a0ceb843d974e630cf34abcfac178838f1974f68f02473044022049774c32b0ad046b7acdb4acc38107b6b1be57c0d167643a48cbc045850c86c202205189ed61342fc52a377c2865a879c4c2606de98eebd6bf4d73874d62329668c70121033484c8ed83c359d1c3e569accb04b77988daab9408fc82869051c10d0749ac2006fa2400', |
|
|
|
|
str(tx)) |
|
|
|
|
|
|
|
|
|
async def test_rbf_batching__merge_duplicate_outputs(self): |
|
|
|
|
"""txos paying to the same address might be merged into a single output with a larger value""" |
|
|
|
|
wallet = self.create_standard_wallet_from_seed('response era cable net spike again observe dumb wage wonder sail tortoise', |
|
|
|
|
config=self.config) |
|
|
|
|
wallet.config.WALLET_BATCH_RBF = True |
|
|
|
|
|
|
|
|
|
# bootstrap wallet (incoming funding_tx0): for 500k sat |
|
|
|
|
funding_tx = Transaction('02000000000101013548c9019890e27ce9e58766de05f18ea40ede70751fb6cd7a3a1715ece0a30100000000fdffffff0220a1070000000000160014542266519a44eb9b903761d40c6fe1055d33fa05485a080000000000160014bc69f7d82c403a9f35dfb6d1a4531d6b19cab0e3024730440220346b200f21c3024e1d51fb4ecddbdbd68bd24ae7b9dfd501519f6dcbeb7c052402200617e3ce7b0eb308e30caf23894fb0388b68fb1c15dd0681dd13ae5e735f148101210360d0c9ef15b8b6a16912d341ad218a4e4e4e07e9347f4a2dbc7ca8d974f8bc9ec1ad2600') |
|
|
|
|
funding_txid = funding_tx.txid() |
|
|
|
|
wallet.adb.receive_tx_callback(funding_txid, funding_tx, TX_HEIGHT_UNCONFIRMED) |
|
|
|
|
|
|
|
|
|
dest_addr = "tb1qtzhwpufqr5dwztdaysfqnwlf9m29uwdkq8zm9w" |
|
|
|
|
# first payment to dest_addr |
|
|
|
|
outputs1 = [PartialTxOutput.from_address_and_value(dest_addr, 200_000)] |
|
|
|
|
coins = wallet.get_spendable_coins(domain=None) |
|
|
|
|
tx1 = wallet.make_unsigned_transaction(coins=coins, outputs=outputs1, fee=2000) |
|
|
|
|
tx1.set_rbf(True) |
|
|
|
|
tx1.locktime = 2534850 |
|
|
|
|
tx1.version = 2 |
|
|
|
|
wallet.sign_transaction(tx1, password=None) |
|
|
|
|
self.assertEqual(2, len(tx1.outputs())) |
|
|
|
|
self.assertEqual('020000000001019264597cffcce8f0c17b16a02adca7a95ae90f2ea51bd4b4df60c76dfe86686e0000000000fdffffff02400d03000000000016001458aee0f1201d1ae12dbd241209bbe92ed45e39b6108c0400000000001600144e1b662f616fe134430054e29295ea6e5c18f1730247304402205ea932303bb89bfe07c1e4c28117cb84f613e09dd51464aa2ed2b184c2f2b76902202968280003b0e7d4098bf9adc47246db7b84c83f718e70a609de05f3b2ae64e80121029b1a61d66896486ab893741b38dbafb9673b91a82237d6e4ca0da3cda7cbeb7cc2ad2600', |
|
|
|
|
str(tx1)) |
|
|
|
|
wallet.adb.receive_tx_callback(tx1.txid(), tx1, TX_HEIGHT_UNCONFIRMED) |
|
|
|
|
self.assertEqual((0, 298_000, 0), wallet.get_balance()) |
|
|
|
|
|
|
|
|
|
wallet.config.WALLET_MERGE_DUPLICATE_OUTPUTS = True |
|
|
|
|
# second payment to dest_addr (merged) |
|
|
|
|
outputs2 = [PartialTxOutput.from_address_and_value(dest_addr, 100_000)] |
|
|
|
|
coins = wallet.get_spendable_coins(domain=None) |
|
|
|
|
tx2 = wallet.make_unsigned_transaction(coins=coins, outputs=outputs2, fee=3000) |
|
|
|
|
tx2.set_rbf(True) |
|
|
|
|
tx2.locktime = 2534850 |
|
|
|
|
tx2.version = 2 |
|
|
|
|
wallet.sign_transaction(tx2, password=None) |
|
|
|
|
self.assertEqual(2, len(tx2.outputs())) |
|
|
|
|
self.assertEqual('020000000001019264597cffcce8f0c17b16a02adca7a95ae90f2ea51bd4b4df60c76dfe86686e0000000000fdffffff0288010300000000001600144e1b662f616fe134430054e29295ea6e5c18f173e09304000000000016001458aee0f1201d1ae12dbd241209bbe92ed45e39b60247304402201b5856f572a70f667392f000780044a6c6677eadadd5b56d2b15d1f90a8bf4b7022046566836d7e1e1a099ff72b4ecb09d6b24e701e12c0fb4c5667172d47d9b54520121029b1a61d66896486ab893741b38dbafb9673b91a82237d6e4ca0da3cda7cbeb7cc2ad2600', |
|
|
|
|
str(tx2)) |
|
|
|
|
wallet.adb.receive_tx_callback(tx2.txid(), tx2, TX_HEIGHT_UNCONFIRMED) |
|
|
|
|
self.assertEqual((0, 197_000, 0), wallet.get_balance()) |
|
|
|
|
|
|
|
|
|
# remove tx2 from wallet, by replacing it with tx1 |
|
|
|
|
wallet.adb.receive_tx_callback(tx1.txid(), tx1, TX_HEIGHT_UNCONFIRMED) |
|
|
|
|
self.assertEqual((0, 298_000, 0), wallet.get_balance()) |
|
|
|
|
|
|
|
|
|
wallet.config.WALLET_MERGE_DUPLICATE_OUTPUTS = False |
|
|
|
|
# second payment to dest_addr (not merged, just duplicate outputs) |
|
|
|
|
outputs2 = [PartialTxOutput.from_address_and_value(dest_addr, 100_000)] |
|
|
|
|
coins = wallet.get_spendable_coins(domain=None) |
|
|
|
|
tx3 = wallet.make_unsigned_transaction(coins=coins, outputs=outputs2, fee=3000) |
|
|
|
|
tx3.set_rbf(True) |
|
|
|
|
tx3.locktime = 2534850 |
|
|
|
|
tx3.version = 2 |
|
|
|
|
wallet.sign_transaction(tx3, password=None) |
|
|
|
|
self.assertEqual(3, len(tx3.outputs())) |
|
|
|
|
self.assertEqual('020000000001019264597cffcce8f0c17b16a02adca7a95ae90f2ea51bd4b4df60c76dfe86686e0000000000fdffffff03a08601000000000016001458aee0f1201d1ae12dbd241209bbe92ed45e39b688010300000000001600144e1b662f616fe134430054e29295ea6e5c18f173400d03000000000016001458aee0f1201d1ae12dbd241209bbe92ed45e39b602473044022061386129ebefda19e22ab9e2c06642a2a5eb7637e1b492d5c164591ff0fb27c9022006129d5d0c780d6830fb6cf924e3eeef03b8a349a9ebb36969cae410d9ff0fa50121029b1a61d66896486ab893741b38dbafb9673b91a82237d6e4ca0da3cda7cbeb7cc2ad2600', |
|
|
|
|
str(tx3)) |
|
|
|
|
wallet.adb.receive_tx_callback(tx3.txid(), tx3, TX_HEIGHT_UNCONFIRMED) |
|
|
|
|
self.assertEqual((0, 197_000, 0), wallet.get_balance()) |
|
|
|
|
|
|
|
|
|
async def test_join_psbts__merge_duplicate_outputs(self): |
|
|
|
|
"""txos paying to the same address might be merged into a single output with a larger value""" |
|
|
|
|
rawtx1 = "70736274ff01007102000000019264597cffcce8f0c17b16a02adca7a95ae90f2ea51bd4b4df60c76dfe86686e0000000000fdffffff02400d03000000000016001458aee0f1201d1ae12dbd241209bbe92ed45e39b6108c0400000000001600144e1b662f616fe134430054e29295ea6e5c18f173c2ad26000001011f20a1070000000000160014542266519a44eb9b903761d40c6fe1055d33fa050100de02000000000101013548c9019890e27ce9e58766de05f18ea40ede70751fb6cd7a3a1715ece0a30100000000fdffffff0220a1070000000000160014542266519a44eb9b903761d40c6fe1055d33fa05485a080000000000160014bc69f7d82c403a9f35dfb6d1a4531d6b19cab0e3024730440220346b200f21c3024e1d51fb4ecddbdbd68bd24ae7b9dfd501519f6dcbeb7c052402200617e3ce7b0eb308e30caf23894fb0388b68fb1c15dd0681dd13ae5e735f148101210360d0c9ef15b8b6a16912d341ad218a4e4e4e07e9347f4a2dbc7ca8d974f8bc9ec1ad26002206029b1a61d66896486ab893741b38dbafb9673b91a82237d6e4ca0da3cda7cbeb7c101f1b48320000008000000000000000000000220203db4846ec1841f48484590e67fcd7d1039f124a04410c5794f38ec8625329ea23101f1b483200000080010000000000000000" |
|
|
|
|
rawtx2 = "70736274ff0100710200000001a4c6da70097e1bfbbcba0edad4ba1143295300b60851aa6c4916a0b32381bf7f0000000000fdffffff02a08601000000000016001458aee0f1201d1ae12dbd241209bbe92ed45e39b6108c040000000000160014fac4435311276a6cfda5681cfb02252acdd14c3fc2ad26000001011f801a06000000000016001452af44a1e32754fd8d2e7c1c3cc1b305379f0b660100de020000000001018eeaf0cd7de0e0e117af1a7f2bab59b4ddfbd416ef7460b3fd42a1f7bc039cfd0000000000fdffffff02801a06000000000016001452af44a1e32754fd8d2e7c1c3cc1b305379f0b66909f0700000000001600140847a3685a3ce9911cdce3fbf33cb42edc8f6dd902473044022044d3485c09784f03cd648117ef2d4d0dabeeb2929b30f2e52c3bbd5efd1c0f820220346655235eb9fcb54b23bbf194217092cc8aa6dd33ecf018907626b90289be6801210304e06afd290a4e7a9eb008cf408a4f9b0640fd2688258b523aa3dbb236bb3f7eccad2600220602c1ed648e71f15643950b444b864ab784b9d0e31e6ca6ec7d849d3dda4d98da05101f1b48320000008000000000010000000000220203aba60233db3aab45d0196cb70a22d667faa92124760700d20c953b0222ced96d101f1b483200000080010000000100000000" |
|
|
|
|
|
|
|
|
|
self.config.WALLET_MERGE_DUPLICATE_OUTPUTS = False |
|
|
|
|
joined_tx = tx_from_any(rawtx1) |
|
|
|
|
joined_tx.join_with_other_psbt(tx_from_any(rawtx2), config=self.config) |
|
|
|
|
self.assertEqual(4, len(joined_tx.outputs())) |
|
|
|
|
self.assertEqual("70736274ff0100d802000000029264597cffcce8f0c17b16a02adca7a95ae90f2ea51bd4b4df60c76dfe86686e0000000000fdffffffa4c6da70097e1bfbbcba0edad4ba1143295300b60851aa6c4916a0b32381bf7f0000000000fdffffff04a08601000000000016001458aee0f1201d1ae12dbd241209bbe92ed45e39b6400d03000000000016001458aee0f1201d1ae12dbd241209bbe92ed45e39b6108c0400000000001600144e1b662f616fe134430054e29295ea6e5c18f173108c040000000000160014fac4435311276a6cfda5681cfb02252acdd14c3fc2ad26000001011f20a1070000000000160014542266519a44eb9b903761d40c6fe1055d33fa050100de02000000000101013548c9019890e27ce9e58766de05f18ea40ede70751fb6cd7a3a1715ece0a30100000000fdffffff0220a1070000000000160014542266519a44eb9b903761d40c6fe1055d33fa05485a080000000000160014bc69f7d82c403a9f35dfb6d1a4531d6b19cab0e3024730440220346b200f21c3024e1d51fb4ecddbdbd68bd24ae7b9dfd501519f6dcbeb7c052402200617e3ce7b0eb308e30caf23894fb0388b68fb1c15dd0681dd13ae5e735f148101210360d0c9ef15b8b6a16912d341ad218a4e4e4e07e9347f4a2dbc7ca8d974f8bc9ec1ad26002206029b1a61d66896486ab893741b38dbafb9673b91a82237d6e4ca0da3cda7cbeb7c101f1b48320000008000000000000000000001011f801a06000000000016001452af44a1e32754fd8d2e7c1c3cc1b305379f0b660100de020000000001018eeaf0cd7de0e0e117af1a7f2bab59b4ddfbd416ef7460b3fd42a1f7bc039cfd0000000000fdffffff02801a06000000000016001452af44a1e32754fd8d2e7c1c3cc1b305379f0b66909f0700000000001600140847a3685a3ce9911cdce3fbf33cb42edc8f6dd902473044022044d3485c09784f03cd648117ef2d4d0dabeeb2929b30f2e52c3bbd5efd1c0f820220346655235eb9fcb54b23bbf194217092cc8aa6dd33ecf018907626b90289be6801210304e06afd290a4e7a9eb008cf408a4f9b0640fd2688258b523aa3dbb236bb3f7eccad2600220602c1ed648e71f15643950b444b864ab784b9d0e31e6ca6ec7d849d3dda4d98da05101f1b4832000000800000000001000000000000220203db4846ec1841f48484590e67fcd7d1039f124a04410c5794f38ec8625329ea23101f1b483200000080010000000000000000220203aba60233db3aab45d0196cb70a22d667faa92124760700d20c953b0222ced96d101f1b483200000080010000000100000000", |
|
|
|
|
joined_tx.serialize_as_bytes().hex()) |
|
|
|
|
|
|
|
|
|
self.config.WALLET_MERGE_DUPLICATE_OUTPUTS = True |
|
|
|
|
joined_tx = tx_from_any(rawtx1) |
|
|
|
|
joined_tx.join_with_other_psbt(tx_from_any(rawtx2), config=self.config) |
|
|
|
|
self.assertEqual(3, len(joined_tx.outputs())) |
|
|
|
|
self.assertEqual("70736274ff0100b902000000029264597cffcce8f0c17b16a02adca7a95ae90f2ea51bd4b4df60c76dfe86686e0000000000fdffffffa4c6da70097e1bfbbcba0edad4ba1143295300b60851aa6c4916a0b32381bf7f0000000000fdffffff03108c0400000000001600144e1b662f616fe134430054e29295ea6e5c18f173108c040000000000160014fac4435311276a6cfda5681cfb02252acdd14c3fe09304000000000016001458aee0f1201d1ae12dbd241209bbe92ed45e39b6c2ad26000001011f20a1070000000000160014542266519a44eb9b903761d40c6fe1055d33fa050100de02000000000101013548c9019890e27ce9e58766de05f18ea40ede70751fb6cd7a3a1715ece0a30100000000fdffffff0220a1070000000000160014542266519a44eb9b903761d40c6fe1055d33fa05485a080000000000160014bc69f7d82c403a9f35dfb6d1a4531d6b19cab0e3024730440220346b200f21c3024e1d51fb4ecddbdbd68bd24ae7b9dfd501519f6dcbeb7c052402200617e3ce7b0eb308e30caf23894fb0388b68fb1c15dd0681dd13ae5e735f148101210360d0c9ef15b8b6a16912d341ad218a4e4e4e07e9347f4a2dbc7ca8d974f8bc9ec1ad26002206029b1a61d66896486ab893741b38dbafb9673b91a82237d6e4ca0da3cda7cbeb7c101f1b48320000008000000000000000000001011f801a06000000000016001452af44a1e32754fd8d2e7c1c3cc1b305379f0b660100de020000000001018eeaf0cd7de0e0e117af1a7f2bab59b4ddfbd416ef7460b3fd42a1f7bc039cfd0000000000fdffffff02801a06000000000016001452af44a1e32754fd8d2e7c1c3cc1b305379f0b66909f0700000000001600140847a3685a3ce9911cdce3fbf33cb42edc8f6dd902473044022044d3485c09784f03cd648117ef2d4d0dabeeb2929b30f2e52c3bbd5efd1c0f820220346655235eb9fcb54b23bbf194217092cc8aa6dd33ecf018907626b90289be6801210304e06afd290a4e7a9eb008cf408a4f9b0640fd2688258b523aa3dbb236bb3f7eccad2600220602c1ed648e71f15643950b444b864ab784b9d0e31e6ca6ec7d849d3dda4d98da05101f1b483200000080000000000100000000220203db4846ec1841f48484590e67fcd7d1039f124a04410c5794f38ec8625329ea23101f1b483200000080010000000000000000220203aba60233db3aab45d0196cb70a22d667faa92124760700d20c953b0222ced96d101f1b48320000008001000000010000000000", |
|
|
|
|
joined_tx.serialize_as_bytes().hex()) |
|
|
|
|
|
|
|
|
|
@mock.patch.object(wallet.Abstract_Wallet, 'save_db') |
|
|
|
|
async def test_cpfp_p2wpkh(self, mock_save_db): |
|
|
|
|
wallet = self.create_standard_wallet_from_seed('frost repair depend effort salon ring foam oak cancel receive save usage') |
|
|
|
|
@ -2117,7 +2196,7 @@ class TestWalletSending(ElectrumTestCase):
|
|
|
|
|
partial_tx2) |
|
|
|
|
|
|
|
|
|
# wallet2 gets raw partial tx1, merges it into his own tx2 |
|
|
|
|
tx2.join_with_other_psbt(tx_from_any(partial_tx1)) |
|
|
|
|
tx2.join_with_other_psbt(tx_from_any(partial_tx1), config=self.config) |
|
|
|
|
partial_tx2 = tx2.serialize_as_bytes().hex() |
|
|
|
|
self.assertEqual("70736274ff0100d80200000002e546bc0a7c9736e82a07df5c24fe6d05df58a310dc376cf09302842ca7264f930100000000fdffffffd5bd4f8ebe63f0521f94e2d174b95d4327757a7e74fda3c9ff5c08796318f8d80000000000fdffffff04988d07000000000016001453675a59be834aa6d139c3ebea56646a9b160c4cb82e0f0000000000160014250dbabd5761d7e0773d6147699938dd08ec2eb88096980000000000160014b93357242ad5a6fff8930ce9dadd8ba44a6c44498096980000000000160014e2672a59431c261903c9469aa082202f37a859a46f8518000001011fa037a000000000001600140719d12228c61cab793ecd659c09cfe565a845c30100df02000000000101d5bd4f8ebe63f0521f94e2d174b95d4327757a7e74fda3c9ff5c08796318f8d80100000000fdffffff025066350000000000160014e3aa82aa2e754507d5585c0b6db06cc0cb4927b7a037a000000000001600140719d12228c61cab793ecd659c09cfe565a845c302483045022100f42e27519bd2379c22951c16b038fa6d49164fe6802854f2fdc7ee87fe31a8bc02204ea71e9324781b44bf7fea2f318caf3bedc5b497cbd1b4313fa71f833500bcb7012103a7853e1ee02a1629c8e870ec694a1420aeb98e6f5d071815257028f62d6f784169851800220602275b4fba18bb34e5198a9cfb3e940306658839079b3bda50d504a9cf2bae36f41067f366970000008000000000010000000001011fc0d8a70000000000160014aba1c9faecc3f8882e641583e8734a3f9d01b15a0100df0200000000010162ecbac2f0c8662f53505d9410fdc56c84c5642ddbd3358d9a27d564e26731130200000000fdffffff02c0d8a70000000000160014aba1c9faecc3f8882e641583e8734a3f9d01b15ab89ed5000000000016001470afbd97b2dc351bd167f714e294b2fd3b60aedf02483045022100c93449989510e279eb14a0193d5c262ae93034b81376a1f6be259c6080d3ba5d0220536ab394f7c20f301d7ec2ef11be6e7b6d492053dce56458931c1b54218ec0fd012103b8f5a11df8e68cf335848e83a41fdad3c7413dc42148248a3799b58c93919ca010851800002202036e4d0a5fb845b2f1c3c868c2ce7212b155b73e91c05be1b7a77c48830831ba4f1067f3669700000080010000000000000000000022020200062fdea2b0a056b17fa6b91dd87f5b5d838fe1ee84d636a5022f9a340eebcc1067f3669700000080000000000000000000", |
|
|
|
|
partial_tx2) |
|
|
|
|
|