Changeset View
Changeset View
Standalone View
Standalone View
test/functional/wallet_txn_clone.py
#!/usr/bin/env python3 | #!/usr/bin/env python3 | ||||
# Copyright (c) 2014-2019 The Bitcoin Core developers | # Copyright (c) 2014-2019 The Bitcoin Core developers | ||||
# Distributed under the MIT software license, see the accompanying | # Distributed under the MIT software license, see the accompanying | ||||
# file COPYING or http://www.opensource.org/licenses/mit-license.php. | # file COPYING or http://www.opensource.org/licenses/mit-license.php. | ||||
"""Test the wallet accounts properly when there are cloned transactions with malleated scriptsigs.""" | """Test the wallet accounts properly when there are cloned transactions with malleated scriptsigs.""" | ||||
import io | |||||
from test_framework.test_framework import BitcoinTestFramework | from test_framework.test_framework import BitcoinTestFramework | ||||
from test_framework.util import ( | from test_framework.util import ( | ||||
assert_equal, | assert_equal, | ||||
connect_nodes, | connect_nodes, | ||||
disconnect_nodes, | disconnect_nodes, | ||||
) | ) | ||||
from test_framework.messages import CTransaction, COIN | |||||
class TxnMallTest(BitcoinTestFramework): | class TxnMallTest(BitcoinTestFramework): | ||||
def set_test_params(self): | def set_test_params(self): | ||||
self.num_nodes = 4 | self.num_nodes = 4 | ||||
self.extra_args = [["-noparkdeepreorg"], ["-noparkdeepreorg"], [], []] | self.extra_args = [["-noparkdeepreorg"], ["-noparkdeepreorg"], [], []] | ||||
self.supports_cli = False | self.supports_cli = False | ||||
▲ Show 20 Lines • Show All 46 Lines • ▼ Show 20 Lines | def run_test(self): | ||||
"vout": rawtx1["vin"][0]["vout"], | "vout": rawtx1["vin"][0]["vout"], | ||||
"sequence": rawtx1["vin"][0]["sequence"]}] | "sequence": rawtx1["vin"][0]["sequence"]}] | ||||
clone_outputs = {rawtx1["vout"][0]["scriptPubKey"]["addresses"][0]: rawtx1["vout"][0]["value"], | clone_outputs = {rawtx1["vout"][0]["scriptPubKey"]["addresses"][0]: rawtx1["vout"][0]["value"], | ||||
rawtx1["vout"][1]["scriptPubKey"]["addresses"][0]: rawtx1["vout"][1]["value"]} | rawtx1["vout"][1]["scriptPubKey"]["addresses"][0]: rawtx1["vout"][1]["value"]} | ||||
clone_locktime = rawtx1["locktime"] | clone_locktime = rawtx1["locktime"] | ||||
clone_raw = self.nodes[0].createrawtransaction( | clone_raw = self.nodes[0].createrawtransaction( | ||||
clone_inputs, clone_outputs, clone_locktime) | clone_inputs, clone_outputs, clone_locktime) | ||||
# createrawtransaction randomizes the order of its outputs, so swap them if necessary. | # createrawtransaction randomizes the order of its outputs, so swap | ||||
# output 0 is at version+#inputs+input+sigstub+sequence+#outputs | # them if necessary. | ||||
# 40 BCH serialized is 00286bee00000000 | clone_tx = CTransaction() | ||||
pos0 = 2 * (4 + 1 + 36 + 1 + 4 + 1) | clone_tx.deserialize(io.BytesIO(bytes.fromhex(clone_raw))) | ||||
hex40 = "00286bee00000000" | if (rawtx1["vout"][0]["value"] == 40 and | ||||
output_len = 16 + 2 + 2 * \ | clone_tx.vout[0].nValue != 40 * COIN or | ||||
int("0x" + clone_raw[pos0 + 16: pos0 + 16 + 2], 0) | rawtx1["vout"][0]["value"] != 40 and | ||||
if (rawtx1["vout"][0]["value"] == 40 and clone_raw[pos0: pos0 + 16] != hex40 or | clone_tx.vout[0].nValue == 40 * COIN): | ||||
rawtx1["vout"][0]["value"] != 40 and clone_raw[pos0: pos0 + 16] == hex40): | (clone_tx.vout[0], clone_tx.vout[1]) = (clone_tx.vout[1], | ||||
output0 = clone_raw[pos0: pos0 + output_len] | clone_tx.vout[0]) | ||||
output1 = clone_raw[pos0 + output_len: pos0 + 2 * output_len] | |||||
clone_raw = clone_raw[:pos0] + output1 + \ | |||||
output0 + clone_raw[pos0 + 2 * output_len:] | |||||
# Use a different signature hash type to sign. This creates an equivalent but malleated clone. | # Use a different signature hash type to sign. This creates an equivalent but malleated clone. | ||||
# Don't send the clone anywhere yet | # Don't send the clone anywhere yet | ||||
tx1_clone = self.nodes[0].signrawtransactionwithwallet( | tx1_clone = self.nodes[0].signrawtransactionwithwallet( | ||||
clone_raw, None, "ALL|FORKID|ANYONECANPAY") | clone_tx.serialize().hex(), None, "ALL|FORKID|ANYONECANPAY") | ||||
assert_equal(tx1_clone["complete"], True) | assert_equal(tx1_clone["complete"], True) | ||||
# Have node0 mine a block, if requested: | # Have node0 mine a block, if requested: | ||||
if (self.options.mine_block): | if (self.options.mine_block): | ||||
self.nodes[0].generate(1) | self.nodes[0].generate(1) | ||||
self.sync_blocks(self.nodes[0:2]) | self.sync_blocks(self.nodes[0:2]) | ||||
tx1 = self.nodes[0].gettransaction(txid1) | tx1 = self.nodes[0].gettransaction(txid1) | ||||
▲ Show 20 Lines • Show All 52 Lines • Show Last 20 Lines |