(self)
| 42 | return self.nodes[0].sendrawtransaction(tx['hex']) |
| 43 | |
| 44 | def run_test(self): |
| 45 | if self.options.segwit: |
| 46 | output_type = "p2sh-segwit" |
| 47 | else: |
| 48 | output_type = "legacy" |
| 49 | |
| 50 | # All nodes should start with 1,250 BTC: |
| 51 | starting_balance = 1250 |
| 52 | for i in range(3): |
| 53 | assert_equal(self.nodes[i].getbalance()['bitcoin'], starting_balance) |
| 54 | |
| 55 | self.nodes[0].settxfee(.001) |
| 56 | |
| 57 | node0_address1 = self.nodes[0].getnewaddress(address_type=output_type) |
| 58 | node0_txid1 = self.nodes[0].sendtoaddress(node0_address1, 1219) |
| 59 | node0_tx1 = self.nodes[0].gettransaction(node0_txid1) |
| 60 | self.nodes[0].lockunspent(False, [{"txid":node0_txid1, "vout": find_vout_for_address(self.nodes[0], node0_txid1, node0_address1)}]) |
| 61 | |
| 62 | node0_address2 = self.nodes[0].getnewaddress(address_type=output_type) |
| 63 | node0_txid2 = self.nodes[0].sendtoaddress(node0_address2, 29) |
| 64 | node0_tx2 = self.nodes[0].gettransaction(node0_txid2) |
| 65 | |
| 66 | assert_equal(self.nodes[0].getbalance()['bitcoin'], |
| 67 | starting_balance + node0_tx1["fee"]['bitcoin'] + node0_tx2["fee"]['bitcoin']) |
| 68 | |
| 69 | # Coins are sent to node1_address |
| 70 | node1_address = self.nodes[1].getnewaddress() |
| 71 | |
| 72 | # Send tx1, and another transaction tx2 that won't be cloned |
| 73 | txid1 = self.spend_txid(node0_txid1, find_vout_for_address(self.nodes[0], node0_txid1, node0_address1), [{node1_address: 40}]) |
| 74 | txid2 = self.spend_txid(node0_txid2, find_vout_for_address(self.nodes[0], node0_txid2, node0_address2), [{node1_address: 20}]) |
| 75 | |
| 76 | # Construct a clone of tx1, to be malleated |
| 77 | rawtx1 = self.nodes[0].getrawtransaction(txid1, 1) |
| 78 | clone_inputs = [{"txid": rawtx1["vin"][0]["txid"], "vout": rawtx1["vin"][0]["vout"], "sequence": rawtx1["vin"][0]["sequence"]}] |
| 79 | clone_outputs = [ |
| 80 | {rawtx1["vout"][0]["scriptPubKey"]["address"]: rawtx1["vout"][0]["value"]}, |
| 81 | {rawtx1["vout"][1]["scriptPubKey"]["address"]: rawtx1["vout"][1]["value"]}, |
| 82 | ] |
| 83 | assert_equal(rawtx1["vout"][2]["scriptPubKey"]["type"], "fee") |
| 84 | clone_outputs.append({"fee": rawtx1["vout"][2]["value"]}) |
| 85 | clone_locktime = rawtx1["locktime"] |
| 86 | clone_raw = self.nodes[0].createrawtransaction(clone_inputs, clone_outputs, clone_locktime) |
| 87 | |
| 88 | # createrawtransaction randomizes the order of its outputs, so swap them if necessary. |
| 89 | clone_tx = tx_from_hex(clone_raw) |
| 90 | if (rawtx1["vout"][0]["value"] == 40 and clone_tx.vout[0].nValue.getAmount() != 40*COIN or rawtx1["vout"][0]["value"] != 40 and clone_tx.vout[0].nValue.getAmount() == 40*COIN): |
| 91 | (clone_tx.vout[0], clone_tx.vout[1]) = (clone_tx.vout[1], clone_tx.vout[0]) |
| 92 | |
| 93 | # Use a different signature hash type to sign. This creates an equivalent but malleated clone. |
| 94 | # Don't send the clone anywhere yet |
| 95 | tx1_clone = self.nodes[0].signrawtransactionwithwallet(clone_tx.serialize().hex(), None, "ALL|ANYONECANPAY") |
| 96 | assert_equal(tx1_clone["complete"], True) |
| 97 | |
| 98 | # Have node0 mine a block, if requested: |
| 99 | if (self.options.mine_block): |
| 100 | self.generate(self.nodes[0], 1, sync_fun=lambda: self.sync_blocks(self.nodes[0:2])) |
| 101 |
nothing calls this directly
no test coverage detected