|
| 1 | +#!/usr/bin/env python3 |
| 2 | +# Copyright (c) 2015-2018 The Bitcoin Core developers |
| 3 | +# Distributed under the MIT software license, see the accompanying |
| 4 | +# file COPYING or http://www.opensource.org/licenses/mit-license.php. |
| 5 | +"""Test the txwitness for elements |
| 6 | +
|
| 7 | +1) Make sure python serialization stuff matches whatever the node/wallet creates, signed and unsigned |
| 8 | +2) Segwit transactions have witness data still, and is validated correctly |
| 9 | +3) Fast merkle root test? (where oh where are we going to find sha2 internals ripped open in python) |
| 10 | +4) transaction round-trips through rpc, p2p, inside and outside of blocks |
| 11 | +5) make sure non-segwit transactions have no witness data too |
| 12 | +6) If we’re not touching all other tests, we’ll need to actually copy our CTransaction python stuff directly into this test, or another adjacent file, otherwise other tests will still break |
| 13 | +7) Try to give it some bitcoin serialization transactions, make sure it fails to decode |
| 14 | +
|
| 15 | +""" |
| 16 | + |
| 17 | +from test_framework.messages import CTransaction, CBlock, ser_uint256 |
| 18 | +from test_framework.test_framework import BitcoinTestFramework |
| 19 | +from test_framework.util import assert_equal, bytes_to_hex_str, hex_str_to_bytes |
| 20 | +from test_framework import util |
| 21 | + |
| 22 | +from io import BytesIO |
| 23 | + |
| 24 | +class TxWitnessTest(BitcoinTestFramework): |
| 25 | + def set_test_params(self): |
| 26 | + self.setup_clean_chain = True |
| 27 | + self.num_nodes = 2 |
| 28 | + |
| 29 | + def assert_tx_format_also_signed(self, utxo, segwit): |
| 30 | + raw = self.nodes[0].createrawtransaction( |
| 31 | + [{"txid": utxo["txid"], "vout": utxo["vout"]}], |
| 32 | + [{self.unknown_addr: "49.9"}] |
| 33 | + ) |
| 34 | + |
| 35 | + unsigned_decoded = self.nodes[0].decoderawtransaction(raw) |
| 36 | + assert_equal(len(unsigned_decoded["vin"]), 1) |
| 37 | + assert('txinwitness' not in unsigned_decoded["vin"][0]) |
| 38 | + |
| 39 | + # Cross-check python serialization |
| 40 | + tx = CTransaction() |
| 41 | + tx.deserialize(BytesIO(hex_str_to_bytes(raw))) |
| 42 | + assert_equal(tx.vin[0].prevout.hash, int("0x"+utxo["txid"], 0)) |
| 43 | + # assert re-encoding |
| 44 | + serialized = bytes_to_hex_str(tx.serialize()) |
| 45 | + assert_equal(serialized, raw) |
| 46 | + |
| 47 | + # Now sign and repeat tests |
| 48 | + signed_raw = self.nodes[0].signrawtransactionwithwallet(raw)["hex"] |
| 49 | + signed_decoded = self.nodes[0].decoderawtransaction(signed_raw) |
| 50 | + assert_equal(len(signed_decoded["vin"]), 1) |
| 51 | + assert(("txinwitness" in signed_decoded["vin"][0]) == segwit) |
| 52 | + |
| 53 | + # Cross-check python serialization |
| 54 | + tx = CTransaction() |
| 55 | + tx.deserialize(BytesIO(hex_str_to_bytes(signed_raw))) |
| 56 | + assert_equal(tx.vin[0].prevout.hash, int("0x"+utxo["txid"], 0)) |
| 57 | + assert_equal(bytes_to_hex_str(tx.vin[0].scriptSig), signed_decoded["vin"][0]["scriptSig"]["hex"]) |
| 58 | + # test witness |
| 59 | + if segwit: |
| 60 | + wit_decoded = signed_decoded["vin"][0]["txinwitness"] |
| 61 | + for i in range(len(wit_decoded)): |
| 62 | + assert_equal(bytes_to_hex_str(tx.wit.vtxinwit[0].scriptWitness.stack[i]), wit_decoded[i]) |
| 63 | + # assert re-encoding |
| 64 | + serialized = bytes_to_hex_str(tx.serialize()) |
| 65 | + assert_equal(serialized, signed_raw) |
| 66 | + |
| 67 | + txid = self.nodes[0].sendrawtransaction(serialized) |
| 68 | + nodetx = self.nodes[0].getrawtransaction(txid, 1) |
| 69 | + assert_equal(nodetx["txid"], tx.rehash()) |
| 70 | + # cross-check wtxid report from node |
| 71 | + wtxid = bytes_to_hex_str(ser_uint256(tx.calc_sha256(True))[::-1]) |
| 72 | + assert_equal(nodetx["wtxid"], wtxid) |
| 73 | + assert_equal(nodetx["hash"], wtxid) |
| 74 | + |
| 75 | + # witness hash stuff |
| 76 | + assert_equal(nodetx["withash"], bytes_to_hex_str(ser_uint256(tx.calc_witness_hash())[::-1])) |
| 77 | + return (txid, wtxid) |
| 78 | + |
| 79 | + def test_transaction_serialization(self): |
| 80 | + legacy_addr = self.nodes[0].getnewaddress("", "legacy") |
| 81 | + p2sh_addr = self.nodes[0].getnewaddress("", "p2sh-segwit") |
| 82 | + bech32_addr = self.nodes[0].getnewaddress("", "bech32") |
| 83 | + self.unknown_addr = self.nodes[1].getnewaddress() |
| 84 | + |
| 85 | + # directly seed types of utxos required |
| 86 | + self.nodes[0].generatetoaddress(1, legacy_addr) |
| 87 | + self.nodes[0].generatetoaddress(1, p2sh_addr) |
| 88 | + self.nodes[0].generatetoaddress(1, bech32_addr) |
| 89 | + self.nodes[0].generatetoaddress(101, self.unknown_addr) |
| 90 | + |
| 91 | + # grab utxos filtering by age |
| 92 | + legacy_utxo = self.nodes[0].listunspent(104, 104)[0] |
| 93 | + p2sh_utxo = self.nodes[0].listunspent(103, 103)[0] |
| 94 | + bech32_utxo = self.nodes[0].listunspent(102, 102)[0] |
| 95 | + |
| 96 | + submitted_txids = [] |
| 97 | + self.log.info("Testing legacy UTXO") |
| 98 | + submitted_txids.append(self.assert_tx_format_also_signed(legacy_utxo, segwit=False)) |
| 99 | + self.log.info("Testing p2sh UTXO") |
| 100 | + submitted_txids.append(self.assert_tx_format_also_signed(p2sh_utxo, segwit=True)) |
| 101 | + self.log.info("Testing bech32 UTXO") |
| 102 | + submitted_txids.append(self.assert_tx_format_also_signed(bech32_utxo, segwit=True)) |
| 103 | + |
| 104 | + blockhash = self.nodes[0].generate(1)[0] |
| 105 | + hexblock = self.nodes[0].getblock(blockhash, 0) |
| 106 | + block_details = self.nodes[0].getblock(blockhash, 2) |
| 107 | + block = CBlock() |
| 108 | + block.deserialize(BytesIO(hex_str_to_bytes(hexblock))) |
| 109 | + assert(len(block.vtx) == len(submitted_txids) + 1) |
| 110 | + assert_equal(len(block_details["tx"]), len(block.vtx)) |
| 111 | + for tx1, tx2 in zip(block.vtx[1:], block_details["tx"][1:]): |
| 112 | + # no tuple wildcard, just re-used tx2 on first one |
| 113 | + assert((tx1.rehash(), tx2["wtxid"]) in submitted_txids) |
| 114 | + assert((tx2["txid"], tx2["hash"]) in submitted_txids) |
| 115 | + assert((tx2["txid"], tx2["wtxid"]) in submitted_txids) |
| 116 | + block.rehash() |
| 117 | + assert_equal(block.hash, self.nodes[0].getbestblockhash()) |
| 118 | + |
| 119 | + |
| 120 | + def run_test(self): |
| 121 | + util.node_fastmerkle = self.nodes[0] |
| 122 | + self.test_transaction_serialization() |
| 123 | + |
| 124 | + |
| 125 | + |
| 126 | + |
| 127 | + |
| 128 | + |
| 129 | + |
| 130 | +if __name__ == '__main__': |
| 131 | + TxWitnessTest().main() |
0 commit comments