Ejemplo n.º 1
0
 def __init__(self, tx=CTransaction(), n=-1):
     self.tx = tx
     # the output we're spending
     self.n = n
Ejemplo n.º 2
0
    def test_doublespend_tree(self):
        """Doublespend of a big tree of transactions"""

        initial_nValue = 50 * COIN
        tx0_outpoint = make_utxo(self.nodes[0], initial_nValue)

        def branch(prevout,
                   initial_value,
                   max_txs,
                   tree_width=5,
                   fee=0.01 * COIN,
                   _total_txs=None):
            if _total_txs is None:
                _total_txs = [0]
            if _total_txs[0] >= max_txs:
                return

            txout_value = (initial_value - fee) // tree_width
            if txout_value < fee:
                return

            vout = [
                CTxOut(txout_value, CScript([i + 1]))
                for i in range(tree_width)
            ]
            tx = CTransaction()
            tx.vin = [CTxIn(prevout, nSequence=0)]
            tx.vout = vout
            tx_hex = txToHex(tx)

            assert len(tx.serialize()) < 100000
            txid = self.nodes[0].sendrawtransaction(tx_hex, 0)
            yield tx
            _total_txs[0] += 1

            txid = int(txid, 16)

            for i, txout in enumerate(tx.vout):
                for x in branch(COutPoint(txid, i),
                                txout_value,
                                max_txs,
                                tree_width=tree_width,
                                fee=fee,
                                _total_txs=_total_txs):
                    yield x

        fee = int(0.01 * COIN)
        n = MAX_REPLACEMENT_LIMIT
        tree_txs = list(branch(tx0_outpoint, initial_nValue, n, fee=fee))
        assert_equal(len(tree_txs), n)

        # Attempt double-spend, will fail because too little fee paid
        dbl_tx = CTransaction()
        dbl_tx.vin = [CTxIn(tx0_outpoint, nSequence=0)]
        dbl_tx.vout = [CTxOut(initial_nValue - fee * n, DUMMY_P2WPKH_SCRIPT)]
        dbl_tx_hex = txToHex(dbl_tx)
        # This will raise an exception due to insufficient fee
        assert_raises_rpc_error(-26, "insufficient fee",
                                self.nodes[0].sendrawtransaction, dbl_tx_hex,
                                0)

        # 1 BTC fee is enough
        dbl_tx = CTransaction()
        dbl_tx.vin = [CTxIn(tx0_outpoint, nSequence=0)]
        dbl_tx.vout = [
            CTxOut(initial_nValue - fee * n - 1 * COIN, DUMMY_P2WPKH_SCRIPT)
        ]
        dbl_tx_hex = txToHex(dbl_tx)
        self.nodes[0].sendrawtransaction(dbl_tx_hex, 0)

        mempool = self.nodes[0].getrawmempool()

        for tx in tree_txs:
            tx.rehash()
            assert tx.hash not in mempool

        # Try again, but with more total transactions than the "max txs
        # double-spent at once" anti-DoS limit.
        for n in (MAX_REPLACEMENT_LIMIT + 1, MAX_REPLACEMENT_LIMIT * 2):
            fee = int(0.01 * COIN)
            tx0_outpoint = make_utxo(self.nodes[0], initial_nValue)
            tree_txs = list(branch(tx0_outpoint, initial_nValue, n, fee=fee))
            assert_equal(len(tree_txs), n)

            dbl_tx = CTransaction()
            dbl_tx.vin = [CTxIn(tx0_outpoint, nSequence=0)]
            dbl_tx.vout = [
                CTxOut(initial_nValue - 2 * fee * n, DUMMY_P2WPKH_SCRIPT)
            ]
            dbl_tx_hex = txToHex(dbl_tx)
            # This will raise an exception
            assert_raises_rpc_error(-26, "too many potential replacements",
                                    self.nodes[0].sendrawtransaction,
                                    dbl_tx_hex, 0)

            for tx in tree_txs:
                tx.rehash()
                self.nodes[0].getrawtransaction(tx.hash)
Ejemplo n.º 3
0
    def test_independent(self):
        self.log.info("Test multiple independent transactions in a package")
        node = self.nodes[0]
        # For independent transactions, order doesn't matter.
        self.assert_testres_equal(self.independent_txns_hex,
                                  self.independent_txns_testres)

        self.log.info(
            "Test an otherwise valid package with an extra garbage tx appended"
        )
        garbage_tx = node.createrawtransaction([{
            "txid": "00" * 32,
            "vout": 5
        }], {self.address: 1})
        tx = CTransaction()
        tx.deserialize(BytesIO(hex_str_to_bytes(garbage_tx)))
        # Only the txid and wtxids are returned because validation is incomplete for the independent txns.
        # Package validation is atomic: if the node cannot find a UTXO for any single tx in the package,
        # it terminates immediately to avoid unnecessary, expensive signature verification.
        package_bad = self.independent_txns_hex + [garbage_tx]
        testres_bad = self.independent_txns_testres_blank + [
            {
                "txid": tx.rehash(),
                "wtxid": tx.getwtxid(),
                "allowed": False,
                "reject-reason": "missing-inputs"
            }
        ]
        self.assert_testres_equal(package_bad, testres_bad)

        self.log.info(
            "Check testmempoolaccept tells us when some transactions completed validation successfully"
        )
        coin = self.coins.pop()
        tx_bad_sig_hex = node.createrawtransaction(
            [{
                "txid": coin["txid"],
                "vout": 0
            }], {self.address: coin["amount"] - Decimal("0.0001")})
        tx_bad_sig = CTransaction()
        tx_bad_sig.deserialize(BytesIO(hex_str_to_bytes(tx_bad_sig_hex)))
        testres_bad_sig = node.testmempoolaccept(self.independent_txns_hex +
                                                 [tx_bad_sig_hex])
        # By the time the signature for the last transaction is checked, all the other transactions
        # have been fully validated, which is why the node returns full validation results for all
        # transactions here but empty results in other cases.
        assert_equal(
            testres_bad_sig, self.independent_txns_testres + [{
                "txid":
                tx_bad_sig.rehash(),
                "wtxid":
                tx_bad_sig.getwtxid(),
                "allowed":
                False,
                "reject-reason":
                "mandatory-script-verify-flag-failed (Operation not valid with the current stack size)"
            }])

        self.log.info(
            "Check testmempoolaccept reports txns in packages that exceed max feerate"
        )
        coin = self.coins.pop()
        tx_high_fee_raw = node.createrawtransaction(
            [{
                "txid": coin["txid"],
                "vout": 0
            }], {self.address: coin["amount"] - Decimal("0.999")})
        tx_high_fee_signed = node.signrawtransactionwithkey(
            hexstring=tx_high_fee_raw, privkeys=self.privkeys)
        assert tx_high_fee_signed["complete"]
        tx_high_fee = CTransaction()
        tx_high_fee.deserialize(
            BytesIO(hex_str_to_bytes(tx_high_fee_signed["hex"])))
        testres_high_fee = node.testmempoolaccept([tx_high_fee_signed["hex"]])
        assert_equal(testres_high_fee, [{
            "txid": tx_high_fee.rehash(),
            "wtxid": tx_high_fee.getwtxid(),
            "allowed": False,
            "reject-reason": "max-fee-exceeded"
        }])
        package_high_fee = [tx_high_fee_signed["hex"]
                            ] + self.independent_txns_hex
        testres_package_high_fee = node.testmempoolaccept(package_high_fee)
        assert_equal(testres_package_high_fee,
                     testres_high_fee + self.independent_txns_testres_blank)
    def test_compactblock_construction(self, test_node, use_witness_address=True):
        version = test_node.cmpct_version
        node = self.nodes[0]
        # Generate a bunch of transactions.
        node.generate(101)
        num_transactions = 25
        address = node.getnewaddress()

        segwit_tx_generated = False
        for i in range(num_transactions):
            txid = node.sendtoaddress(address, 0.1)
            hex_tx = node.gettransaction(txid)["hex"]
            tx = FromHex(CTransaction(), hex_tx)
            if not tx.wit.is_null():
                segwit_tx_generated = True

        if use_witness_address:
            assert segwit_tx_generated  # check that our test is not broken

        # Wait until we've seen the block announcement for the resulting tip
        tip = int(node.getbestblockhash(), 16)
        test_node.wait_for_block_announcement(tip)

        # Make sure we will receive a fast-announce compact block
        self.request_cb_announcements(test_node)

        # Now mine a block, and look at the resulting compact block.
        test_node.clear_block_announcement()
        block_hash = int(node.generate(1)[0], 16)

        # Store the raw block in our internal format.
        block = FromHex(CBlock(), node.getblock("%064x" % block_hash, False))
        for tx in block.vtx:
            tx.calc_sha256()
        block.rehash()

        # Wait until the block was announced (via compact blocks)
        wait_until(test_node.received_block_announcement, timeout=30, lock=mininode_lock)

        # Now fetch and check the compact block
        header_and_shortids = None
        with mininode_lock:
            assert "cmpctblock" in test_node.last_message
            # Convert the on-the-wire representation to absolute indexes
            header_and_shortids = HeaderAndShortIDs(test_node.last_message["cmpctblock"].header_and_shortids)
        self.check_compactblock_construction_from_block(version, header_and_shortids, block_hash, block)

        # Now fetch the compact block using a normal non-announce getdata
        with mininode_lock:
            test_node.clear_block_announcement()
            inv = CInv(4, block_hash)  # 4 == "CompactBlock"
            test_node.send_message(msg_getdata([inv]))

        wait_until(test_node.received_block_announcement, timeout=30, lock=mininode_lock)

        # Now fetch and check the compact block
        header_and_shortids = None
        with mininode_lock:
            assert "cmpctblock" in test_node.last_message
            # Convert the on-the-wire representation to absolute indexes
            header_and_shortids = HeaderAndShortIDs(test_node.last_message["cmpctblock"].header_and_shortids)
        self.check_compactblock_construction_from_block(version, header_and_shortids, block_hash, block)
Ejemplo n.º 5
0
    def run_test(self):
        # Mine some coins
        self.nodes[0].generate(110)

        # Get some addresses from the two nodes
        addr1 = [self.nodes[1].getnewaddress() for i in range(3)]
        addr2 = [self.nodes[2].getnewaddress() for i in range(3)]
        addrs = addr1 + addr2

        # Send 1 + 0.5 coin to each address
        [self.nodes[0].sendtoaddress(addr, 1.0) for addr in addrs]
        [self.nodes[0].sendtoaddress(addr, 0.5) for addr in addrs]

        self.nodes[0].generate(1)
        self.sync_all()

        # For each node, send 0.2 coins back to 0;
        # - node[1] should pick one 0.5 UTXO and leave the rest
        # - node[2] should pick one (1.0 + 0.5) UTXO group corresponding to a
        #   given address, and leave the rest
        txid1 = self.nodes[1].sendtoaddress(self.nodes[0].getnewaddress(), 0.2)
        tx1 = self.nodes[1].getrawtransaction(txid1, True)
        # txid1 should have 1 input and 2 outputs
        assert_equal(1, len(tx1["vin"]))
        assert_equal(2, len(tx1["vout"]))
        # one output should be 0.2, the other should be ~0.3
        v = [vout["value"] for vout in tx1["vout"]]
        v.sort()
        assert_approx(v[0], 0.2)
        assert_approx(v[1], 0.3, 0.0001)

        txid2 = self.nodes[2].sendtoaddress(self.nodes[0].getnewaddress(), 0.2)
        tx2 = self.nodes[2].getrawtransaction(txid2, True)
        # txid2 should have 2 inputs and 2 outputs
        assert_equal(2, len(tx2["vin"]))
        assert_equal(2, len(tx2["vout"]))
        # one output should be 0.2, the other should be ~1.3
        v = [vout["value"] for vout in tx2["vout"]]
        v.sort()
        assert_approx(v[0], 0.2)
        assert_approx(v[1], 1.3, 0.0001)

        # Empty out node2's wallet
        self.nodes[2].sendtoaddress(address=self.nodes[0].getnewaddress(),
                                    amount=self.nodes[2].getbalance(),
                                    subtractfeefromamount=True)
        self.sync_all()
        self.nodes[0].generate(1)

        # Fill node2's wallet with 10000 outputs corresponding to the same
        # scriptPubKey
        for i in range(5):
            raw_tx = self.nodes[0].createrawtransaction([{
                "txid": "0" * 64,
                "vout": 0
            }], [{
                addr2[0]: 0.05
            }])
            tx = FromHex(CTransaction(), raw_tx)
            tx.vin = []
            tx.vout = [tx.vout[0]] * 2000
            funded_tx = self.nodes[0].fundrawtransaction(ToHex(tx))
            signed_tx = self.nodes[0].signrawtransactionwithwallet(
                funded_tx['hex'])
            self.nodes[0].sendrawtransaction(signed_tx['hex'])
            self.nodes[0].generate(1)

        self.sync_all()

        # Check that we can create a transaction that only requires ~100 of our
        # utxos, without pulling in all outputs and creating a transaction that
        # is way too big.
        assert self.nodes[2].sendtoaddress(address=addr2[0], amount=5)
Ejemplo n.º 6
0
    def run_test(self):
        node = self.nodes[0]  # convenience reference to the node
        self.address = node.getnewaddress()
        node.add_p2p_connection(P2PDataStore())
        node.p2p.wait_for_getheaders(timeout=5)
        self.address = self.nodes[0].getnewaddress()

        self.log.info("Test starting...")

        #generate 10 blocks for coinbase outputs
        coinbase_txs = []
        for i in range(1, 10):
            height = node.getblockcount() + 1
            coinbase_tx = create_coinbase(height, self.coinbase_pubkey)
            coinbase_txs.append(coinbase_tx)
            tip = node.getbestblockhash()
            block_time = node.getblockheader(tip)["mediantime"] + 1
            block = create_block(int(tip, 16), coinbase_tx, block_time)
            block.solve(self.signblockprivkey)
            tip = block.hash

            node.p2p.send_and_ping(msg_block(block))
            assert_equal(node.getbestblockhash(), tip)

        change_script = CScript([self.coinbase_pubkey, OP_CHECKSIG])
        burn_script = CScript([hex_str_to_bytes(self.pubkeys[1]), OP_CHECKSIG])

        #TxSuccess1 - coinbaseTx1 - issue 100 REISSUABLE  + 30     (UTXO-1,2)
        colorId_reissuable = colorIdReissuable(coinbase_txs[0].vout[0].scriptPubKey)
        script_reissuable = CP2PHK_script(colorId = colorId_reissuable, pubkey = self.pubkeys[0])
        script_transfer_reissuable = CP2PHK_script(colorId = colorId_reissuable, pubkey = self.pubkeys[1])

        txSuccess1 = CTransaction()
        txSuccess1.vin.append(CTxIn(COutPoint(coinbase_txs[0].malfixsha256, 0), b""))
        txSuccess1.vout.append(CTxOut(100, script_reissuable))
        txSuccess1.vout.append(CTxOut(30 * COIN, CScript([self.coinbase_pubkey, OP_CHECKSIG])))
        sig_hash, err = SignatureHash(coinbase_txs[0].vout[0].scriptPubKey, txSuccess1, 0, SIGHASH_ALL)
        signature = self.coinbase_key.sign(sig_hash) + b'\x01'  # 0x1 is SIGHASH_ALL
        txSuccess1.vin[0].scriptSig = CScript([signature])
        txSuccess1.rehash()

        test_transaction_acceptance(node, txSuccess1, accepted=True)
        tx_info = node.getrawtransaction(txSuccess1.hashMalFix, 1)
        assert_equal(tx_info['vout'][0]['token'], bytes_to_hex_str(colorId_reissuable))
        assert_equal(tx_info['vout'][0]['value'], 100)

        #TxSuccess2 - (UTXO-2)    - issue 100 NON-REISSUABLE       (UTXO-3)
        colorId_nonreissuable = colorIdNonReissuable(COutPoint(txSuccess1.malfixsha256, 1).serialize())
        script_nonreissuable = CP2PHK_script(colorId = colorId_nonreissuable, pubkey = self.pubkeys[0])
        script_transfer_nonreissuable = CP2PHK_script(colorId = colorId_nonreissuable, pubkey = self.pubkeys[1])

        txSuccess2 = CTransaction()
        txSuccess2.vin.append(CTxIn(COutPoint(txSuccess1.malfixsha256, 1), b""))
        txSuccess2.vout.append(CTxOut(100, script_nonreissuable))
        sig_hash, err = SignatureHash(txSuccess1.vout[1].scriptPubKey, txSuccess2, 0, SIGHASH_ALL)
        signature = self.coinbase_key.sign(sig_hash) + b'\x01'
        txSuccess2.vin[0].scriptSig = CScript([signature])
        txSuccess2.rehash()

        test_transaction_acceptance(node, txSuccess2, accepted=True)
        tx_info = node.getrawtransaction(txSuccess2.hashMalFix, 1)
        assert_equal(tx_info['vout'][0]['token'], bytes_to_hex_str(colorId_nonreissuable))
        assert_equal(tx_info['vout'][0]['value'], 100)

        #TxSuccess3 - coinbaseTx2 - issue 1 NFT                    (UTXO-4)
        colorId_nft = colorIdNFT(COutPoint(coinbase_txs[1].malfixsha256, 0).serialize())
        script_nft = CP2PHK_script(colorId = colorId_nft, pubkey = self.pubkeys[0])
        script_transfer_nft = CP2PHK_script(colorId = colorId_nft, pubkey = self.pubkeys[0])

        txSuccess3 = CTransaction()
        txSuccess3.vin.append(CTxIn(COutPoint(coinbase_txs[1].malfixsha256, 0), b""))
        txSuccess3.vout.append(CTxOut(1, script_nft))
        sig_hash, err = SignatureHash(coinbase_txs[1].vout[0].scriptPubKey, txSuccess3, 0, SIGHASH_ALL)
        signature = self.coinbase_key.sign(sig_hash) + b'\x01'
        txSuccess3.vin[0].scriptSig = CScript([signature])
        txSuccess3.rehash()

        test_transaction_acceptance(node, txSuccess3, accepted=True)
        tx_info = node.getrawtransaction(txSuccess3.hashMalFix, 1)
        assert_equal(tx_info['vout'][0]['token'], bytes_to_hex_str(colorId_nft))
        assert_equal(tx_info['vout'][0]['value'], 1)

        #TxFailure4 - (UTXO-1)    - split REISSUABLE - 25 + 75     (UTXO-5,6)
        #           - (UTXO-3)    - split NON-REISSUABLE - 40 + 60 (UTXO-7,8)
        #           - coinbaseTx3 - issue 100 REISSUABLE           (UTXO-9)
        TxFailure4 = CTransaction()
        TxFailure4.vin.append(CTxIn(COutPoint(txSuccess1.malfixsha256, 0), b""))
        TxFailure4.vin.append(CTxIn(COutPoint(txSuccess2.malfixsha256, 0), b""))
        TxFailure4.vin.append(CTxIn(COutPoint(coinbase_txs[2].malfixsha256, 0), b""))
        TxFailure4.vout.append(CTxOut(25, script_reissuable))
        TxFailure4.vout.append(CTxOut(75, script_reissuable))
        TxFailure4.vout.append(CTxOut(40, script_nonreissuable))
        TxFailure4.vout.append(CTxOut(60, script_nonreissuable))
        TxFailure4.vout.append(CTxOut(100, script_reissuable))
        sig_hash, err = SignatureHash(txSuccess1.vout[0].scriptPubKey, TxFailure4, 0, SIGHASH_ALL)
        signature = self.privkeys[0].sign(sig_hash) + b'\x01'
        TxFailure4.vin[0].scriptSig = CScript([signature, hex_str_to_bytes(self.pubkeys[0])])
        sig_hash, err = SignatureHash(txSuccess2.vout[0].scriptPubKey, TxFailure4, 1, SIGHASH_ALL)
        signature = self.privkeys[0].sign(sig_hash) + b'\x01'
        TxFailure4.vin[1].scriptSig = CScript([signature, hex_str_to_bytes(self.pubkeys[0])])
        sig_hash, err = SignatureHash(coinbase_txs[2].vout[0].scriptPubKey, TxFailure4, 2, SIGHASH_ALL)
        signature = self.coinbase_key.sign(sig_hash) + b'\x01'
        TxFailure4.vin[2].scriptSig = CScript([signature])
        TxFailure4.rehash()

        test_transaction_acceptance(node, TxFailure4, accepted=False, reason=b"bad-txns-token-balance")

        #TxSuccess4 - (UTXO-1)    - split REISSUABLE - 25 + 75     (UTXO-5,6)
        #           - (UTXO-3)    - split NON-REISSUABLE - 40 + 60 (UTXO-7,8)
        txSuccess4 = CTransaction()
        txSuccess4.vin.append(CTxIn(COutPoint(txSuccess1.malfixsha256, 0), b""))
        txSuccess4.vin.append(CTxIn(COutPoint(txSuccess2.malfixsha256, 0), b""))
        txSuccess4.vin.append(CTxIn(COutPoint(coinbase_txs[2].malfixsha256, 0), b""))
        txSuccess4.vout.append(CTxOut(25, script_reissuable))
        txSuccess4.vout.append(CTxOut(75, script_reissuable))
        txSuccess4.vout.append(CTxOut(40, script_nonreissuable))
        txSuccess4.vout.append(CTxOut(60, script_nonreissuable))
        sig_hash, err = SignatureHash(txSuccess1.vout[0].scriptPubKey, txSuccess4, 0, SIGHASH_ALL)
        signature = self.privkeys[0].sign(sig_hash) + b'\x01'
        txSuccess4.vin[0].scriptSig = CScript([signature, hex_str_to_bytes(self.pubkeys[0])])
        sig_hash, err = SignatureHash(txSuccess2.vout[0].scriptPubKey, txSuccess4, 1, SIGHASH_ALL)
        signature = self.privkeys[0].sign(sig_hash) + b'\x01'
        txSuccess4.vin[1].scriptSig = CScript([signature, hex_str_to_bytes(self.pubkeys[0])])
        sig_hash, err = SignatureHash(coinbase_txs[2].vout[0].scriptPubKey, txSuccess4, 2, SIGHASH_ALL)
        signature = self.coinbase_key.sign(sig_hash) + b'\x01'
        txSuccess4.vin[2].scriptSig = CScript([signature])
        txSuccess4.rehash()

        test_transaction_acceptance(node, txSuccess4, accepted=True)

        #TxFailure5 - (UTXO-6)    - split REISSUABLE(75)           (UTXO-10,11)
        #           - (UTXO-7)    - split NON-REISSUABLE(40)       (UTXO-12)
        #           - (UTXO-4)    - split NFT                      (UTXO-13)
        #           - coinbaseTx4
        TxFailure5 = CTransaction()
        TxFailure5.vin.append(CTxIn(COutPoint(txSuccess4.malfixsha256, 1), b""))
        TxFailure5.vin.append(CTxIn(COutPoint(txSuccess4.malfixsha256, 2), b""))
        TxFailure5.vin.append(CTxIn(COutPoint(txSuccess3.malfixsha256, 0), b""))
        TxFailure5.vin.append(CTxIn(COutPoint(coinbase_txs[3].malfixsha256, 0), b""))
        TxFailure5.vout.append(CTxOut(35, script_reissuable))
        TxFailure5.vout.append(CTxOut(40, script_reissuable))
        TxFailure5.vout.append(CTxOut(20, script_nonreissuable))
        TxFailure5.vout.append(CTxOut(20, script_nonreissuable))
        TxFailure5.vout.append(CTxOut(1, script_nft))
        TxFailure5.vout.append(CTxOut(1, script_nft))
        sig_hash, err = SignatureHash(txSuccess4.vout[1].scriptPubKey, TxFailure5, 0, SIGHASH_ALL)
        signature = self.privkeys[0].sign(sig_hash) + b'\x01'
        TxFailure5.vin[0].scriptSig = CScript([signature, hex_str_to_bytes(self.pubkeys[0])])
        sig_hash, err = SignatureHash(txSuccess4.vout[2].scriptPubKey, TxFailure5, 1, SIGHASH_ALL)
        signature = self.privkeys[0].sign(sig_hash) + b'\x01'
        TxFailure5.vin[1].scriptSig = CScript([signature, hex_str_to_bytes(self.pubkeys[0])])
        sig_hash, err = SignatureHash(txSuccess3.vout[0].scriptPubKey, TxFailure5, 2, SIGHASH_ALL)
        signature = self.privkeys[0].sign(sig_hash) + b'\x01'
        TxFailure5.vin[2].scriptSig = CScript([signature, hex_str_to_bytes(self.pubkeys[0])])
        sig_hash, err = SignatureHash(coinbase_txs[3].vout[0].scriptPubKey, TxFailure5, 3, SIGHASH_ALL)
        signature = self.coinbase_key.sign(sig_hash) + b'\x01'
        TxFailure5.vin[3].scriptSig = CScript([signature])
        TxFailure5.rehash()

        test_transaction_acceptance(node, TxFailure5, accepted=False, reason=b"bad-txns-token-balance")

        #txSuccess5 - (UTXO-6)    - split REISSUABLE(75)           (UTXO-10,11)
        #           - (UTXO-7)    - split NON-REISSUABLE(40)       (UTXO-12)
        #           - (UTXO-4)    - transfer NFT                      (UTXO-13)
        #           - coinbaseTx4
        txSuccess5 = CTransaction()
        txSuccess5.vin.append(CTxIn(COutPoint(txSuccess4.malfixsha256, 1), b""))
        txSuccess5.vin.append(CTxIn(COutPoint(txSuccess4.malfixsha256, 2), b""))
        txSuccess5.vin.append(CTxIn(COutPoint(txSuccess3.malfixsha256, 0), b""))
        txSuccess5.vin.append(CTxIn(COutPoint(coinbase_txs[3].malfixsha256, 0), b""))
        txSuccess5.vout.append(CTxOut(35, script_reissuable))
        txSuccess5.vout.append(CTxOut(40, script_reissuable))
        txSuccess5.vout.append(CTxOut(20, script_nonreissuable))
        txSuccess5.vout.append(CTxOut(20, script_nonreissuable))
        txSuccess5.vout.append(CTxOut(1, script_nft))
        sig_hash, err = SignatureHash(txSuccess4.vout[1].scriptPubKey, txSuccess5, 0, SIGHASH_ALL)
        signature = self.privkeys[0].sign(sig_hash) + b'\x01'
        txSuccess5.vin[0].scriptSig = CScript([signature, hex_str_to_bytes(self.pubkeys[0])])
        sig_hash, err = SignatureHash(txSuccess4.vout[2].scriptPubKey, txSuccess5, 1, SIGHASH_ALL)
        signature = self.privkeys[0].sign(sig_hash) + b'\x01'
        txSuccess5.vin[1].scriptSig = CScript([signature, hex_str_to_bytes(self.pubkeys[0])])
        sig_hash, err = SignatureHash(txSuccess3.vout[0].scriptPubKey, txSuccess5, 2, SIGHASH_ALL)
        signature = self.privkeys[0].sign(sig_hash) + b'\x01'
        txSuccess5.vin[2].scriptSig = CScript([signature, hex_str_to_bytes(self.pubkeys[0])])
        sig_hash, err = SignatureHash(coinbase_txs[3].vout[0].scriptPubKey, txSuccess5, 3, SIGHASH_ALL)
        signature = self.coinbase_key.sign(sig_hash) + b'\x01'
        txSuccess5.vin[3].scriptSig = CScript([signature])
        txSuccess5.rehash()

        test_transaction_acceptance(node, txSuccess5, accepted=True)

        #TxFailure6 - (UTXO-11)   - transfer REISSUABLE(40)        (UTXO-14)
        #           - (UTXO-8)    - burn NON-REISSUABLE(60)        (UTXO-15)*
        #           - (UTXO-13)   - transfer NFT                   (UTXO-16)
        #           - coinbaseTx5 - issue 1000 REISSUABLE1, change (UTXO-17)
        colorId_reissuable1 = colorIdReissuable(coinbase_txs[6].vout[0].scriptPubKey)
        script_reissuable1 = CP2PHK_script(colorId = colorId_reissuable, pubkey = self.pubkeys[0])

        TxFailure6 = CTransaction()
        TxFailure6.vin.append(CTxIn(COutPoint(txSuccess5.malfixsha256, 1), b""))
        TxFailure6.vin.append(CTxIn(COutPoint(txSuccess4.malfixsha256, 3), b""))
        TxFailure6.vin.append(CTxIn(COutPoint(txSuccess5.malfixsha256, 4), b""))
        TxFailure6.vin.append(CTxIn(COutPoint(coinbase_txs[4].malfixsha256, 0), b""))
        TxFailure6.vout.append(CTxOut(40, script_transfer_reissuable))
        TxFailure6.vout.append(CTxOut(30, script_transfer_nonreissuable))
        TxFailure6.vout.append(CTxOut(1, script_transfer_nft))
        TxFailure6.vout.append(CTxOut(1000, script_reissuable1))
        TxFailure6.vout.append(CTxOut(1*COIN, change_script))
        sig_hash, err = SignatureHash(txSuccess5.vout[1].scriptPubKey, TxFailure6, 0, SIGHASH_ALL)
        signature = self.privkeys[0].sign(sig_hash) + b'\x01'
        TxFailure6.vin[0].scriptSig = CScript([signature, hex_str_to_bytes(self.pubkeys[0])])
        sig_hash, err = SignatureHash(txSuccess4.vout[3].scriptPubKey, TxFailure6, 1, SIGHASH_ALL)
        signature = self.privkeys[0].sign(sig_hash) + b'\x01'
        TxFailure6.vin[1].scriptSig = CScript([signature, hex_str_to_bytes(self.pubkeys[0])])
        sig_hash, err = SignatureHash(txSuccess5.vout[4].scriptPubKey, TxFailure6, 2, SIGHASH_ALL)
        signature = self.privkeys[0].sign(sig_hash) + b'\x01'
        TxFailure6.vin[2].scriptSig = CScript([signature, hex_str_to_bytes(self.pubkeys[0])])
        sig_hash, err = SignatureHash(coinbase_txs[4].vout[0].scriptPubKey, TxFailure6, 3, SIGHASH_ALL)
        signature = self.coinbase_key.sign(sig_hash) + b'\x01'
        TxFailure6.vin[3].scriptSig = CScript([signature])
        TxFailure6.rehash()

        test_transaction_acceptance(node, TxFailure6, accepted=False, reason=b"bad-txns-token-balance")

        #TxSuccess6 - (UTXO-11)   - transfer REISSUABLE(40)        (UTXO-14)
        #           - (UTXO-8)    - burn NON-REISSUABLE(60)        (UTXO-15)*
        #           - (UTXO-13)   - transfer NFT                   (UTXO-16)
        #           - coinbaseTx5 - change 
        txSuccess6 = CTransaction()
        txSuccess6.vin.append(CTxIn(COutPoint(txSuccess5.malfixsha256, 1), b""))
        txSuccess6.vin.append(CTxIn(COutPoint(txSuccess4.malfixsha256, 3), b""))
        txSuccess6.vin.append(CTxIn(COutPoint(txSuccess5.malfixsha256, 4), b""))
        txSuccess6.vin.append(CTxIn(COutPoint(coinbase_txs[4].malfixsha256, 0), b""))
        txSuccess6.vout.append(CTxOut(40, script_transfer_reissuable))
        txSuccess6.vout.append(CTxOut(30, script_transfer_nonreissuable))
        txSuccess6.vout.append(CTxOut(1, script_transfer_nft))
        txSuccess6.vout.append(CTxOut(1*COIN, change_script))
        sig_hash, err = SignatureHash(txSuccess5.vout[1].scriptPubKey, txSuccess6, 0, SIGHASH_ALL)
        signature = self.privkeys[0].sign(sig_hash) + b'\x01'
        txSuccess6.vin[0].scriptSig = CScript([signature, hex_str_to_bytes(self.pubkeys[0])])
        sig_hash, err = SignatureHash(txSuccess4.vout[3].scriptPubKey, txSuccess6, 1, SIGHASH_ALL)
        signature = self.privkeys[0].sign(sig_hash) + b'\x01'
        txSuccess6.vin[1].scriptSig = CScript([signature, hex_str_to_bytes(self.pubkeys[0])])
        sig_hash, err = SignatureHash(txSuccess5.vout[4].scriptPubKey, txSuccess6, 2, SIGHASH_ALL)
        signature = self.privkeys[0].sign(sig_hash) + b'\x01'
        txSuccess6.vin[2].scriptSig = CScript([signature, hex_str_to_bytes(self.pubkeys[0])])
        sig_hash, err = SignatureHash(coinbase_txs[4].vout[0].scriptPubKey, txSuccess6, 3, SIGHASH_ALL)
        signature = self.coinbase_key.sign(sig_hash) + b'\x01'
        txSuccess6.vin[3].scriptSig = CScript([signature])
        txSuccess6.rehash()

        test_transaction_acceptance(node, txSuccess6, accepted=True)

        #TxSuccess7 - coinbaseTx5 - issue 1000 REISSUABLE1, change (UTXO-17)
        txSuccess7 = CTransaction()
        txSuccess7.vin.append(CTxIn(COutPoint(coinbase_txs[5].malfixsha256, 0), b""))
        txSuccess7.vout.append(CTxOut(1000, script_reissuable1))
        sig_hash, err = SignatureHash(coinbase_txs[5].vout[0].scriptPubKey, txSuccess7, 0, SIGHASH_ALL)
        signature = self.coinbase_key.sign(sig_hash) + b'\x01'
        txSuccess7.vin[0].scriptSig = CScript([signature])
        txSuccess7.rehash()

        test_transaction_acceptance(node, txSuccess7, accepted=True)

        #TxFailure7 - (UTXO-9,14) - aggregate REISSUABLE(25 + 40) x
        #           - (UTXO-12)   - burn NON-REISSUABLE(20)        *
        TxFailure7 = CTransaction()
        TxFailure7.vin.append(CTxIn(COutPoint(txSuccess4.malfixsha256, 0), b""))
        TxFailure7.vin.append(CTxIn(COutPoint(txSuccess6.malfixsha256, 0), b""))
        TxFailure7.vin.append(CTxIn(COutPoint(txSuccess5.malfixsha256, 2), b""))
        TxFailure7.vout.append(CTxOut(65, script_transfer_reissuable))
        sig_hash, err = SignatureHash(txSuccess4.vout[0].scriptPubKey, TxFailure7, 0, SIGHASH_ALL)
        signature = self.privkeys[0].sign(sig_hash) + b'\x01'
        TxFailure7.vin[0].scriptSig = CScript([signature, hex_str_to_bytes(self.pubkeys[0])])
        sig_hash, err = SignatureHash(txSuccess6.vout[0].scriptPubKey, TxFailure7, 1, SIGHASH_ALL)
        signature = self.privkeys[0].sign(sig_hash) + b'\x01'
        TxFailure7.vin[1].scriptSig = CScript([signature, hex_str_to_bytes(self.pubkeys[0])])
        sig_hash, err = SignatureHash(txSuccess5.vout[2].scriptPubKey, TxFailure7, 2, SIGHASH_ALL)
        signature = self.privkeys[0].sign(sig_hash) + b'\x01'
        TxFailure7.vin[2].scriptSig = CScript([signature, hex_str_to_bytes(self.pubkeys[0])])
        TxFailure7.rehash()

        test_transaction_acceptance(node, TxFailure7, accepted=False, reason=b'min relay fee not met')

        #txSuccess8 - (UTXO-9,14) - aggregate REISSUABLE(25 + 40) x
        #           - (UTXO-12)   - burn NON-REISSUABLE(20)        *
        #           - coinbase[6]
        txSuccess8 = CTransaction()
        txSuccess8.vin.append(CTxIn(COutPoint(txSuccess4.malfixsha256, 0), b""))
        txSuccess8.vin.append(CTxIn(COutPoint(txSuccess6.malfixsha256, 0), b""))
        txSuccess8.vin.append(CTxIn(COutPoint(txSuccess5.malfixsha256, 2), b""))
        txSuccess8.vin.append(CTxIn(COutPoint(coinbase_txs[6].malfixsha256, 0), b""))
        txSuccess8.vout.append(CTxOut(65, script_transfer_reissuable))
        sig_hash, err = SignatureHash(txSuccess4.vout[0].scriptPubKey, txSuccess8, 0, SIGHASH_ALL)
        signature = self.privkeys[0].sign(sig_hash) + b'\x01'
        txSuccess8.vin[0].scriptSig = CScript([signature, hex_str_to_bytes(self.pubkeys[0])])
        sig_hash, err = SignatureHash(txSuccess6.vout[0].scriptPubKey, txSuccess8, 1, SIGHASH_ALL)
        signature = self.privkeys[1].sign(sig_hash) + b'\x01'
        txSuccess8.vin[1].scriptSig = CScript([signature, hex_str_to_bytes(self.pubkeys[1])])
        sig_hash, err = SignatureHash(txSuccess5.vout[2].scriptPubKey, txSuccess8, 2, SIGHASH_ALL)
        signature = self.privkeys[0].sign(sig_hash) + b'\x01'
        txSuccess8.vin[2].scriptSig = CScript([signature, hex_str_to_bytes(self.pubkeys[0])])
        sig_hash, err = SignatureHash(coinbase_txs[6].vout[0].scriptPubKey, txSuccess8, 3, SIGHASH_ALL)
        signature = self.coinbase_key.sign(sig_hash) + b'\x01'
        txSuccess8.vin[3].scriptSig = CScript([signature])
        txSuccess8.rehash()

        test_transaction_acceptance(node, txSuccess8, accepted=True)

        #TxFailure8 - (UTXO-17)   - convert REISSUABLE to NON-REISSUABLE
        TxFailure8 = CTransaction()
        TxFailure8.vin.append(CTxIn(COutPoint(txSuccess7.malfixsha256, 0), b""))
        TxFailure8.vout.append(CTxOut(60, script_transfer_nonreissuable))
        sig_hash, err = SignatureHash(txSuccess7.vout[0].scriptPubKey, TxFailure8, 0, SIGHASH_ALL)
        signature = self.coinbase_key.sign(sig_hash) + b'\x01'
        TxFailure8.vin[0].scriptSig = CScript([signature])
        TxFailure8.rehash()

        test_transaction_acceptance(node, TxFailure8, accepted=False, reason=b'invalid-colorid')
    def test_sequence_lock_confirmed_inputs(self):
        # Create lots of confirmed utxos, and use them to generate lots of random
        # transactions.
        max_outputs = 50
        addresses = []
        while len(addresses) < max_outputs:
            addresses.append(self.nodes[0].getnewaddress())
        while len(self.nodes[0].listunspent()) < 200:
            import random
            random.shuffle(addresses)
            num_outputs = random.randint(1, max_outputs)
            outputs = {}
            for i in range(num_outputs):
                outputs[addresses[i]] = random.randint(1, 20)*0.01
            self.nodes[0].sendmany("", outputs)
            self.nodes[0].generate(1)

        utxos = self.nodes[0].listunspent()

        # Try creating a lot of random transactions.
        # Each time, choose a random number of inputs, and randomly set
        # some of those inputs to be sequence locked (and randomly choose
        # between height/time locking). Small random chance of making the locks
        # all pass.
        for i in range(400):
            # Randomly choose up to 10 inputs
            num_inputs = random.randint(1, 10)
            random.shuffle(utxos)

            # Track whether any sequence locks used should fail
            should_pass = True

            # Track whether this transaction was built with sequence locks
            using_sequence_locks = False

            tx = CTransaction()
            tx.nVersion = 2
            value = 0
            for j in range(num_inputs):
                sequence_value = 0xfffffffe # this disables sequence locks

                # 50% chance we enable sequence locks
                if random.randint(0,1):
                    using_sequence_locks = True

                    # 10% of the time, make the input sequence value pass
                    input_will_pass = (random.randint(1,10) == 1)
                    sequence_value = utxos[j]["confirmations"]
                    if not input_will_pass:
                        sequence_value += 1
                        should_pass = False

                    # Figure out what the median-time-past was for the confirmed input
                    # Note that if an input has N confirmations, we're going back N blocks
                    # from the tip so that we're looking up MTP of the block
                    # PRIOR to the one the input appears in, as per the BIP68 spec.
                    orig_time = self.get_median_time_past(utxos[j]["confirmations"])
                    cur_time = self.get_median_time_past(0) # MTP of the tip

                    # can only timelock this input if it's not too old -- otherwise use height
                    can_time_lock = True
                    if ((cur_time - orig_time) >> SEQUENCE_LOCKTIME_GRANULARITY) >= SEQUENCE_LOCKTIME_MASK:
                        can_time_lock = False

                    # if time-lockable, then 50% chance we make this a time lock
                    if random.randint(0,1) and can_time_lock:
                        # Find first time-lock value that fails, or latest one that succeeds
                        time_delta = sequence_value << SEQUENCE_LOCKTIME_GRANULARITY
                        if input_will_pass and time_delta > cur_time - orig_time:
                            sequence_value = ((cur_time - orig_time) >> SEQUENCE_LOCKTIME_GRANULARITY)
                        elif (not input_will_pass and time_delta <= cur_time - orig_time):
                            sequence_value = ((cur_time - orig_time) >> SEQUENCE_LOCKTIME_GRANULARITY)+1
                        sequence_value |= SEQUENCE_LOCKTIME_TYPE_FLAG
                tx.vin.append(CTxIn(COutPoint(int(utxos[j]["txid"], 16), utxos[j]["vout"]), nSequence=sequence_value))
                value += utxos[j]["amount"]*COIN
            # Overestimate the size of the tx - signatures should be less than 120 bytes, and leave 50 for the output
            tx_size = len(ToHex(tx))//2 + 120*num_inputs + 50
            tx.vout.append(CTxOut(int(value-self.relayfee*tx_size*COIN/1000), CScript([b'a'])))
            rawtx = self.nodes[0].signrawtransactionwithwallet(ToHex(tx))["hex"]

            if (using_sequence_locks and not should_pass):
                # This transaction should be rejected
                assert_raises_rpc_error(-26, NOT_FINAL_ERROR, self.nodes[0].sendrawtransaction, rawtx)
            else:
                # This raw transaction should be accepted
                self.nodes[0].sendrawtransaction(rawtx)
                utxos = self.nodes[0].listunspent()
Ejemplo n.º 8
0
    def test_prioritised_transactions(self):
        # Ensure that fee deltas used via prioritisetransaction are
        # correctly used by replacement logic

        # 1. Check that feeperkb uses modified fees
        tx0_outpoint = make_utxo(self.nodes[0], int(1.1 * COIN))

        tx1a = CTransaction()
        tx1a.vin = [CTxIn(tx0_outpoint, nSequence=0)]
        tx1a.vout = [CTxOut(1 * COIN, CScript([b'a' * 35]))]
        tx1a_hex = txToHex(tx1a)
        tx1a_txid = self.nodes[0].sendrawtransaction(tx1a_hex, True)

        # Higher fee, but the actual fee per KB is much lower.
        tx1b = CTransaction()
        tx1b.vin = [CTxIn(tx0_outpoint, nSequence=0)]
        tx1b.vout = [CTxOut(int(0.001 * COIN), CScript([b'a' * 740000]))]
        tx1b_hex = txToHex(tx1b)

        # Verify tx1b cannot replace tx1a.
        assert_raises_rpc_error(-26, "insufficient fee",
                                self.nodes[0].sendrawtransaction, tx1b_hex,
                                True)

        # Use prioritisetransaction to set tx1a's fee to 0.
        self.nodes[0].prioritisetransaction(txid=tx1a_txid,
                                            fee_delta=int(-0.1 * COIN))

        # Now tx1b should be able to replace tx1a
        tx1b_txid = self.nodes[0].sendrawtransaction(tx1b_hex, True)

        assert (tx1b_txid in self.nodes[0].getrawmempool())

        # 2. Check that absolute fee checks use modified fee.
        tx1_outpoint = make_utxo(self.nodes[0], int(1.1 * COIN))

        tx2a = CTransaction()
        tx2a.vin = [CTxIn(tx1_outpoint, nSequence=0)]
        tx2a.vout = [CTxOut(1 * COIN, CScript([b'a' * 35]))]
        tx2a_hex = txToHex(tx2a)
        self.nodes[0].sendrawtransaction(tx2a_hex, True)

        # Lower fee, but we'll prioritise it
        tx2b = CTransaction()
        tx2b.vin = [CTxIn(tx1_outpoint, nSequence=0)]
        tx2b.vout = [CTxOut(int(1.01 * COIN), CScript([b'a' * 35]))]
        tx2b.rehash()
        tx2b_hex = txToHex(tx2b)

        # Verify tx2b cannot replace tx2a.
        assert_raises_rpc_error(-26, "insufficient fee",
                                self.nodes[0].sendrawtransaction, tx2b_hex,
                                True)

        # Now prioritise tx2b to have a higher modified fee
        self.nodes[0].prioritisetransaction(txid=tx2b.hash,
                                            fee_delta=int(0.1 * COIN))

        # tx2b should now be accepted
        tx2b_txid = self.nodes[0].sendrawtransaction(tx2b_hex, True)

        assert (tx2b_txid in self.nodes[0].getrawmempool())
Ejemplo n.º 9
0
    def run_test(self):
        protected_peers = set(
        )  # peers that we expect to be protected from eviction
        current_peer = -1
        node = self.nodes[0]
        node.generatetoaddress(101, node.get_deterministic_priv_key().address)

        self.log.info(
            "Create 4 peers and protect them from eviction by sending us a block"
        )
        for _ in range(4):
            block_peer = node.add_p2p_connection(SlowP2PDataStore())
            current_peer += 1
            block_peer.sync_with_ping()
            best_block = node.getbestblockhash()
            tip = int(best_block, 16)
            best_block_time = node.getblock(best_block)['time']
            block = create_block(tip,
                                 create_coinbase(node.getblockcount() + 1),
                                 best_block_time + 1)
            block.solve()
            block_peer.send_blocks_and_test([block], node, success=True)
            protected_peers.add(current_peer)

        self.log.info(
            "Create 5 slow-pinging peers, making them eviction candidates")
        for _ in range(5):
            node.add_p2p_connection(SlowP2PInterface())
            current_peer += 1

        self.log.info(
            "Create 4 peers and protect them from eviction by sending us a tx")
        for i in range(4):
            txpeer = node.add_p2p_connection(SlowP2PInterface())
            current_peer += 1
            txpeer.sync_with_ping()

            prevtx = node.getblock(node.getblockhash(i + 1), 2)['tx'][0]
            rawtx = node.createrawtransaction(
                inputs=[{
                    'txid': prevtx['txid'],
                    'vout': 0
                }],
                outputs=[{
                    node.get_deterministic_priv_key().address:
                    50 - 0.00125
                }],
            )
            sigtx = node.signrawtransactionwithkey(
                hexstring=rawtx,
                privkeys=[node.get_deterministic_priv_key().key],
                prevtxs=[{
                    'txid':
                    prevtx['txid'],
                    'vout':
                    0,
                    'scriptPubKey':
                    prevtx['vout'][0]['scriptPubKey']['hex'],
                }],
            )['hex']
            txpeer.send_message(msg_tx(FromHex(CTransaction(), sigtx)))
            protected_peers.add(current_peer)

        self.log.info(
            "Create 8 peers and protect them from eviction by having faster pings"
        )
        for _ in range(8):
            fastpeer = node.add_p2p_connection(P2PInterface())
            current_peer += 1
            self.wait_until(lambda: "ping" in fastpeer.last_message,
                            timeout=10)

        # Make sure by asking the node what the actual min pings are
        peerinfo = node.getpeerinfo()
        pings = {}
        for i in range(len(peerinfo)):
            pings[i] = peerinfo[i]['minping'] if 'minping' in peerinfo[
                i] else 1000000
        sorted_pings = sorted(pings.items(), key=lambda x: x[1])

        # Usually the 8 fast peers are protected. In rare case of unreliable pings,
        # one of the slower peers might have a faster min ping though.
        for i in range(8):
            protected_peers.add(sorted_pings[i][0])

        self.log.info("Create peer that triggers the eviction mechanism")
        node.add_p2p_connection(SlowP2PInterface())

        # One of the non-protected peers must be evicted. We can't be sure which one because
        # 4 peers are protected via netgroup, which is identical for all peers,
        # and the eviction mechanism doesn't preserve the order of identical elements.
        evicted_peers = []
        for i in range(len(node.p2ps)):
            if not node.p2ps[i].is_connected:
                evicted_peers.append(i)

        self.log.info("Test that one peer was evicted")
        self.log.debug("{} evicted peer: {}".format(len(evicted_peers),
                                                    set(evicted_peers)))
        assert_equal(len(evicted_peers), 1)

        self.log.info("Test that no peer expected to be protected was evicted")
        self.log.debug("{} protected peers: {}".format(len(protected_peers),
                                                       protected_peers))
        assert evicted_peers[0] not in protected_peers
Ejemplo n.º 10
0
    def run_test(self):
        p2p0 = self.nodes[0].add_p2p_connection(BaseNode())

        # Build the blockchain
        self.tip = int(self.nodes[0].getbestblockhash(), 16)
        self.block_time = self.nodes[0].getblock(
            self.nodes[0].getbestblockhash())['time'] + 1

        self.blocks = []

        # Get a pubkey for the coinbase TXO
        coinbase_key = CECKey()
        coinbase_key.set_secretbytes(b"horsebattery")
        coinbase_pubkey = coinbase_key.get_pubkey()

        # Create the first block with a coinbase output to our key
        height = 1
        block = create_block(self.tip, create_coinbase(height,
                                                       coinbase_pubkey),
                             self.block_time)
        self.blocks.append(block)
        self.block_time += 1
        block.solve()
        # Save the coinbase for later
        self.block1 = block
        self.tip = block.sha256
        height += 1

        # Bury the block 100 deep so the coinbase output is spendable
        for i in range(100):
            block = create_block(self.tip, create_coinbase(height),
                                 self.block_time)
            block.solve()
            self.blocks.append(block)
            self.tip = block.sha256
            self.block_time += 1
            height += 1

        # Create a transaction spending the coinbase output with an invalid (null) signature
        tx = CTransaction()
        tx.vin.append(
            CTxIn(COutPoint(self.block1.vtx[0].sha256, 0), scriptSig=b""))
        tx.vout.append(CTxOut(49 * 100000000, CScript([OP_TRUE])))
        tx.calc_sha256()

        block102 = create_block(self.tip, create_coinbase(height),
                                self.block_time)
        self.block_time += 1
        block102.vtx.extend([tx])
        block102.hashMerkleRoot = block102.calc_merkle_root()
        block102.rehash()
        block102.solve()
        self.blocks.append(block102)
        self.tip = block102.sha256
        self.block_time += 1
        height += 1

        # Bury the assumed valid block 2100 deep
        for i in range(2100):
            block = create_block(self.tip, create_coinbase(height),
                                 self.block_time)
            block.nVersion = 4
            block.solve()
            self.blocks.append(block)
            self.tip = block.sha256
            self.block_time += 1
            height += 1

        self.nodes[0].disconnect_p2ps()

        # Start node1 and node2 with assumevalid so they accept a block with a bad signature.
        self.start_node(1, extra_args=["-assumevalid=" + hex(block102.sha256)])
        self.start_node(2, extra_args=["-assumevalid=" + hex(block102.sha256)])

        p2p0 = self.nodes[0].add_p2p_connection(BaseNode())
        p2p1 = self.nodes[1].add_p2p_connection(BaseNode())
        p2p2 = self.nodes[2].add_p2p_connection(BaseNode())

        # send header lists to all three nodes
        p2p0.send_header_for_blocks(self.blocks[0:2000])
        p2p0.send_header_for_blocks(self.blocks[2000:])
        p2p1.send_header_for_blocks(self.blocks[0:2000])
        p2p1.send_header_for_blocks(self.blocks[2000:])
        p2p2.send_header_for_blocks(self.blocks[0:200])

        # Send blocks to node0. Block 102 will be rejected.
        self.send_blocks_until_disconnected(p2p0)
        self.assert_blockchain_height(self.nodes[0], 101)

        # Send all blocks to node1. All blocks will be accepted.
        for i in range(2202):
            p2p1.send_message(msg_block(self.blocks[i]))
        # Syncing 2200 blocks can take a while on slow systems. Give it plenty of time to sync.
        p2p1.sync_with_ping(120)
        assert_equal(
            self.nodes[1].getblock(self.nodes[1].getbestblockhash())['height'],
            2202)

        # Send blocks to node2. Block 102 will be rejected.
        self.send_blocks_until_disconnected(p2p2)
        self.assert_blockchain_height(self.nodes[2], 101)
Ejemplo n.º 11
0
    def create_spam_block(self,
                          hashPrevBlock,
                          stakingPrevOuts,
                          height,
                          fStakeDoubleSpent=False,
                          fZPoS=False,
                          spendingPrevOuts={}):
        ''' creates a block to spam the network with
        :param   hashPrevBlock:      (hex string) hash of previous block
                 stakingPrevOuts:    ({COutPoint --> (int, int, int, str)} dictionary)
                                      map outpoints (to be used as staking inputs) to amount, block_time, nStakeModifier, hashStake
                 height:             (int) block height
                 fStakeDoubleSpent:  (bool) spend the coinstake input inside the block
                 fZPoS:              (bool) stake the block with zerocoin
                 spendingPrevOuts:   ({COutPoint --> (int, int, int, str)} dictionary)
                                      map outpoints (to be used as tx inputs) to amount, block_time, nStakeModifier, hashStake
        :return  block:              (CBlock) generated block
        '''

        # If not given inputs to create spam txes, use a copy of the staking inputs
        if len(spendingPrevOuts) == 0:
            spendingPrevOuts = dict(stakingPrevOuts)

        # Get current time
        current_time = int(time.time())
        nTime = current_time & 0xfffffff0

        # Create coinbase TX
        # Even if PoS blocks have empty coinbase vout, the height is required for the vin script
        coinbase = create_coinbase(height)
        coinbase.vout[0].nValue = 0
        coinbase.vout[0].scriptPubKey = b""
        coinbase.nTime = nTime
        coinbase.rehash()

        # Create Block with coinbase
        block = create_block(int(hashPrevBlock, 16), coinbase, nTime)

        # Find valid kernel hash - Create a new private key used for block signing.
        if not block.solve_stake(stakingPrevOuts):
            raise Exception("Not able to solve for any prev_outpoint")

        # Sign coinstake TX and add it to the block
        signed_stake_tx = self.sign_stake_tx(
            block, stakingPrevOuts[block.prevoutStake][0], fZPoS)
        block.vtx.append(signed_stake_tx)

        # Remove coinstake input prevout unless we want to try double spending in the same block.
        # Skip for zPoS as the spendingPrevouts are just regular UTXOs
        if not fZPoS and not fStakeDoubleSpent:
            del spendingPrevOuts[block.prevoutStake]

        # remove a random prevout from the list
        # (to randomize block creation if the same height is picked two times)
        if len(spendingPrevOuts) > 0:
            del spendingPrevOuts[choice(list(spendingPrevOuts))]

        # Create spam for the block. Sign the spendingPrevouts
        for outPoint in spendingPrevOuts:
            value_out = int(spendingPrevOuts[outPoint][0] -
                            self.DEFAULT_FEE * COIN)
            tx = create_transaction(outPoint,
                                    b"",
                                    value_out,
                                    nTime,
                                    scriptPubKey=CScript([
                                        self.block_sig_key.get_pubkey(),
                                        OP_CHECKSIG
                                    ]))
            # sign txes
            signed_tx_hex = self.node.signrawtransaction(
                bytes_to_hex_str(tx.serialize()))['hex']
            signed_tx = CTransaction()
            signed_tx.deserialize(BytesIO(hex_str_to_bytes(signed_tx_hex)))
            block.vtx.append(signed_tx)

        # Get correct MerkleRoot and rehash block
        block.hashMerkleRoot = block.calc_merkle_root()
        block.rehash()

        # Sign block with coinstake key and return it
        block.sign_block(self.block_sig_key)
        return block
Ejemplo n.º 12
0
def tx_from_hex(hexstring):
    tx = CTransaction()
    f = BytesIO(hex_str_to_bytes(hexstring))
    tx.deserialize(f)
    return tx
Ejemplo n.º 13
0
    def run_test(self):
        self.log.info(
            'prepare some coins for multiple *rawtransaction commands')
        self.nodes[2].generate(1)
        self.sync_all()
        self.nodes[0].generate(COINBASE_MATURITY + 1)
        self.sync_all()
        self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 1.5)
        self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 1.0)
        self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 5.0)
        self.sync_all()
        self.nodes[0].generate(5)
        self.sync_all()

        self.log.info(
            'Test getrawtransaction on genesis block coinbase returns an error'
        )
        block = self.nodes[0].getblock(self.nodes[0].getblockhash(0))
        assert_raises_rpc_error(
            -5,
            "The genesis block coinbase is not considered an ordinary transaction",
            self.nodes[0].getrawtransaction, block['merkleroot'])

        self.log.info(
            'Check parameter types and required parameters of createrawtransaction'
        )
        # Test `createrawtransaction` required parameters
        assert_raises_rpc_error(-1, "createrawtransaction",
                                self.nodes[0].createrawtransaction)
        assert_raises_rpc_error(-1, "createrawtransaction",
                                self.nodes[0].createrawtransaction, [])

        # Test `createrawtransaction` invalid extra parameters
        assert_raises_rpc_error(-1, "createrawtransaction",
                                self.nodes[0].createrawtransaction, [], {}, 0,
                                False, 'foo')

        # Test `createrawtransaction` invalid `inputs`
        txid = '1d1d4e24ed99057e84c3f80fd8fbec79ed9e1acee37da269356ecea000000000'
        assert_raises_rpc_error(-3, "Expected type array",
                                self.nodes[0].createrawtransaction, 'foo', {})
        assert_raises_rpc_error(-1, "JSON value is not an object as expected",
                                self.nodes[0].createrawtransaction, ['foo'],
                                {})
        assert_raises_rpc_error(-1, "JSON value is not a string as expected",
                                self.nodes[0].createrawtransaction, [{}], {})
        assert_raises_rpc_error(
            -8, "txid must be of length 64 (not 3, for 'foo')",
            self.nodes[0].createrawtransaction, [{
                'txid': 'foo'
            }], {})
        assert_raises_rpc_error(
            -8,
            "txid must be hexadecimal string (not 'ZZZ7bb8b1697ea987f3b223ba7819250cae33efacb068d23dc24859824a77844')",
            self.nodes[0].createrawtransaction, [{
                'txid':
                'ZZZ7bb8b1697ea987f3b223ba7819250cae33efacb068d23dc24859824a77844'
            }], {})
        assert_raises_rpc_error(-8, "Invalid parameter, missing vout key",
                                self.nodes[0].createrawtransaction,
                                [{
                                    'txid': txid
                                }], {})
        assert_raises_rpc_error(-8, "Invalid parameter, missing vout key",
                                self.nodes[0].createrawtransaction,
                                [{
                                    'txid': txid,
                                    'vout': 'foo'
                                }], {})
        assert_raises_rpc_error(-8,
                                "Invalid parameter, vout cannot be negative",
                                self.nodes[0].createrawtransaction, [{
                                    'txid': txid,
                                    'vout': -1
                                }], {})
        assert_raises_rpc_error(
            -8, "Invalid parameter, sequence number is out of range",
            self.nodes[0].createrawtransaction, [{
                'txid': txid,
                'vout': 0,
                'sequence': -1
            }], {})

        # Test `createrawtransaction` invalid `outputs`
        address = self.nodes[0].getnewaddress()
        address2 = self.nodes[0].getnewaddress()
        assert_raises_rpc_error(-1, "JSON value is not an array as expected",
                                self.nodes[0].createrawtransaction, [], 'foo')
        self.nodes[0].createrawtransaction(
            inputs=[],
            outputs={})  # Should not throw for backwards compatibility
        self.nodes[0].createrawtransaction(inputs=[], outputs=[])
        assert_raises_rpc_error(-8, "Data must be hexadecimal string",
                                self.nodes[0].createrawtransaction, [],
                                {'data': 'foo'})
        assert_raises_rpc_error(-5, "Invalid MicroBitcoin address",
                                self.nodes[0].createrawtransaction, [],
                                {'foo': 0})
        assert_raises_rpc_error(-3, "Invalid amount",
                                self.nodes[0].createrawtransaction, [],
                                {address: 'foo'})
        assert_raises_rpc_error(-3, "Amount out of range",
                                self.nodes[0].createrawtransaction, [],
                                {address: -1})
        assert_raises_rpc_error(
            -8, "Invalid parameter, duplicated address: %s" % address,
            self.nodes[0].createrawtransaction, [],
            multidict([(address, 1), (address, 1)]))
        assert_raises_rpc_error(
            -8, "Invalid parameter, duplicated address: %s" % address,
            self.nodes[0].createrawtransaction, [], [{
                address: 1
            }, {
                address: 1
            }])
        assert_raises_rpc_error(-8, "Invalid parameter, duplicate key: data",
                                self.nodes[0].createrawtransaction, [],
                                [{
                                    "data": 'aa'
                                }, {
                                    "data": "bb"
                                }])
        assert_raises_rpc_error(-8, "Invalid parameter, duplicate key: data",
                                self.nodes[0].createrawtransaction, [],
                                multidict([("data", 'aa'), ("data", "bb")]))
        assert_raises_rpc_error(
            -8,
            "Invalid parameter, key-value pair must contain exactly one key",
            self.nodes[0].createrawtransaction, [], [{
                'a': 1,
                'b': 2
            }])
        assert_raises_rpc_error(
            -8, "Invalid parameter, key-value pair not an object as expected",
            self.nodes[0].createrawtransaction, [],
            [['key-value pair1'], ['2']])

        # Test `createrawtransaction` invalid `locktime`
        assert_raises_rpc_error(-3, "Expected type number",
                                self.nodes[0].createrawtransaction, [], {},
                                'foo')
        assert_raises_rpc_error(-8, "Invalid parameter, locktime out of range",
                                self.nodes[0].createrawtransaction, [], {}, -1)
        assert_raises_rpc_error(-8, "Invalid parameter, locktime out of range",
                                self.nodes[0].createrawtransaction, [], {},
                                4294967296)

        # Test `createrawtransaction` invalid `replaceable`
        assert_raises_rpc_error(-3, "Expected type bool",
                                self.nodes[0].createrawtransaction, [], {}, 0,
                                'foo')

        self.log.info(
            'Check that createrawtransaction accepts an array and object as outputs'
        )
        # One output
        tx = tx_from_hex(self.nodes[2].createrawtransaction(
            inputs=[{
                'txid': txid,
                'vout': 9
            }], outputs={address: 99}))
        assert_equal(len(tx.vout), 1)
        assert_equal(
            tx.serialize().hex(),
            self.nodes[2].createrawtransaction(inputs=[{
                'txid': txid,
                'vout': 9
            }],
                                               outputs=[{
                                                   address: 99
                                               }]),
        )
        # Two outputs
        tx = tx_from_hex(self.nodes[2].createrawtransaction(
            inputs=[{
                'txid': txid,
                'vout': 9
            }],
            outputs=OrderedDict([(address, 99), (address2, 99)])))
        assert_equal(len(tx.vout), 2)
        assert_equal(
            tx.serialize().hex(),
            self.nodes[2].createrawtransaction(inputs=[{
                'txid': txid,
                'vout': 9
            }],
                                               outputs=[{
                                                   address: 99
                                               }, {
                                                   address2: 99
                                               }]),
        )
        # Multiple mixed outputs
        tx = tx_from_hex(self.nodes[2].createrawtransaction(inputs=[{
            'txid': txid,
            'vout': 9
        }],
                                                            outputs=multidict([
                                                                (address, 99),
                                                                (address2, 99),
                                                                ('data', '99')
                                                            ])))
        assert_equal(len(tx.vout), 3)
        assert_equal(
            tx.serialize().hex(),
            self.nodes[2].createrawtransaction(inputs=[{
                'txid': txid,
                'vout': 9
            }],
                                               outputs=[{
                                                   address: 99
                                               }, {
                                                   address2: 99
                                               }, {
                                                   'data': '99'
                                               }]),
        )

        for type in ["bech32", "p2sh-segwit", "legacy"]:
            addr = self.nodes[0].getnewaddress("", type)
            addrinfo = self.nodes[0].getaddressinfo(addr)
            pubkey = addrinfo["scriptPubKey"]

            self.log.info('sendrawtransaction with missing prevtx info (%s)' %
                          (type))

            # Test `signrawtransactionwithwallet` invalid `prevtxs`
            inputs = [{'txid': txid, 'vout': 3, 'sequence': 1000}]
            outputs = {self.nodes[0].getnewaddress(): 1}
            rawtx = self.nodes[0].createrawtransaction(inputs, outputs)

            prevtx = dict(txid=txid, scriptPubKey=pubkey, vout=3, amount=1)
            succ = self.nodes[0].signrawtransactionwithwallet(rawtx, [prevtx])
            assert succ["complete"]
            if type == "legacy":
                del prevtx["amount"]
                succ = self.nodes[0].signrawtransactionwithwallet(
                    rawtx, [prevtx])
                assert succ["complete"]

            if type != "legacy":
                assert_raises_rpc_error(
                    -3, "Missing amount",
                    self.nodes[0].signrawtransactionwithwallet, rawtx,
                    [{
                        "txid": txid,
                        "scriptPubKey": pubkey,
                        "vout": 3,
                    }])

            assert_raises_rpc_error(-3, "Missing vout",
                                    self.nodes[0].signrawtransactionwithwallet,
                                    rawtx, [{
                                        "txid": txid,
                                        "scriptPubKey": pubkey,
                                        "amount": 1,
                                    }])
            assert_raises_rpc_error(-3, "Missing txid",
                                    self.nodes[0].signrawtransactionwithwallet,
                                    rawtx, [{
                                        "scriptPubKey": pubkey,
                                        "vout": 3,
                                        "amount": 1,
                                    }])
            assert_raises_rpc_error(-3, "Missing scriptPubKey",
                                    self.nodes[0].signrawtransactionwithwallet,
                                    rawtx, [{
                                        "txid": txid,
                                        "vout": 3,
                                        "amount": 1
                                    }])

        #########################################
        # sendrawtransaction with missing input #
        #########################################

        self.log.info('sendrawtransaction with missing input')
        inputs = [{
            'txid':
            "1d1d4e24ed99057e84c3f80fd8fbec79ed9e1acee37da269356ecea000000000",
            'vout': 1
        }]  #won't exists
        outputs = {self.nodes[0].getnewaddress(): 4.998}
        rawtx = self.nodes[2].createrawtransaction(inputs, outputs)
        rawtx = self.nodes[2].signrawtransactionwithwallet(rawtx)

        # This will raise an exception since there are missing inputs
        assert_raises_rpc_error(-25, "bad-txns-inputs-missingorspent",
                                self.nodes[2].sendrawtransaction, rawtx['hex'])

        #####################################
        # getrawtransaction with block hash #
        #####################################

        # make a tx by sending then generate 2 blocks; block1 has the tx in it
        tx = self.nodes[2].sendtoaddress(self.nodes[1].getnewaddress(), 1)
        block1, block2 = self.nodes[2].generate(2)
        self.sync_all()
        # We should be able to get the raw transaction by providing the correct block
        gottx = self.nodes[0].getrawtransaction(tx, True, block1)
        assert_equal(gottx['txid'], tx)
        assert_equal(gottx['in_active_chain'], True)
        # We should not have the 'in_active_chain' flag when we don't provide a block
        gottx = self.nodes[0].getrawtransaction(tx, True)
        assert_equal(gottx['txid'], tx)
        assert 'in_active_chain' not in gottx
        # We should not get the tx if we provide an unrelated block
        assert_raises_rpc_error(-5, "No such transaction found",
                                self.nodes[0].getrawtransaction, tx, True,
                                block2)
        # An invalid block hash should raise the correct errors
        assert_raises_rpc_error(-1, "JSON value is not a string as expected",
                                self.nodes[0].getrawtransaction, tx, True,
                                True)
        assert_raises_rpc_error(
            -8, "parameter 3 must be of length 64 (not 6, for 'foobar')",
            self.nodes[0].getrawtransaction, tx, True, "foobar")
        assert_raises_rpc_error(
            -8, "parameter 3 must be of length 64 (not 8, for 'abcd1234')",
            self.nodes[0].getrawtransaction, tx, True, "abcd1234")
        assert_raises_rpc_error(
            -8,
            "parameter 3 must be hexadecimal string (not 'ZZZ0000000000000000000000000000000000000000000000000000000000000')",
            self.nodes[0].getrawtransaction, tx, True,
            "ZZZ0000000000000000000000000000000000000000000000000000000000000")
        assert_raises_rpc_error(
            -5, "Block hash not found", self.nodes[0].getrawtransaction, tx,
            True,
            "0000000000000000000000000000000000000000000000000000000000000000")
        # Undo the blocks and check in_active_chain
        self.nodes[0].invalidateblock(block1)
        gottx = self.nodes[0].getrawtransaction(txid=tx,
                                                verbose=True,
                                                blockhash=block1)
        assert_equal(gottx['in_active_chain'], False)
        self.nodes[0].reconsiderblock(block1)
        assert_equal(self.nodes[0].getbestblockhash(), block2)

        if not self.options.descriptors:
            # The traditional multisig workflow does not work with descriptor wallets so these are legacy only.
            # The multisig workflow with descriptor wallets uses PSBTs and is tested elsewhere, no need to do them here.
            #########################
            # RAW TX MULTISIG TESTS #
            #########################
            # 2of2 test
            addr1 = self.nodes[2].getnewaddress()
            addr2 = self.nodes[2].getnewaddress()

            addr1Obj = self.nodes[2].getaddressinfo(addr1)
            addr2Obj = self.nodes[2].getaddressinfo(addr2)

            # Tests for createmultisig and addmultisigaddress
            assert_raises_rpc_error(-5, "Invalid public key",
                                    self.nodes[0].createmultisig, 1,
                                    ["01020304"])
            self.nodes[0].createmultisig(
                2, [addr1Obj['pubkey'], addr2Obj['pubkey']
                    ])  # createmultisig can only take public keys
            assert_raises_rpc_error(
                -5, "Invalid public key", self.nodes[0].createmultisig, 2,
                [addr1Obj['pubkey'], addr1]
            )  # addmultisigaddress can take both pubkeys and addresses so long as they are in the wallet, which is tested here.

            mSigObj = self.nodes[2].addmultisigaddress(
                2, [addr1Obj['pubkey'], addr1])['address']

            #use balance deltas instead of absolute values
            bal = self.nodes[2].getbalance()

            # send 1.2 MBC to msig adr
            txId = self.nodes[0].sendtoaddress(mSigObj, 1.2)
            self.sync_all()
            self.nodes[0].generate(1)
            self.sync_all()
            assert_equal(
                self.nodes[2].getbalance(), bal + Decimal('1.20000000')
            )  #node2 has both keys of the 2of2 ms addr., tx should affect the balance

            # 2of3 test from different nodes
            bal = self.nodes[2].getbalance()
            addr1 = self.nodes[1].getnewaddress()
            addr2 = self.nodes[2].getnewaddress()
            addr3 = self.nodes[2].getnewaddress()

            addr1Obj = self.nodes[1].getaddressinfo(addr1)
            addr2Obj = self.nodes[2].getaddressinfo(addr2)
            addr3Obj = self.nodes[2].getaddressinfo(addr3)

            mSigObj = self.nodes[2].addmultisigaddress(
                2,
                [addr1Obj['pubkey'], addr2Obj['pubkey'], addr3Obj['pubkey']
                 ])['address']

            txId = self.nodes[0].sendtoaddress(mSigObj, 2.2)
            decTx = self.nodes[0].gettransaction(txId)
            rawTx = self.nodes[0].decoderawtransaction(decTx['hex'])
            self.sync_all()
            self.nodes[0].generate(1)
            self.sync_all()

            #THIS IS AN INCOMPLETE FEATURE
            #NODE2 HAS TWO OF THREE KEY AND THE FUNDS SHOULD BE SPENDABLE AND COUNT AT BALANCE CALCULATION
            assert_equal(
                self.nodes[2].getbalance(), bal
            )  #for now, assume the funds of a 2of3 multisig tx are not marked as spendable

            txDetails = self.nodes[0].gettransaction(txId, True)
            rawTx = self.nodes[0].decoderawtransaction(txDetails['hex'])
            vout = next(o for o in rawTx['vout']
                        if o['value'] == Decimal('2.20000000'))

            bal = self.nodes[0].getbalance()
            inputs = [{
                "txid": txId,
                "vout": vout['n'],
                "scriptPubKey": vout['scriptPubKey']['hex'],
                "amount": vout['value']
            }]
            outputs = {self.nodes[0].getnewaddress(): 2.19}
            rawTx = self.nodes[2].createrawtransaction(inputs, outputs)
            rawTxPartialSigned = self.nodes[1].signrawtransactionwithwallet(
                rawTx, inputs)
            assert_equal(
                rawTxPartialSigned['complete'],
                False)  #node1 only has one key, can't comp. sign the tx

            rawTxSigned = self.nodes[2].signrawtransactionwithwallet(
                rawTx, inputs)
            assert_equal(
                rawTxSigned['complete'],
                True)  #node2 can sign the tx compl., own two of three keys
            self.nodes[2].sendrawtransaction(rawTxSigned['hex'])
            rawTx = self.nodes[0].decoderawtransaction(rawTxSigned['hex'])
            self.sync_all()
            self.nodes[0].generate(1)
            self.sync_all()
            assert_equal(self.nodes[0].getbalance(),
                         bal + Decimal('50.00000000') +
                         Decimal('2.19000000'))  #block reward + tx

            # 2of2 test for combining transactions
            bal = self.nodes[2].getbalance()
            addr1 = self.nodes[1].getnewaddress()
            addr2 = self.nodes[2].getnewaddress()

            addr1Obj = self.nodes[1].getaddressinfo(addr1)
            addr2Obj = self.nodes[2].getaddressinfo(addr2)

            self.nodes[1].addmultisigaddress(
                2, [addr1Obj['pubkey'], addr2Obj['pubkey']])['address']
            mSigObj = self.nodes[2].addmultisigaddress(
                2, [addr1Obj['pubkey'], addr2Obj['pubkey']])['address']
            mSigObjValid = self.nodes[2].getaddressinfo(mSigObj)

            txId = self.nodes[0].sendtoaddress(mSigObj, 2.2)
            decTx = self.nodes[0].gettransaction(txId)
            rawTx2 = self.nodes[0].decoderawtransaction(decTx['hex'])
            self.sync_all()
            self.nodes[0].generate(1)
            self.sync_all()

            assert_equal(
                self.nodes[2].getbalance(), bal
            )  # the funds of a 2of2 multisig tx should not be marked as spendable

            txDetails = self.nodes[0].gettransaction(txId, True)
            rawTx2 = self.nodes[0].decoderawtransaction(txDetails['hex'])
            vout = next(o for o in rawTx2['vout']
                        if o['value'] == Decimal('2.20000000'))

            bal = self.nodes[0].getbalance()
            inputs = [{
                "txid": txId,
                "vout": vout['n'],
                "scriptPubKey": vout['scriptPubKey']['hex'],
                "redeemScript": mSigObjValid['hex'],
                "amount": vout['value']
            }]
            outputs = {self.nodes[0].getnewaddress(): 2.19}
            rawTx2 = self.nodes[2].createrawtransaction(inputs, outputs)
            rawTxPartialSigned1 = self.nodes[1].signrawtransactionwithwallet(
                rawTx2, inputs)
            self.log.debug(rawTxPartialSigned1)
            assert_equal(
                rawTxPartialSigned1['complete'],
                False)  #node1 only has one key, can't comp. sign the tx

            rawTxPartialSigned2 = self.nodes[2].signrawtransactionwithwallet(
                rawTx2, inputs)
            self.log.debug(rawTxPartialSigned2)
            assert_equal(
                rawTxPartialSigned2['complete'],
                False)  #node2 only has one key, can't comp. sign the tx
            rawTxComb = self.nodes[2].combinerawtransaction(
                [rawTxPartialSigned1['hex'], rawTxPartialSigned2['hex']])
            self.log.debug(rawTxComb)
            self.nodes[2].sendrawtransaction(rawTxComb)
            rawTx2 = self.nodes[0].decoderawtransaction(rawTxComb)
            self.sync_all()
            self.nodes[0].generate(1)
            self.sync_all()
            assert_equal(self.nodes[0].getbalance(),
                         bal + Decimal('50.00000000') +
                         Decimal('2.19000000'))  #block reward + tx

        # decoderawtransaction tests
        # witness transaction
        encrawtx = "010000000001010000000000000072c1a6a246ae63f74f931e8365e15a089c68d61900000000000000000000ffffffff0100e1f50500000000000102616100000000"
        decrawtx = self.nodes[0].decoderawtransaction(
            encrawtx, True)  # decode as witness transaction
        assert_equal(decrawtx['vout'][0]['value'], Decimal('1.00000000'))
        assert_raises_rpc_error(
            -22, 'TX decode failed', self.nodes[0].decoderawtransaction,
            encrawtx, False)  # force decode as non-witness transaction
        # non-witness transaction
        encrawtx = "01000000010000000000000072c1a6a246ae63f74f931e8365e15a089c68d61900000000000000000000ffffffff0100e1f505000000000000000000"
        decrawtx = self.nodes[0].decoderawtransaction(
            encrawtx, False)  # decode as non-witness transaction
        assert_equal(decrawtx['vout'][0]['value'], Decimal('1.00000000'))
        # known ambiguous transaction in the chain (see https://github.com/MicroBitcoinOrg/MicroBitcoin/issues/20579)
        encrawtx = "020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff4b03c68708046ff8415c622f4254432e434f4d2ffabe6d6de1965d02c68f928e5b244ab1965115a36f56eb997633c7f690124bbf43644e23080000000ca3d3af6d005a65ff0200fd00000000ffffffff03f4c1fb4b0000000016001497cfc76442fe717f2a3f0cc9c175f7561b6619970000000000000000266a24aa21a9ed957d1036a80343e0d1b659497e1b48a38ebe876a056d45965fac4a85cda84e1900000000000000002952534b424c4f434b3a8e092581ab01986cbadc84f4b43f4fa4bb9e7a2e2a0caf9b7cf64d939028e22c0120000000000000000000000000000000000000000000000000000000000000000000000000"
        decrawtx = self.nodes[0].decoderawtransaction(encrawtx)
        decrawtx_wit = self.nodes[0].decoderawtransaction(encrawtx, True)
        assert_raises_rpc_error(
            -22, 'TX decode failed', self.nodes[0].decoderawtransaction,
            encrawtx, False)  # fails to decode as non-witness transaction
        assert_equal(
            decrawtx,
            decrawtx_wit)  # the witness interpretation should be chosen
        assert_equal(
            decrawtx['vin'][0]['coinbase'],
            "03c68708046ff8415c622f4254432e434f4d2ffabe6d6de1965d02c68f928e5b244ab1965115a36f56eb997633c7f690124bbf43644e23080000000ca3d3af6d005a65ff0200fd00000000"
        )

        # Basic signrawtransaction test
        addr = self.nodes[1].getnewaddress()
        txid = self.nodes[0].sendtoaddress(addr, 10)
        self.nodes[0].generate(1)
        self.sync_all()
        vout = find_vout_for_address(self.nodes[1], txid, addr)
        rawTx = self.nodes[1].createrawtransaction(
            [{
                'txid': txid,
                'vout': vout
            }], {self.nodes[1].getnewaddress(): 9.999})
        rawTxSigned = self.nodes[1].signrawtransactionwithwallet(rawTx)
        txId = self.nodes[1].sendrawtransaction(rawTxSigned['hex'])
        self.nodes[0].generate(1)
        self.sync_all()

        # getrawtransaction tests
        # 1. valid parameters - only supply txid
        assert_equal(self.nodes[0].getrawtransaction(txId), rawTxSigned['hex'])

        # 2. valid parameters - supply txid and 0 for non-verbose
        assert_equal(self.nodes[0].getrawtransaction(txId, 0),
                     rawTxSigned['hex'])

        # 3. valid parameters - supply txid and False for non-verbose
        assert_equal(self.nodes[0].getrawtransaction(txId, False),
                     rawTxSigned['hex'])

        # 4. valid parameters - supply txid and 1 for verbose.
        # We only check the "hex" field of the output so we don't need to update this test every time the output format changes.
        assert_equal(self.nodes[0].getrawtransaction(txId, 1)["hex"],
                     rawTxSigned['hex'])

        # 5. valid parameters - supply txid and True for non-verbose
        assert_equal(self.nodes[0].getrawtransaction(txId, True)["hex"],
                     rawTxSigned['hex'])

        # 6. invalid parameters - supply txid and string "Flase"
        assert_raises_rpc_error(-1, "not a boolean",
                                self.nodes[0].getrawtransaction, txId, "Flase")

        # 7. invalid parameters - supply txid and empty array
        assert_raises_rpc_error(-1, "not a boolean",
                                self.nodes[0].getrawtransaction, txId, [])

        # 8. invalid parameters - supply txid and empty dict
        assert_raises_rpc_error(-1, "not a boolean",
                                self.nodes[0].getrawtransaction, txId, {})

        inputs = [{
            'txid':
            "1d1d4e24ed99057e84c3f80fd8fbec79ed9e1acee37da269356ecea000000000",
            'vout': 1,
            'sequence': 1000
        }]
        outputs = {self.nodes[0].getnewaddress(): 1}
        rawtx = self.nodes[0].createrawtransaction(inputs, outputs)
        decrawtx = self.nodes[0].decoderawtransaction(rawtx)
        assert_equal(decrawtx['vin'][0]['sequence'], 1000)

        # 9. invalid parameters - sequence number out of range
        inputs = [{
            'txid':
            "1d1d4e24ed99057e84c3f80fd8fbec79ed9e1acee37da269356ecea000000000",
            'vout': 1,
            'sequence': -1
        }]
        outputs = {self.nodes[0].getnewaddress(): 1}
        assert_raises_rpc_error(
            -8, 'Invalid parameter, sequence number is out of range',
            self.nodes[0].createrawtransaction, inputs, outputs)

        # 10. invalid parameters - sequence number out of range
        inputs = [{
            'txid':
            "1d1d4e24ed99057e84c3f80fd8fbec79ed9e1acee37da269356ecea000000000",
            'vout': 1,
            'sequence': 4294967296
        }]
        outputs = {self.nodes[0].getnewaddress(): 1}
        assert_raises_rpc_error(
            -8, 'Invalid parameter, sequence number is out of range',
            self.nodes[0].createrawtransaction, inputs, outputs)

        inputs = [{
            'txid':
            "1d1d4e24ed99057e84c3f80fd8fbec79ed9e1acee37da269356ecea000000000",
            'vout': 1,
            'sequence': 4294967294
        }]
        outputs = {self.nodes[0].getnewaddress(): 1}
        rawtx = self.nodes[0].createrawtransaction(inputs, outputs)
        decrawtx = self.nodes[0].decoderawtransaction(rawtx)
        assert_equal(decrawtx['vin'][0]['sequence'], 4294967294)

        ####################################
        # TRANSACTION VERSION NUMBER TESTS #
        ####################################

        # Test the minimum transaction version number that fits in a signed 32-bit integer.
        # As transaction version is unsigned, this should convert to its unsigned equivalent.
        tx = CTransaction()
        tx.nVersion = -0x80000000
        rawtx = tx.serialize().hex()
        decrawtx = self.nodes[0].decoderawtransaction(rawtx)
        assert_equal(decrawtx['version'], 0x80000000)

        # Test the maximum transaction version number that fits in a signed 32-bit integer.
        tx = CTransaction()
        tx.nVersion = 0x7fffffff
        rawtx = tx.serialize().hex()
        decrawtx = self.nodes[0].decoderawtransaction(rawtx)
        assert_equal(decrawtx['version'], 0x7fffffff)

        self.log.info('sendrawtransaction/testmempoolaccept with maxfeerate')

        # Test a transaction with a small fee.
        txId = self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 1.0)
        rawTx = self.nodes[0].getrawtransaction(txId, True)
        vout = next(o for o in rawTx['vout']
                    if o['value'] == Decimal('1.00000000'))

        self.sync_all()
        inputs = [{"txid": txId, "vout": vout['n']}]
        # Fee 10,000 satoshis, (1 - (10000 sat * 0.00000001 MBC/sat)) = 0.9999
        outputs = {self.nodes[0].getnewaddress(): Decimal("0.99990000")}
        rawTx = self.nodes[2].createrawtransaction(inputs, outputs)
        rawTxSigned = self.nodes[2].signrawtransactionwithwallet(rawTx)
        assert_equal(rawTxSigned['complete'], True)
        # Fee 10,000 satoshis, ~100 b transaction, fee rate should land around 100 sat/byte = 0.00100000 MBC/kB
        # Thus, testmempoolaccept should reject
        testres = self.nodes[2].testmempoolaccept([rawTxSigned['hex']],
                                                  0.00001000)[0]
        assert_equal(testres['allowed'], False)
        assert_equal(testres['reject-reason'], 'max-fee-exceeded')
        # and sendrawtransaction should throw
        assert_raises_rpc_error(
            -25,
            'Fee exceeds maximum configured by user (e.g. -maxtxfee, maxfeerate)',
            self.nodes[2].sendrawtransaction, rawTxSigned['hex'], 0.00001000)
        # and the following calls should both succeed
        testres = self.nodes[2].testmempoolaccept(
            rawtxs=[rawTxSigned['hex']])[0]
        assert_equal(testres['allowed'], True)
        self.nodes[2].sendrawtransaction(hexstring=rawTxSigned['hex'])

        # Test a transaction with a large fee.
        txId = self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 1.0)
        rawTx = self.nodes[0].getrawtransaction(txId, True)
        vout = next(o for o in rawTx['vout']
                    if o['value'] == Decimal('1.00000000'))

        self.sync_all()
        inputs = [{"txid": txId, "vout": vout['n']}]
        # Fee 2,000,000 satoshis, (1 - (2000000 sat * 0.00000001 MBC/sat)) = 0.98
        outputs = {self.nodes[0].getnewaddress(): Decimal("0.98000000")}
        rawTx = self.nodes[2].createrawtransaction(inputs, outputs)
        rawTxSigned = self.nodes[2].signrawtransactionwithwallet(rawTx)
        assert_equal(rawTxSigned['complete'], True)
        # Fee 2,000,000 satoshis, ~100 b transaction, fee rate should land around 20,000 sat/byte = 0.20000000 MBC/kB
        # Thus, testmempoolaccept should reject
        testres = self.nodes[2].testmempoolaccept([rawTxSigned['hex']])[0]
        assert_equal(testres['allowed'], False)
        assert_equal(testres['reject-reason'], 'max-fee-exceeded')
        # and sendrawtransaction should throw
        assert_raises_rpc_error(
            -25,
            'Fee exceeds maximum configured by user (e.g. -maxtxfee, maxfeerate)',
            self.nodes[2].sendrawtransaction, rawTxSigned['hex'])
        # and the following calls should both succeed
        testres = self.nodes[2].testmempoolaccept(rawtxs=[rawTxSigned['hex']],
                                                  maxfeerate='0.20000000')[0]
        assert_equal(testres['allowed'], True)
        self.nodes[2].sendrawtransaction(hexstring=rawTxSigned['hex'],
                                         maxfeerate='0.20000000')
Ejemplo n.º 14
0
    def run_test(self):
        node = self.nodes[0]  # convenience reference to the node

        self.bootstrap_p2p()  # Add one p2p connection to the node

        best_block = self.nodes[0].getbestblockhash()
        tip = int(best_block, 16)
        best_block_time = self.nodes[0].getblock(best_block)['time']
        block_time = best_block_time + 1

        self.log.info("Create a new block with an anyone-can-spend coinbase.")
        height = 1
        block = create_block(tip, create_coinbase(height), block_time)
        block.solve()
        # Save the coinbase for later
        block1 = block
        tip = block.sha256
        node.p2p.send_blocks_and_test([block], node, success=True)

        self.log.info("Mature the block.")
        self.nodes[0].generate(100)

        # b'\x64' is OP_NOTIF
        # Transaction will be rejected with code 16 (REJECT_INVALID)
        # and we get disconnected immediately
        self.log.info('Test a transaction that is rejected')
        tx1 = create_tx_with_script(block1.vtx[0],
                                    0,
                                    script_sig=b'\x64' * 35,
                                    amount=50 * COIN - 12000)
        node.p2p.send_txs_and_test([tx1],
                                   node,
                                   success=False,
                                   expect_disconnect=True)

        # Make two p2p connections to provide the node with orphans
        # * p2ps[0] will send valid orphan txs (one with low fee)
        # * p2ps[1] will send an invalid orphan tx (and is later disconnected for that)
        self.reconnect_p2p(num_connections=2)

        self.log.info('Test orphan transaction handling ... ')
        # Create a root transaction that we withhold until all dependend transactions
        # are sent out and in the orphan cache
        SCRIPT_PUB_KEY_OP_TRUE = b'\x51\x75' * 15 + b'\x51'
        tx_withhold = CTransaction()
        tx_withhold.vin.append(
            CTxIn(outpoint=COutPoint(block1.vtx[0].sha256, 0)))
        tx_withhold.vout.append(
            CTxOut(nValue=50 * COIN - 12000,
                   scriptPubKey=SCRIPT_PUB_KEY_OP_TRUE))
        tx_withhold.calc_sha256()

        # Our first orphan tx with some outputs to create further orphan txs
        tx_orphan_1 = CTransaction()
        tx_orphan_1.vin.append(
            CTxIn(outpoint=COutPoint(tx_withhold.sha256, 0)))
        tx_orphan_1.vout = [
            CTxOut(nValue=10 * COIN, scriptPubKey=SCRIPT_PUB_KEY_OP_TRUE)
        ] * 3
        tx_orphan_1.calc_sha256()

        # A valid transaction with low fee
        tx_orphan_2_no_fee = CTransaction()
        tx_orphan_2_no_fee.vin.append(
            CTxIn(outpoint=COutPoint(tx_orphan_1.sha256, 0)))
        tx_orphan_2_no_fee.vout.append(
            CTxOut(nValue=10 * COIN, scriptPubKey=SCRIPT_PUB_KEY_OP_TRUE))

        # A valid transaction with sufficient fee
        tx_orphan_2_valid = CTransaction()
        tx_orphan_2_valid.vin.append(
            CTxIn(outpoint=COutPoint(tx_orphan_1.sha256, 1)))
        tx_orphan_2_valid.vout.append(
            CTxOut(nValue=10 * COIN - 12000,
                   scriptPubKey=SCRIPT_PUB_KEY_OP_TRUE))
        tx_orphan_2_valid.calc_sha256()

        # An invalid transaction with negative fee
        tx_orphan_2_invalid = CTransaction()
        tx_orphan_2_invalid.vin.append(
            CTxIn(outpoint=COutPoint(tx_orphan_1.sha256, 2)))
        tx_orphan_2_invalid.vout.append(
            CTxOut(nValue=11 * COIN, scriptPubKey=SCRIPT_PUB_KEY_OP_TRUE))

        self.log.info('Send the orphans ... ')
        # Send valid orphan txs from p2ps[0]
        node.p2p.send_txs_and_test(
            [tx_orphan_1, tx_orphan_2_no_fee, tx_orphan_2_valid],
            node,
            success=False)
        # Send invalid tx from p2ps[1]
        node.p2ps[1].send_txs_and_test([tx_orphan_2_invalid],
                                       node,
                                       success=False)

        assert_equal(0,
                     node.getmempoolinfo()['size'])  # Mempool should be empty
        assert_equal(2, len(node.getpeerinfo()))  # p2ps[1] is still connected

        self.log.info('Send the withhold tx ... ')
        node.p2p.send_txs_and_test([tx_withhold], node, success=True)

        # Transactions that should end up in the mempool
        expected_mempool = {
            t.hash
            for t in [
                tx_withhold,  # The transaction that is the root for all orphans
                tx_orphan_1,  # The orphan transaction that splits the coins
                tx_orphan_2_valid,  # The valid transaction (with sufficient fee)
            ]
        }
        # Transactions that do not end up in the mempool
        # tx_orphan_no_fee, because it has too low fee (p2ps[0] is not disconnected for relaying that tx)
        # tx_orphan_invaid, because it has negative fee (p2ps[1] is disconnected for relaying that tx)

        wait_until(lambda: 1 == len(node.getpeerinfo()),
                   timeout=12)  # p2ps[1] is no longer connected
        assert_equal(expected_mempool, set(node.getrawmempool()))

        # restart node with sending BIP61 messages disabled, check that it disconnects without sending the reject message
        self.log.info(
            'Test a transaction that is rejected, with BIP61 disabled')
        self.restart_node(0, ['-enablebip61=0', '-persistmempool=0'])
        self.reconnect_p2p(num_connections=1)
        with node.assert_debug_log(expected_msgs=[
                "{} from peer=0 was not accepted: mandatory-script-verify-flag-failed (Invalid OP_IF construction) (code 16)"
                .format(tx1.hash),
                "disconnecting peer=0",
        ]):
            node.p2p.send_txs_and_test([tx1],
                                       node,
                                       success=False,
                                       expect_disconnect=True)
        # send_txs_and_test will have waited for disconnect, so we can safely check that no reject has been received
        assert_equal(node.p2p.reject_code_received, None)
Ejemplo n.º 15
0
    def decoderawtransaction_asm_sighashtype(self):
        """Test decoding scripts via RPC command "decoderawtransaction".

        This test is in with the "decodescript" tests because they are testing the same "asm" script decodes.
        """

        # this test case uses a random plain vanilla mainnet transaction with a single P2PKH input and output
        tx = '010000000001696a20784a2c70143f634e95227dbdfdf0ecd51647052e70854512235f5986ca010000008a47304402207174775824bec6c2700023309a168231ec80b82c6069282f5133e6f11cbb04460220570edc55c7c5da2ca687ebd0372d3546ebc3f810516a002350cac72dfe192dfb014104d3f898e6487787910a690410b7a917ef198905c27fb9d3b0a42da12aceae0544fc7088d239d9a48f2828a15a09e84043001f27cc80d162cb95404e1210161536ffffffff0101ac2e6a47e85fdc2a5a27334544440f2f5135553a7476f4f5e3b9792da6a58fe001000000000000000000066a047465737400000000'
        rpc_result = self.nodes[0].decoderawtransaction(tx)
        assert_equal(
            '304402207174775824bec6c2700023309a168231ec80b82c6069282f5133e6f11cbb04460220570edc55c7c5da2ca687ebd0372d3546ebc3f810516a002350cac72dfe192dfb[ALL] 04d3f898e6487787910a690410b7a917ef198905c27fb9d3b0a42da12aceae0544fc7088d239d9a48f2828a15a09e84043001f27cc80d162cb95404e1210161536',
            rpc_result['vin'][0]['scriptSig']['asm'])

        # this test case uses a mainnet transaction that has a P2SH input and both P2PKH and P2SH outputs.
        # it's from James D'Angelo's awesome introductory videos about multisig: https://www.youtube.com/watch?v=zIbUSaZBJgU and https://www.youtube.com/watch?v=OSA1pwlaypc
        # verify that we have not altered scriptPubKey decoding.
        tx = '0100000000018d1f5635abd06e2c7e2ddf58dc85b3de111e4ad6e0ab51bb0dcf5e84126d927300000000fdfe0000483045022100ae3b4e589dfc9d48cb82d41008dc5fa6a86f94d5c54f9935531924602730ab8002202f88cf464414c4ed9fa11b773c5ee944f66e9b05cc1e51d97abc22ce098937ea01483045022100b44883be035600e9328a01b66c7d8439b74db64187e76b99a68f7893b701d5380220225bf286493e4c4adcf928c40f785422572eb232f84a0b83b0dea823c3a19c75014c695221020743d44be989540d27b1b4bbbcfd17721c337cb6bc9af20eb8a32520b393532f2102c0120a1dda9e51a938d39ddd9fe0ebc45ea97e1d27a7cbd671d5431416d3dd87210213820eb3d5f509d7438c9eeecb4157b2f595105e7cd564b3cdbb9ead3da41eed53aeffffffff0201ac2e6a47e85fdc2a5a27334544440f2f5135553a7476f4f5e3b9792da6a58fe0010000000000001e61001976a914dc863734a218bfe83ef770ee9d41a27f824a6e5688ac01ac2e6a47e85fdc2a5a27334544440f2f5135553a7476f4f5e3b9792da6a58fe0010000000000022aee0017a9142a5edea39971049a540474c6a99edf0aa4074c588700000000'
        rpc_result = self.nodes[0].decoderawtransaction(tx)
        assert_equal(
            '0640baa19c5df568c1fef1685cf251c33efe2cda37193f3dc2e6b5115774f30a',
            rpc_result['txid'])
        assert_equal(
            '0 3045022100ae3b4e589dfc9d48cb82d41008dc5fa6a86f94d5c54f9935531924602730ab8002202f88cf464414c4ed9fa11b773c5ee944f66e9b05cc1e51d97abc22ce098937ea[ALL] 3045022100b44883be035600e9328a01b66c7d8439b74db64187e76b99a68f7893b701d5380220225bf286493e4c4adcf928c40f785422572eb232f84a0b83b0dea823c3a19c75[ALL] 5221020743d44be989540d27b1b4bbbcfd17721c337cb6bc9af20eb8a32520b393532f2102c0120a1dda9e51a938d39ddd9fe0ebc45ea97e1d27a7cbd671d5431416d3dd87210213820eb3d5f509d7438c9eeecb4157b2f595105e7cd564b3cdbb9ead3da41eed53ae',
            rpc_result['vin'][0]['scriptSig']['asm'])
        assert_equal(
            'OP_DUP OP_HASH160 dc863734a218bfe83ef770ee9d41a27f824a6e56 OP_EQUALVERIFY OP_CHECKSIG',
            rpc_result['vout'][0]['scriptPubKey']['asm'])
        assert_equal(
            'OP_HASH160 2a5edea39971049a540474c6a99edf0aa4074c58 OP_EQUAL',
            rpc_result['vout'][1]['scriptPubKey']['asm'])
        txSave = CTransaction()
        txSave.deserialize(BytesIO(hex_str_to_bytes(tx)))

        # make sure that a specifically crafted op_return value will not pass all the IsDERSignature checks and then get decoded as a sighash type
        tx = '0100000000015ded05872fdbda629c7d3d02b194763ce3b9b1535ea884e3c8e765d42e316724020000006b48304502204c10d4064885c42638cbff3585915b322de33762598321145ba033fc796971e2022100bb153ad3baa8b757e30a2175bd32852d2e1cb9080f84d7e32fcdfd667934ef1b012103163c0ff73511ea1743fb5b98384a2ff09dd06949488028fd819f4d83f56264efffffffff0201ac2e6a47e85fdc2a5a27334544440f2f5135553a7476f4f5e3b9792da6a58fe0010000000000000000000b6a0930060201000201000101ac2e6a47e85fdc2a5a27334544440f2f5135553a7476f4f5e3b9792da6a58fe0010000000000013880001976a9141cabd296e753837c086da7a45a6c2fe0d49d7b7b88ac00000000'
        rpc_result = self.nodes[0].decoderawtransaction(tx)
        assert_equal('OP_RETURN 300602010002010001',
                     rpc_result['vout'][0]['scriptPubKey']['asm'])

        # verify that we have not altered scriptPubKey processing even of a specially crafted P2PKH pubkeyhash and P2SH redeem script hash that is made to pass the der signature checks
        tx = '0100000000018d1f5635abd06e2c7e2ddf58dc85b3de111e4ad6e0ab51bb0dcf5e84126d927300000000fdfe0000483045022100ae3b4e589dfc9d48cb82d41008dc5fa6a86f94d5c54f9935531924602730ab8002202f88cf464414c4ed9fa11b773c5ee944f66e9b05cc1e51d97abc22ce098937ea01483045022100b44883be035600e9328a01b66c7d8439b74db64187e76b99a68f7893b701d5380220225bf286493e4c4adcf928c40f785422572eb232f84a0b83b0dea823c3a19c75014c695221020743d44be989540d27b1b4bbbcfd17721c337cb6bc9af20eb8a32520b393532f2102c0120a1dda9e51a938d39ddd9fe0ebc45ea97e1d27a7cbd671d5431416d3dd87210213820eb3d5f509d7438c9eeecb4157b2f595105e7cd564b3cdbb9ead3da41eed53aeffffffff0201ac2e6a47e85fdc2a5a27334544440f2f5135553a7476f4f5e3b9792da6a58fe0010000000000001e61001976a914301102070101010101010102060101010101010188ac01ac2e6a47e85fdc2a5a27334544440f2f5135553a7476f4f5e3b9792da6a58fe0010000000000022aee0017a91430110207010101010101010206010101010101018700000000'
        rpc_result = self.nodes[0].decoderawtransaction(tx)
        assert_equal(
            'OP_DUP OP_HASH160 3011020701010101010101020601010101010101 OP_EQUALVERIFY OP_CHECKSIG',
            rpc_result['vout'][0]['scriptPubKey']['asm'])
        assert_equal(
            'OP_HASH160 3011020701010101010101020601010101010101 OP_EQUAL',
            rpc_result['vout'][1]['scriptPubKey']['asm'])

        # some more full transaction tests of varying specific scriptSigs. used instead of
        # tests in decodescript_script_sig because the decodescript RPC is specifically
        # for working on scriptPubKeys (argh!).
        push_signature = bytes_to_hex_str(
            txSave.vin[0].scriptSig)[2:(0x48 * 2 + 4)]
        signature = push_signature[2:]
        der_signature = signature[:-2]
        signature_sighash_decoded = der_signature + '[ALL]'
        signature_2 = der_signature + '82'
        push_signature_2 = '48' + signature_2
        signature_2_sighash_decoded = der_signature + '[NONE|ANYONECANPAY]'

        # 1) P2PK scriptSig
        txSave.vin[0].scriptSig = hex_str_to_bytes(push_signature)
        rpc_result = self.nodes[0].decoderawtransaction(
            bytes_to_hex_str(txSave.serialize()))
        assert_equal(signature_sighash_decoded,
                     rpc_result['vin'][0]['scriptSig']['asm'])

        # make sure that the sighash decodes come out correctly for a more complex / lesser used case.
        txSave.vin[0].scriptSig = hex_str_to_bytes(push_signature_2)
        rpc_result = self.nodes[0].decoderawtransaction(
            bytes_to_hex_str(txSave.serialize()))
        assert_equal(signature_2_sighash_decoded,
                     rpc_result['vin'][0]['scriptSig']['asm'])

        # 2) multisig scriptSig
        txSave.vin[0].scriptSig = hex_str_to_bytes('00' + push_signature +
                                                   push_signature_2)
        rpc_result = self.nodes[0].decoderawtransaction(
            bytes_to_hex_str(txSave.serialize()))
        assert_equal(
            '0 ' + signature_sighash_decoded + ' ' +
            signature_2_sighash_decoded,
            rpc_result['vin'][0]['scriptSig']['asm'])

        # 3) test a scriptSig that contains more than push operations.
        # in fact, it contains an OP_RETURN with data specially crafted to cause improper decode if the code does not catch it.
        txSave.vin[0].scriptSig = hex_str_to_bytes(
            '6a143011020701010101010101020601010101010101')
        rpc_result = self.nodes[0].decoderawtransaction(
            bytes_to_hex_str(txSave.serialize()))
        assert_equal('OP_RETURN 3011020701010101010101020601010101010101',
                     rpc_result['vin'][0]['scriptSig']['asm'])
Ejemplo n.º 16
0
    def run_test(self):
        self.nodes[0].generate(161)  # block 161

        self.log.info(
            "Verify sigops are counted in GBT with pre-BIP141 rules before the fork"
        )
        txid = self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), 1)
        tmpl = self.nodes[0].getblocktemplate({'rules': ['segwit']})
        assert tmpl['sizelimit'] == 1000000
        assert 'weightlimit' not in tmpl
        assert tmpl['sigoplimit'] == 20000
        assert tmpl['transactions'][0]['hash'] == txid
        assert tmpl['transactions'][0]['sigops'] == 2
        tmpl = self.nodes[0].getblocktemplate({'rules': ['segwit']})
        assert tmpl['sizelimit'] == 1000000
        assert 'weightlimit' not in tmpl
        assert tmpl['sigoplimit'] == 20000
        assert tmpl['transactions'][0]['hash'] == txid
        assert tmpl['transactions'][0]['sigops'] == 2
        self.nodes[0].generate(1)  # block 162

        balance_presetup = self.nodes[0].getbalance()
        self.pubkey = []
        p2sh_ids = [
        ]  # p2sh_ids[NODE][VER] is an array of txids that spend to a witness version VER pkscript to an address for NODE embedded in p2sh
        wit_ids = [
        ]  # wit_ids[NODE][VER] is an array of txids that spend to a witness version VER pkscript to an address for NODE via bare witness
        for i in range(3):
            newaddress = self.nodes[i].getnewaddress()
            self.pubkey.append(
                self.nodes[i].getaddressinfo(newaddress)["pubkey"])
            multiscript = CScript([
                OP_1,
                hex_str_to_bytes(self.pubkey[-1]), OP_1, OP_CHECKMULTISIG
            ])
            p2sh_ms_addr = self.nodes[i].addmultisigaddress(
                1, [self.pubkey[-1]], '', 'p2sh-segwit')['address']
            bip173_ms_addr = self.nodes[i].addmultisigaddress(
                1, [self.pubkey[-1]], '', 'bech32')['address']
            assert_equal(p2sh_ms_addr, script_to_p2sh_p2wsh(multiscript))
            assert_equal(bip173_ms_addr, script_to_p2wsh(multiscript))
            p2sh_ids.append([])
            wit_ids.append([])
            for v in range(2):
                p2sh_ids[i].append([])
                wit_ids[i].append([])

        for i in range(5):
            for n in range(3):
                for v in range(2):
                    wit_ids[n][v].append(
                        send_to_witness(v, self.nodes[0],
                                        find_spendable_utxo(self.nodes[0], 50),
                                        self.pubkey[n], False,
                                        Decimal("49.999")))
                    p2sh_ids[n][v].append(
                        send_to_witness(v, self.nodes[0],
                                        find_spendable_utxo(self.nodes[0], 50),
                                        self.pubkey[n], True,
                                        Decimal("49.999")))

        self.nodes[0].generate(1)  # block 163
        self.sync_blocks()

        # Make sure all nodes recognize the transactions as theirs
        assert_equal(self.nodes[0].getbalance(),
                     balance_presetup - 60 * 50 + 20 * Decimal("49.999") + 50)
        assert_equal(self.nodes[1].getbalance(), 20 * Decimal("49.999"))
        assert_equal(self.nodes[2].getbalance(), 20 * Decimal("49.999"))

        self.nodes[0].generate(260)  # block 423
        self.sync_blocks()

        self.log.info(
            "Verify witness txs are skipped for mining before the fork")
        self.skip_mine(self.nodes[2], wit_ids[NODE_2][WIT_V0][0],
                       True)  # block 424
        self.skip_mine(self.nodes[2], wit_ids[NODE_2][WIT_V1][0],
                       True)  # block 425
        self.skip_mine(self.nodes[2], p2sh_ids[NODE_2][WIT_V0][0],
                       True)  # block 426
        self.skip_mine(self.nodes[2], p2sh_ids[NODE_2][WIT_V1][0],
                       True)  # block 427

        self.log.info(
            "Verify unsigned p2sh witness txs without a redeem script are invalid"
        )
        self.fail_accept(self.nodes[2], "mandatory-script-verify-flag",
                         p2sh_ids[NODE_2][WIT_V0][1], False)
        self.fail_accept(self.nodes[2], "mandatory-script-verify-flag",
                         p2sh_ids[NODE_2][WIT_V1][1], False)

        self.nodes[2].generate(4)  # blocks 428-431

        self.log.info(
            "Verify previous witness txs skipped for mining can now be mined")
        assert_equal(len(self.nodes[2].getrawmempool()), 4)
        blockhash = self.nodes[2].generate(1)[
            0]  # block 432 (first block with new rules; 432 = 144 * 3)
        self.sync_blocks()
        assert_equal(len(self.nodes[2].getrawmempool()), 0)
        segwit_tx_list = self.nodes[2].getblock(blockhash)["tx"]
        assert_equal(len(segwit_tx_list), 5)

        self.log.info(
            "Verify default node can't accept txs with missing witness")
        # unsigned, no scriptsig
        self.fail_accept(self.nodes[0], "mandatory-script-verify-flag",
                         wit_ids[NODE_0][WIT_V0][0], False)
        self.fail_accept(self.nodes[0], "mandatory-script-verify-flag",
                         wit_ids[NODE_0][WIT_V1][0], False)
        self.fail_accept(self.nodes[0], "mandatory-script-verify-flag",
                         p2sh_ids[NODE_0][WIT_V0][0], False)
        self.fail_accept(self.nodes[0], "mandatory-script-verify-flag",
                         p2sh_ids[NODE_0][WIT_V1][0], False)
        # unsigned with redeem script
        self.fail_accept(self.nodes[0], "mandatory-script-verify-flag",
                         p2sh_ids[NODE_0][WIT_V0][0], False,
                         witness_script(False, self.pubkey[0]))
        self.fail_accept(self.nodes[0], "mandatory-script-verify-flag",
                         p2sh_ids[NODE_0][WIT_V1][0], False,
                         witness_script(True, self.pubkey[0]))

        self.log.info(
            "Verify block and transaction serialization rpcs return differing serializations depending on rpc serialization flag"
        )
        assert self.nodes[2].getblock(
            blockhash, False) != self.nodes[0].getblock(blockhash, False)
        assert self.nodes[1].getblock(blockhash,
                                      False) == self.nodes[2].getblock(
                                          blockhash, False)

        for tx_id in segwit_tx_list:
            tx = FromHex(CTransaction(),
                         self.nodes[2].gettransaction(tx_id)["hex"])
            assert self.nodes[2].getrawtransaction(
                tx_id, False, blockhash) != self.nodes[0].getrawtransaction(
                    tx_id, False, blockhash)
            assert self.nodes[1].getrawtransaction(
                tx_id, False, blockhash) == self.nodes[2].getrawtransaction(
                    tx_id, False, blockhash)
            assert self.nodes[0].getrawtransaction(
                tx_id, False,
                blockhash) != self.nodes[2].gettransaction(tx_id)["hex"]
            assert self.nodes[1].getrawtransaction(
                tx_id, False,
                blockhash) == self.nodes[2].gettransaction(tx_id)["hex"]
            assert self.nodes[0].getrawtransaction(
                tx_id, False,
                blockhash) == tx.serialize_without_witness().hex()

        self.log.info(
            "Verify witness txs without witness data are invalid after the fork"
        )
        self.fail_accept(
            self.nodes[2],
            'non-mandatory-script-verify-flag (Witness program hash mismatch) (code 64)',
            wit_ids[NODE_2][WIT_V0][2],
            sign=False)
        self.fail_accept(
            self.nodes[2],
            'non-mandatory-script-verify-flag (Witness program was passed an empty witness) (code 64)',
            wit_ids[NODE_2][WIT_V1][2],
            sign=False)
        self.fail_accept(
            self.nodes[2],
            'non-mandatory-script-verify-flag (Witness program hash mismatch) (code 64)',
            p2sh_ids[NODE_2][WIT_V0][2],
            sign=False,
            redeem_script=witness_script(False, self.pubkey[2]))
        self.fail_accept(
            self.nodes[2],
            'non-mandatory-script-verify-flag (Witness program was passed an empty witness) (code 64)',
            p2sh_ids[NODE_2][WIT_V1][2],
            sign=False,
            redeem_script=witness_script(True, self.pubkey[2]))

        self.log.info("Verify default node can now use witness txs")
        self.success_mine(self.nodes[0], wit_ids[NODE_0][WIT_V0][0],
                          True)  # block 432
        self.success_mine(self.nodes[0], wit_ids[NODE_0][WIT_V1][0],
                          True)  # block 433
        self.success_mine(self.nodes[0], p2sh_ids[NODE_0][WIT_V0][0],
                          True)  # block 434
        self.success_mine(self.nodes[0], p2sh_ids[NODE_0][WIT_V1][0],
                          True)  # block 435

        self.log.info(
            "Verify sigops are counted in GBT with BIP141 rules after the fork"
        )
        txid = self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), 1)
        tmpl = self.nodes[0].getblocktemplate({'rules': ['segwit']})
        assert tmpl[
            'sizelimit'] >= 3999577  # actual maximum size is lower due to minimum mandatory non-witness data
        assert tmpl['weightlimit'] == 4000000
        assert tmpl['sigoplimit'] == 80000
        assert tmpl['transactions'][0]['txid'] == txid
        assert tmpl['transactions'][0]['sigops'] == 8

        self.nodes[0].generate(1)  # Mine a block to clear the gbt cache

        self.log.info(
            "Non-segwit miners are able to use GBT response after activation.")
        # Create a 3-tx chain: tx1 (non-segwit input, paying to a segwit output) ->
        #                      tx2 (segwit input, paying to a non-segwit output) ->
        #                      tx3 (non-segwit input, paying to a non-segwit output).
        # tx1 is allowed to appear in the block, but no others.
        txid1 = send_to_witness(1, self.nodes[0],
                                find_spendable_utxo(self.nodes[0], 50),
                                self.pubkey[0], False, Decimal("49.996"))
        hex_tx = self.nodes[0].gettransaction(txid)['hex']
        tx = FromHex(CTransaction(), hex_tx)
        assert tx.wit.is_null()  # This should not be a segwit input
        assert txid1 in self.nodes[0].getrawmempool()

        # Now create tx2, which will spend from txid1.
        tx = CTransaction()
        tx.vin.append(CTxIn(COutPoint(int(txid1, 16), 0), b''))
        tx.vout.append(
            CTxOut(int(49.99 * COIN),
                   CScript([OP_TRUE, OP_DROP] * 15 + [OP_TRUE])))
        tx2_hex = self.nodes[0].signrawtransactionwithwallet(ToHex(tx))['hex']
        txid2 = self.nodes[0].sendrawtransaction(tx2_hex)
        tx = FromHex(CTransaction(), tx2_hex)
        assert not tx.wit.is_null()

        # Now create tx3, which will spend from txid2
        tx = CTransaction()
        tx.vin.append(CTxIn(COutPoint(int(txid2, 16), 0), b""))
        tx.vout.append(
            CTxOut(int(49.95 * COIN),
                   CScript([OP_TRUE, OP_DROP] * 15 + [OP_TRUE])))  # Huge fee
        tx.calc_sha256()
        txid3 = self.nodes[0].sendrawtransaction(ToHex(tx))
        assert tx.wit.is_null()
        assert txid3 in self.nodes[0].getrawmempool()

        # Check that getblocktemplate includes all transactions.
        template = self.nodes[0].getblocktemplate({"rules": ["segwit"]})
        template_txids = [t['txid'] for t in template['transactions']]
        assert txid1 in template_txids
        assert txid2 in template_txids
        assert txid3 in template_txids

        # Check that wtxid is properly reported in mempool entry
        assert_equal(int(self.nodes[0].getmempoolentry(txid3)["wtxid"], 16),
                     tx.calc_sha256(True))

        # Mine a block to clear the gbt cache again.
        self.nodes[0].generate(1)

        self.log.info("Verify behaviour of importaddress and listunspent")

        # Some public keys to be used later
        pubkeys = [
            "0363D44AABD0F1699138239DF2F042C3282C0671CC7A76826A55C8203D90E39242",  # cPiM8Ub4heR9NBYmgVzJQiUH1if44GSBGiqaeJySuL2BKxubvgwb
            "02D3E626B3E616FC8662B489C123349FECBFC611E778E5BE739B257EAE4721E5BF",  # cPpAdHaD6VoYbW78kveN2bsvb45Q7G5PhaPApVUGwvF8VQ9brD97
            "04A47F2CBCEFFA7B9BCDA184E7D5668D3DA6F9079AD41E422FA5FD7B2D458F2538A62F5BD8EC85C2477F39650BD391EA6250207065B2A81DA8B009FC891E898F0E",  # 91zqCU5B9sdWxzMt1ca3VzbtVm2YM6Hi5Rxn4UDtxEaN9C9nzXV
            "02A47F2CBCEFFA7B9BCDA184E7D5668D3DA6F9079AD41E422FA5FD7B2D458F2538",  # cPQFjcVRpAUBG8BA9hzr2yEzHwKoMgLkJZBBtK9vJnvGJgMjzTbd
            "036722F784214129FEB9E8129D626324F3F6716555B603FFE8300BBCB882151228",  # cQGtcm34xiLjB1v7bkRa4V3aAc9tS2UTuBZ1UnZGeSeNy627fN66
            "0266A8396EE936BF6D99D17920DB21C6C7B1AB14C639D5CD72B300297E416FD2EC",  # cTW5mR5M45vHxXkeChZdtSPozrFwFgmEvTNnanCW6wrqwaCZ1X7K
            "0450A38BD7F0AC212FEBA77354A9B036A32E0F7C81FC4E0C5ADCA7C549C4505D2522458C2D9AE3CEFD684E039194B72C8A10F9CB9D4764AB26FCC2718D421D3B84",  # 92h2XPssjBpsJN5CqSP7v9a7cf2kgDunBC6PDFwJHMACM1rrVBJ
        ]

        # Import a compressed key and an uncompressed key, generate some multisig addresses
        self.nodes[0].importprivkey(
            "92e6XLo5jVAVwrQKPNTs93oQco8f8sDNBcpv73Dsrs397fQtFQn")
        uncompressed_spendable_address = ["mvozP4UwyGD2mGZU4D2eMvMLPB9WkMmMQu"]
        self.nodes[0].importprivkey(
            "cNC8eQ5dg3mFAVePDX4ddmPYpPbw41r9bm2jd1nLJT77e6RrzTRR")
        compressed_spendable_address = ["mmWQubrDomqpgSYekvsU7HWEVjLFHAakLe"]
        assert not self.nodes[0].getaddressinfo(
            uncompressed_spendable_address[0])['iscompressed']
        assert self.nodes[0].getaddressinfo(
            compressed_spendable_address[0])['iscompressed']

        self.nodes[0].importpubkey(pubkeys[0])
        compressed_solvable_address = [key_to_p2pkh(pubkeys[0])]
        self.nodes[0].importpubkey(pubkeys[1])
        compressed_solvable_address.append(key_to_p2pkh(pubkeys[1]))
        self.nodes[0].importpubkey(pubkeys[2])
        uncompressed_solvable_address = [key_to_p2pkh(pubkeys[2])]

        spendable_anytime = [
        ]  # These outputs should be seen anytime after importprivkey and addmultisigaddress
        spendable_after_importaddress = [
        ]  # These outputs should be seen after importaddress
        solvable_after_importaddress = [
        ]  # These outputs should be seen after importaddress but not spendable
        unsolvable_after_importaddress = [
        ]  # These outputs should be unsolvable after importaddress
        solvable_anytime = [
        ]  # These outputs should be solvable after importpubkey
        unseen_anytime = []  # These outputs should never be seen

        uncompressed_spendable_address.append(self.nodes[0].addmultisigaddress(
            2, [
                uncompressed_spendable_address[0],
                compressed_spendable_address[0]
            ])['address'])
        uncompressed_spendable_address.append(self.nodes[0].addmultisigaddress(
            2, [
                uncompressed_spendable_address[0],
                uncompressed_spendable_address[0]
            ])['address'])
        compressed_spendable_address.append(self.nodes[0].addmultisigaddress(
            2,
            [compressed_spendable_address[0], compressed_spendable_address[0]
             ])['address'])
        uncompressed_solvable_address.append(self.nodes[0].addmultisigaddress(
            2, [
                compressed_spendable_address[0],
                uncompressed_solvable_address[0]
            ])['address'])
        compressed_solvable_address.append(self.nodes[0].addmultisigaddress(
            2,
            [compressed_spendable_address[0], compressed_solvable_address[0]
             ])['address'])
        compressed_solvable_address.append(self.nodes[0].addmultisigaddress(
            2,
            [compressed_solvable_address[0], compressed_solvable_address[1]
             ])['address'])

        # Test multisig_without_privkey
        # We have 2 public keys without private keys, use addmultisigaddress to add to wallet.
        # Money sent to P2SH of multisig of this should only be seen after importaddress with the BASE58 P2SH address.

        multisig_without_privkey_address = self.nodes[0].addmultisigaddress(
            2, [pubkeys[3], pubkeys[4]])['address']
        script = CScript([
            OP_2,
            hex_str_to_bytes(pubkeys[3]),
            hex_str_to_bytes(pubkeys[4]), OP_2, OP_CHECKMULTISIG
        ])
        solvable_after_importaddress.append(
            CScript([OP_HASH160, hash160(script), OP_EQUAL]))

        for i in compressed_spendable_address:
            v = self.nodes[0].getaddressinfo(i)
            if (v['isscript']):
                [bare, p2sh, p2wsh,
                 p2sh_p2wsh] = self.p2sh_address_to_script(v)
                # p2sh multisig with compressed keys should always be spendable
                spendable_anytime.extend([p2sh])
                # bare multisig can be watched and signed, but is not treated as ours
                solvable_after_importaddress.extend([bare])
                # P2WSH and P2SH(P2WSH) multisig with compressed keys are spendable after direct importaddress
                spendable_after_importaddress.extend([p2wsh, p2sh_p2wsh])
            else:
                [
                    p2wpkh, p2sh_p2wpkh, p2pk, p2pkh, p2sh_p2pk, p2sh_p2pkh,
                    p2wsh_p2pk, p2wsh_p2pkh, p2sh_p2wsh_p2pk, p2sh_p2wsh_p2pkh
                ] = self.p2pkh_address_to_script(v)
                # normal P2PKH and P2PK with compressed keys should always be spendable
                spendable_anytime.extend([p2pkh, p2pk])
                # P2SH_P2PK, P2SH_P2PKH with compressed keys are spendable after direct importaddress
                spendable_after_importaddress.extend([
                    p2sh_p2pk, p2sh_p2pkh, p2wsh_p2pk, p2wsh_p2pkh,
                    p2sh_p2wsh_p2pk, p2sh_p2wsh_p2pkh
                ])
                # P2WPKH and P2SH_P2WPKH with compressed keys should always be spendable
                spendable_anytime.extend([p2wpkh, p2sh_p2wpkh])

        for i in uncompressed_spendable_address:
            v = self.nodes[0].getaddressinfo(i)
            if (v['isscript']):
                [bare, p2sh, p2wsh,
                 p2sh_p2wsh] = self.p2sh_address_to_script(v)
                # p2sh multisig with uncompressed keys should always be spendable
                spendable_anytime.extend([p2sh])
                # bare multisig can be watched and signed, but is not treated as ours
                solvable_after_importaddress.extend([bare])
                # P2WSH and P2SH(P2WSH) multisig with uncompressed keys are never seen
                unseen_anytime.extend([p2wsh, p2sh_p2wsh])
            else:
                [
                    p2wpkh, p2sh_p2wpkh, p2pk, p2pkh, p2sh_p2pk, p2sh_p2pkh,
                    p2wsh_p2pk, p2wsh_p2pkh, p2sh_p2wsh_p2pk, p2sh_p2wsh_p2pkh
                ] = self.p2pkh_address_to_script(v)
                # normal P2PKH and P2PK with uncompressed keys should always be spendable
                spendable_anytime.extend([p2pkh, p2pk])
                # P2SH_P2PK and P2SH_P2PKH are spendable after direct importaddress
                spendable_after_importaddress.extend([p2sh_p2pk, p2sh_p2pkh])
                # Witness output types with uncompressed keys are never seen
                unseen_anytime.extend([
                    p2wpkh, p2sh_p2wpkh, p2wsh_p2pk, p2wsh_p2pkh,
                    p2sh_p2wsh_p2pk, p2sh_p2wsh_p2pkh
                ])

        for i in compressed_solvable_address:
            v = self.nodes[0].getaddressinfo(i)
            if (v['isscript']):
                # Multisig without private is not seen after addmultisigaddress, but seen after importaddress
                [bare, p2sh, p2wsh,
                 p2sh_p2wsh] = self.p2sh_address_to_script(v)
                solvable_after_importaddress.extend(
                    [bare, p2sh, p2wsh, p2sh_p2wsh])
            else:
                [
                    p2wpkh, p2sh_p2wpkh, p2pk, p2pkh, p2sh_p2pk, p2sh_p2pkh,
                    p2wsh_p2pk, p2wsh_p2pkh, p2sh_p2wsh_p2pk, p2sh_p2wsh_p2pkh
                ] = self.p2pkh_address_to_script(v)
                # normal P2PKH, P2PK, P2WPKH and P2SH_P2WPKH with compressed keys should always be seen
                solvable_anytime.extend([p2pkh, p2pk, p2wpkh, p2sh_p2wpkh])
                # P2SH_P2PK, P2SH_P2PKH with compressed keys are seen after direct importaddress
                solvable_after_importaddress.extend([
                    p2sh_p2pk, p2sh_p2pkh, p2wsh_p2pk, p2wsh_p2pkh,
                    p2sh_p2wsh_p2pk, p2sh_p2wsh_p2pkh
                ])

        for i in uncompressed_solvable_address:
            v = self.nodes[0].getaddressinfo(i)
            if (v['isscript']):
                [bare, p2sh, p2wsh,
                 p2sh_p2wsh] = self.p2sh_address_to_script(v)
                # Base uncompressed multisig without private is not seen after addmultisigaddress, but seen after importaddress
                solvable_after_importaddress.extend([bare, p2sh])
                # P2WSH and P2SH(P2WSH) multisig with uncompressed keys are never seen
                unseen_anytime.extend([p2wsh, p2sh_p2wsh])
            else:
                [
                    p2wpkh, p2sh_p2wpkh, p2pk, p2pkh, p2sh_p2pk, p2sh_p2pkh,
                    p2wsh_p2pk, p2wsh_p2pkh, p2sh_p2wsh_p2pk, p2sh_p2wsh_p2pkh
                ] = self.p2pkh_address_to_script(v)
                # normal P2PKH and P2PK with uncompressed keys should always be seen
                solvable_anytime.extend([p2pkh, p2pk])
                # P2SH_P2PK, P2SH_P2PKH with uncompressed keys are seen after direct importaddress
                solvable_after_importaddress.extend([p2sh_p2pk, p2sh_p2pkh])
                # Witness output types with uncompressed keys are never seen
                unseen_anytime.extend([
                    p2wpkh, p2sh_p2wpkh, p2wsh_p2pk, p2wsh_p2pkh,
                    p2sh_p2wsh_p2pk, p2sh_p2wsh_p2pkh
                ])

        op1 = CScript([OP_1])
        op0 = CScript([OP_0])
        # 2N7MGY19ti4KDMSzRfPAssP6Pxyuxoi6jLe is the P2SH(P2PKH) version of mjoE3sSrb8ByYEvgnC3Aox86u1CHnfJA4V
        unsolvable_address_key = hex_str_to_bytes(
            "02341AEC7587A51CDE5279E0630A531AEA2615A9F80B17E8D9376327BAEAA59E3D"
        )
        unsolvablep2pkh = CScript([
            OP_DUP, OP_HASH160,
            hash160(unsolvable_address_key), OP_EQUALVERIFY, OP_CHECKSIG
        ])
        unsolvablep2wshp2pkh = CScript([OP_0, sha256(unsolvablep2pkh)])
        p2shop0 = CScript([OP_HASH160, hash160(op0), OP_EQUAL])
        p2wshop1 = CScript([OP_0, sha256(op1)])
        unsolvable_after_importaddress.append(unsolvablep2pkh)
        unsolvable_after_importaddress.append(unsolvablep2wshp2pkh)
        unsolvable_after_importaddress.append(
            op1)  # OP_1 will be imported as script
        unsolvable_after_importaddress.append(p2wshop1)
        unseen_anytime.append(
            op0
        )  # OP_0 will be imported as P2SH address with no script provided
        unsolvable_after_importaddress.append(p2shop0)

        spendable_txid = []
        solvable_txid = []
        spendable_txid.append(
            self.mine_and_test_listunspent(spendable_anytime, 2))
        solvable_txid.append(
            self.mine_and_test_listunspent(solvable_anytime, 1))
        self.mine_and_test_listunspent(
            spendable_after_importaddress + solvable_after_importaddress +
            unseen_anytime + unsolvable_after_importaddress, 0)

        importlist = []
        for i in compressed_spendable_address + uncompressed_spendable_address + compressed_solvable_address + uncompressed_solvable_address:
            v = self.nodes[0].getaddressinfo(i)
            if (v['isscript']):
                bare = hex_str_to_bytes(v['hex'])
                importlist.append(bare.hex())
                importlist.append(CScript([OP_0, sha256(bare)]).hex())
            else:
                pubkey = hex_str_to_bytes(v['pubkey'])
                p2pk = CScript([pubkey, OP_CHECKSIG])
                p2pkh = CScript([
                    OP_DUP, OP_HASH160,
                    hash160(pubkey), OP_EQUALVERIFY, OP_CHECKSIG
                ])
                importlist.append(p2pk.hex())
                importlist.append(p2pkh.hex())
                importlist.append(CScript([OP_0, hash160(pubkey)]).hex())
                importlist.append(CScript([OP_0, sha256(p2pk)]).hex())
                importlist.append(CScript([OP_0, sha256(p2pkh)]).hex())

        importlist.append(unsolvablep2pkh.hex())
        importlist.append(unsolvablep2wshp2pkh.hex())
        importlist.append(op1.hex())
        importlist.append(p2wshop1.hex())

        for i in importlist:
            # import all generated addresses. The wallet already has the private keys for some of these, so catch JSON RPC
            # exceptions and continue.
            try_rpc(
                -4,
                "The wallet already contains the private key for this address or script",
                self.nodes[0].importaddress, i, "", False, True)

        self.nodes[0].importaddress(
            script_to_p2sh(op0))  # import OP_0 as address only
        self.nodes[0].importaddress(
            multisig_without_privkey_address)  # Test multisig_without_privkey

        spendable_txid.append(
            self.mine_and_test_listunspent(
                spendable_anytime + spendable_after_importaddress, 2))
        solvable_txid.append(
            self.mine_and_test_listunspent(
                solvable_anytime + solvable_after_importaddress, 1))
        self.mine_and_test_listunspent(unsolvable_after_importaddress, 1)
        self.mine_and_test_listunspent(unseen_anytime, 0)

        spendable_txid.append(
            self.mine_and_test_listunspent(
                spendable_anytime + spendable_after_importaddress, 2))
        solvable_txid.append(
            self.mine_and_test_listunspent(
                solvable_anytime + solvable_after_importaddress, 1))
        self.mine_and_test_listunspent(unsolvable_after_importaddress, 1)
        self.mine_and_test_listunspent(unseen_anytime, 0)

        # Repeat some tests. This time we don't add witness scripts with importaddress
        # Import a compressed key and an uncompressed key, generate some multisig addresses
        self.nodes[0].importprivkey(
            "927pw6RW8ZekycnXqBQ2JS5nPyo1yRfGNN8oq74HeddWSpafDJH")
        uncompressed_spendable_address = ["mguN2vNSCEUh6rJaXoAVwY3YZwZvEmf5xi"]
        self.nodes[0].importprivkey(
            "cMcrXaaUC48ZKpcyydfFo8PxHAjpsYLhdsp6nmtB3E2ER9UUHWnw")
        compressed_spendable_address = ["n1UNmpmbVUJ9ytXYXiurmGPQ3TRrXqPWKL"]

        self.nodes[0].importpubkey(pubkeys[5])
        compressed_solvable_address = [key_to_p2pkh(pubkeys[5])]
        self.nodes[0].importpubkey(pubkeys[6])
        uncompressed_solvable_address = [key_to_p2pkh(pubkeys[6])]

        unseen_anytime = []  # These outputs should never be seen
        solvable_anytime = [
        ]  # These outputs should be solvable after importpubkey
        unseen_anytime = []  # These outputs should never be seen

        uncompressed_spendable_address.append(self.nodes[0].addmultisigaddress(
            2, [
                uncompressed_spendable_address[0],
                compressed_spendable_address[0]
            ])['address'])
        uncompressed_spendable_address.append(self.nodes[0].addmultisigaddress(
            2, [
                uncompressed_spendable_address[0],
                uncompressed_spendable_address[0]
            ])['address'])
        compressed_spendable_address.append(self.nodes[0].addmultisigaddress(
            2,
            [compressed_spendable_address[0], compressed_spendable_address[0]
             ])['address'])
        uncompressed_solvable_address.append(self.nodes[0].addmultisigaddress(
            2,
            [compressed_solvable_address[0], uncompressed_solvable_address[0]
             ])['address'])
        compressed_solvable_address.append(self.nodes[0].addmultisigaddress(
            2,
            [compressed_spendable_address[0], compressed_solvable_address[0]
             ])['address'])

        premature_witaddress = []

        for i in compressed_spendable_address:
            v = self.nodes[0].getaddressinfo(i)
            if (v['isscript']):
                [bare, p2sh, p2wsh,
                 p2sh_p2wsh] = self.p2sh_address_to_script(v)
                premature_witaddress.append(script_to_p2sh(p2wsh))
            else:
                [
                    p2wpkh, p2sh_p2wpkh, p2pk, p2pkh, p2sh_p2pk, p2sh_p2pkh,
                    p2wsh_p2pk, p2wsh_p2pkh, p2sh_p2wsh_p2pk, p2sh_p2wsh_p2pkh
                ] = self.p2pkh_address_to_script(v)
                # P2WPKH, P2SH_P2WPKH are always spendable
                spendable_anytime.extend([p2wpkh, p2sh_p2wpkh])

        for i in uncompressed_spendable_address + uncompressed_solvable_address:
            v = self.nodes[0].getaddressinfo(i)
            if (v['isscript']):
                [bare, p2sh, p2wsh,
                 p2sh_p2wsh] = self.p2sh_address_to_script(v)
                # P2WSH and P2SH(P2WSH) multisig with uncompressed keys are never seen
                unseen_anytime.extend([p2wsh, p2sh_p2wsh])
            else:
                [
                    p2wpkh, p2sh_p2wpkh, p2pk, p2pkh, p2sh_p2pk, p2sh_p2pkh,
                    p2wsh_p2pk, p2wsh_p2pkh, p2sh_p2wsh_p2pk, p2sh_p2wsh_p2pkh
                ] = self.p2pkh_address_to_script(v)
                # P2WPKH, P2SH_P2WPKH with uncompressed keys are never seen
                unseen_anytime.extend([p2wpkh, p2sh_p2wpkh])

        for i in compressed_solvable_address:
            v = self.nodes[0].getaddressinfo(i)
            if (v['isscript']):
                [bare, p2sh, p2wsh,
                 p2sh_p2wsh] = self.p2sh_address_to_script(v)
                premature_witaddress.append(script_to_p2sh(p2wsh))
            else:
                [
                    p2wpkh, p2sh_p2wpkh, p2pk, p2pkh, p2sh_p2pk, p2sh_p2pkh,
                    p2wsh_p2pk, p2wsh_p2pkh, p2sh_p2wsh_p2pk, p2sh_p2wsh_p2pkh
                ] = self.p2pkh_address_to_script(v)
                # P2SH_P2PK, P2SH_P2PKH with compressed keys are always solvable
                solvable_anytime.extend([p2wpkh, p2sh_p2wpkh])

        self.mine_and_test_listunspent(spendable_anytime, 2)
        self.mine_and_test_listunspent(solvable_anytime, 1)
        self.mine_and_test_listunspent(unseen_anytime, 0)

        # Check that createrawtransaction/decoderawtransaction with non-v0 Bech32 works
        v1_addr = program_to_witness(1, [3, 5])
        v1_tx = self.nodes[0].createrawtransaction(
            [getutxo(spendable_txid[0])], {v1_addr: 1})
        v1_decoded = self.nodes[1].decoderawtransaction(v1_tx)
        assert_equal(v1_decoded['vout'][0]['scriptPubKey']['addresses'][0],
                     v1_addr)
        assert_equal(v1_decoded['vout'][0]['scriptPubKey']['hex'], "51020305")

        # Check that spendable outputs are really spendable
        self.create_and_mine_tx_from_txids(spendable_txid)

        # import all the private keys so solvable addresses become spendable
        self.nodes[0].importprivkey(
            "cPiM8Ub4heR9NBYmgVzJQiUH1if44GSBGiqaeJySuL2BKxubvgwb")
        self.nodes[0].importprivkey(
            "cPpAdHaD6VoYbW78kveN2bsvb45Q7G5PhaPApVUGwvF8VQ9brD97")
        self.nodes[0].importprivkey(
            "91zqCU5B9sdWxzMt1ca3VzbtVm2YM6Hi5Rxn4UDtxEaN9C9nzXV")
        self.nodes[0].importprivkey(
            "cPQFjcVRpAUBG8BA9hzr2yEzHwKoMgLkJZBBtK9vJnvGJgMjzTbd")
        self.nodes[0].importprivkey(
            "cQGtcm34xiLjB1v7bkRa4V3aAc9tS2UTuBZ1UnZGeSeNy627fN66")
        self.nodes[0].importprivkey(
            "cTW5mR5M45vHxXkeChZdtSPozrFwFgmEvTNnanCW6wrqwaCZ1X7K")
        self.create_and_mine_tx_from_txids(solvable_txid)

        # Test that importing native P2WPKH/P2WSH scripts works
        for use_p2wsh in [False, True]:
            if use_p2wsh:
                scriptPubKey = "00203a59f3f56b713fdcf5d1a57357f02c44342cbf306ffe0c4741046837bf90561a"
                transaction = "01000000000100e1f505000000002200203a59f3f56b713fdcf5d1a57357f02c44342cbf306ffe0c4741046837bf90561a00000000"
            else:
                scriptPubKey = "a9142f8c469c2f0084c48e11f998ffbe7efa7549f26d87"
                transaction = "01000000000100e1f5050000000017a9142f8c469c2f0084c48e11f998ffbe7efa7549f26d8700000000"

            self.nodes[1].importaddress(scriptPubKey, "", False)
            rawtxfund = self.nodes[1].fundrawtransaction(transaction)['hex']
            rawtxfund = self.nodes[1].signrawtransactionwithwallet(
                rawtxfund)["hex"]
            txid = self.nodes[1].sendrawtransaction(rawtxfund)

            assert_equal(self.nodes[1].gettransaction(txid, True)["txid"],
                         txid)
            assert_equal(
                self.nodes[1].listtransactions("*", 1, 0, True)[0]["txid"],
                txid)

            # Assert it is properly saved
            self.stop_node(1)
            self.start_node(1)
            assert_equal(self.nodes[1].gettransaction(txid, True)["txid"],
                         txid)
            assert_equal(
                self.nodes[1].listtransactions("*", 1, 0, True)[0]["txid"],
                txid)
Ejemplo n.º 17
0
    def run_test(self):
        node = self.nodes[0]  # convenience reference to the node

        self.bootstrap_p2p()  # Add one p2p connection to the node

        best_block = self.nodes[0].getbestblockhash()
        tip = int(best_block, 16)
        best_block_time = self.nodes[0].getblock(best_block)['time']
        block_time = best_block_time + 1

        self.log.info("Create a new block with an anyone-can-spend coinbase.")
        height = 1
        block = create_block(tip, create_coinbase(height), block_time)
        block.solve()
        # Save the coinbase for later
        block1 = block
        tip = block.sha256
        node.p2p.send_blocks_and_test([block], node, success=True)

        self.log.info("Mature the block.")
        self.nodes[0].generatetoaddress(100, self.nodes[0].get_deterministic_priv_key().address)

        # Iterate through a list of known invalid transaction types, ensuring each is
        # rejected. Some are consensus invalid and some just violate policy.
        for BadTxTemplate in invalid_txs.iter_all_templates():
            self.log.info("Testing invalid transaction: %s", BadTxTemplate.__name__)
            template = BadTxTemplate(spend_block=block1)
            tx = template.get_tx()
            node.p2p.send_txs_and_test(
                [tx], node, success=False,
                expect_disconnect=template.expect_disconnect,
                reject_reason=template.reject_reason,
            )

            if template.expect_disconnect:
                self.log.info("Reconnecting to peer")
                self.reconnect_p2p()

        # Make two p2p connections to provide the node with orphans
        # * p2ps[0] will send valid orphan txs (one with low fee)
        # * p2ps[1] will send an invalid orphan tx (and is later disconnected for that)
        self.reconnect_p2p(num_connections=2)

        self.log.info('Test orphan transaction handling ... ')
        # Create a root transaction that we withhold until all dependent transactions
        # are sent out and in the orphan cache
        SCRIPT_PUB_KEY_OP_TRUE = b'\x51\x75' * 15 + b'\x51'
        tx_withhold = CTransaction()
        tx_withhold.vin.append(CTxIn(outpoint=COutPoint(block1.vtx[0].sha256, 0)))
        tx_withhold.vout.append(CTxOut(nValue=50 * COIN - 12000, scriptPubKey=SCRIPT_PUB_KEY_OP_TRUE))
        tx_withhold.calc_sha256()

        # Our first orphan tx with some outputs to create further orphan txs
        tx_orphan_1 = CTransaction()
        tx_orphan_1.vin.append(CTxIn(outpoint=COutPoint(tx_withhold.sha256, 0)))
        tx_orphan_1.vout = [CTxOut(nValue=10 * COIN, scriptPubKey=SCRIPT_PUB_KEY_OP_TRUE)] * 3
        tx_orphan_1.calc_sha256()

        # A valid transaction with low fee
        tx_orphan_2_no_fee = CTransaction()
        tx_orphan_2_no_fee.vin.append(CTxIn(outpoint=COutPoint(tx_orphan_1.sha256, 0)))
        tx_orphan_2_no_fee.vout.append(CTxOut(nValue=10 * COIN, scriptPubKey=SCRIPT_PUB_KEY_OP_TRUE))

        # A valid transaction with sufficient fee
        tx_orphan_2_valid = CTransaction()
        tx_orphan_2_valid.vin.append(CTxIn(outpoint=COutPoint(tx_orphan_1.sha256, 1)))
        tx_orphan_2_valid.vout.append(CTxOut(nValue=10 * COIN - 12000, scriptPubKey=SCRIPT_PUB_KEY_OP_TRUE))
        tx_orphan_2_valid.calc_sha256()

        # An invalid transaction with negative fee
        tx_orphan_2_invalid = CTransaction()
        tx_orphan_2_invalid.vin.append(CTxIn(outpoint=COutPoint(tx_orphan_1.sha256, 2)))
        tx_orphan_2_invalid.vout.append(CTxOut(nValue=11 * COIN, scriptPubKey=SCRIPT_PUB_KEY_OP_TRUE))

        self.log.info('Send the orphans ... ')
        # Send valid orphan txs from p2ps[0]
        node.p2p.send_txs_and_test([tx_orphan_1, tx_orphan_2_no_fee, tx_orphan_2_valid], node, success=False)
        # Send invalid tx from p2ps[1]
        node.p2ps[1].send_txs_and_test([tx_orphan_2_invalid], node, success=False)

        assert_equal(0, node.getmempoolinfo()['size'])  # Mempool should be empty
        assert_equal(2, len(node.getpeerinfo()))  # p2ps[1] is still connected

        self.log.info('Send the withhold tx ... ')
        with node.assert_debug_log(expected_msgs=["bad-txns-in-belowout"]):
            node.p2p.send_txs_and_test([tx_withhold], node, success=True)

        # Transactions that should end up in the mempool
        expected_mempool = {
            t.hash
            for t in [
                tx_withhold,  # The transaction that is the root for all orphans
                tx_orphan_1,  # The orphan transaction that splits the coins
                tx_orphan_2_valid,  # The valid transaction (with sufficient fee)
            ]
        }
        # Transactions that do not end up in the mempool
        # tx_orphan_no_fee, because it has too low fee (p2ps[0] is not disconnected for relaying that tx)
        # tx_orphan_invaid, because it has negative fee (p2ps[1] is disconnected for relaying that tx)

        wait_until(lambda: 1 == len(node.getpeerinfo()), timeout=12)  # p2ps[1] is no longer connected
        assert_equal(expected_mempool, set(node.getrawmempool()))
    def run_test(self):
        self.nodes[0].add_p2p_connection(P2PDataStore())
        self.nodeaddress = self.nodes[0].getnewaddress()
        self.pubkey = self.nodes[0].getaddressinfo(self.nodeaddress)["pubkey"]
        self.log.info("Mining %d blocks", CHAIN_HEIGHT)
        self.coinbase_txids = [
            self.nodes[0].getblock(b)['tx'][0] for b in self.nodes[0].generate(
                CHAIN_HEIGHT, self.signblockprivkeys)
        ]

        ##  P2PKH transaction
        ########################
        self.log.info("Test using a P2PKH transaction")
        spendtx = create_transaction(self.nodes[0],
                                     self.coinbase_txids[0],
                                     self.nodeaddress,
                                     amount=10)
        spendtx.rehash()
        copy_spendTx = CTransaction(spendtx)

        #cache hashes
        hash = spendtx.hash
        hashMalFix = spendtx.hashMalFix

        #malleate
        unDERify(spendtx)
        spendtx.rehash()

        # verify that hashMalFix remains the same even when signature is malleated and hash changes
        assert_not_equal(hash, spendtx.hash)
        assert_equal(hashMalFix, spendtx.hashMalFix)

        # verify that hash is spendtx.serialize()
        hash = encode(hash256(spendtx.serialize())[::-1],
                      'hex_codec').decode('ascii')
        assert_equal(hash, spendtx.hash)

        # verify that hashMalFix is spendtx.serialize(with_scriptsig=False)
        hashMalFix = encode(
            hash256(spendtx.serialize(with_scriptsig=False))[::-1],
            'hex_codec').decode('ascii')
        assert_equal(hashMalFix, spendtx.hashMalFix)

        assert_not_equal(hash, hashMalFix)
        #as this transaction does not have witness data the following is true
        assert_equal(spendtx.serialize(),
                     spendtx.serialize(with_witness=True, with_scriptsig=True))
        assert_equal(spendtx.serialize(with_witness=False),
                     spendtx.serialize(with_witness=True, with_scriptsig=True))
        assert_not_equal(
            spendtx.serialize(with_witness=False),
            spendtx.serialize(with_witness=True, with_scriptsig=False))
        assert_equal(spendtx.serialize(with_witness=False),
                     spendtx.serialize_without_witness(with_scriptsig=True))
        assert_equal(spendtx.serialize_with_witness(with_scriptsig=True),
                     spendtx.serialize_without_witness(with_scriptsig=True))
        assert_equal(spendtx.serialize_with_witness(with_scriptsig=False),
                     spendtx.serialize_without_witness(with_scriptsig=False))

        #Create block with only non-DER signature P2PKH transaction
        tip = self.nodes[0].getbestblockhash()
        block_time = self.nodes[0].getblockheader(tip)['mediantime'] + 1
        block = create_block(int(tip, 16), create_coinbase(CHAIN_HEIGHT + 1),
                             block_time)
        block.vtx.append(spendtx)
        block.hashMerkleRoot = block.calc_merkle_root()
        block.hashImMerkleRoot = block.calc_immutable_merkle_root()
        block.rehash()
        block.solve(self.signblockprivkeys)

        # serialize with and without witness block remains the same
        assert_equal(block.serialize(with_witness=True), block.serialize())
        assert_equal(block.serialize(with_witness=True),
                     block.serialize(with_witness=False))
        assert_equal(block.serialize(with_witness=True),
                     block.serialize(with_witness=False, with_scriptsig=True))

        self.log.info("Reject block with non-DER signature")
        self.nodes[0].p2p.send_and_ping(msg_block(block))
        assert_equal(self.nodes[0].getbestblockhash(), tip)

        wait_until(lambda: "reject" in self.nodes[0].p2p.last_message.keys(),
                   lock=mininode_lock)
        with mininode_lock:
            assert_equal(self.nodes[0].p2p.last_message["reject"].code,
                         REJECT_INVALID)
            assert_equal(self.nodes[0].p2p.last_message["reject"].data,
                         block.sha256)
            assert_equal(self.nodes[0].p2p.last_message["reject"].reason,
                         b'block-validation-failed')

        self.log.info("Accept block with DER signature")
        #recreate block with DER sig transaction
        block = create_block(int(tip, 16), create_coinbase(CHAIN_HEIGHT + 1),
                             block_time)
        block.vtx.append(copy_spendTx)
        block.hashMerkleRoot = block.calc_merkle_root()
        block.hashImMerkleRoot = block.calc_immutable_merkle_root()
        block.rehash()
        block.solve(self.signblockprivkeys)

        self.nodes[0].p2p.send_and_ping(msg_block(block))
        assert_equal(self.nodes[0].getbestblockhash(), block.hash)

        ##  P2SH transaction
        ########################
        self.log.info("Test using P2SH transaction ")

        REDEEM_SCRIPT_1 = CScript([OP_1, OP_DROP])
        P2SH_1 = CScript([OP_HASH160, hash160(REDEEM_SCRIPT_1), OP_EQUAL])

        tx = CTransaction()
        tx.vin.append(
            CTxIn(COutPoint(int(self.coinbase_txids[1], 16), 0), b"",
                  0xffffffff))
        tx.vout.append(CTxOut(10, P2SH_1))
        tx.rehash()

        spendtx_raw = self.nodes[0].signrawtransactionwithwallet(
            ToHex(tx), [], "ALL", self.options.scheme)["hex"]
        spendtx = FromHex(spendtx, spendtx_raw)
        spendtx.rehash()
        copy_spendTx = CTransaction(spendtx)

        #cache hashes
        hash = spendtx.hash
        hashMalFix = spendtx.hashMalFix

        #malleate
        spendtxcopy = spendtx
        unDERify(spendtxcopy)
        spendtxcopy.rehash()

        # verify that hashMalFix remains the same even when signature is malleated and hash changes
        assert_not_equal(hash, spendtxcopy.hash)
        assert_equal(hashMalFix, spendtxcopy.hashMalFix)

        # verify that hash is spendtx.serialize()
        hash = encode(
            hash256(spendtx.serialize(with_witness=False))[::-1],
            'hex_codec').decode('ascii')
        assert_equal(hash, spendtx.hash)

        # verify that hashMalFix is spendtx.serialize(with_scriptsig=False)
        hashMalFix = encode(
            hash256(spendtx.serialize(with_witness=False,
                                      with_scriptsig=False))[::-1],
            'hex_codec').decode('ascii')
        assert_equal(hashMalFix, spendtx.hashMalFix)

        assert_not_equal(hash, hashMalFix)
        #as this transaction does not have witness data the following is true
        assert_equal(spendtx.serialize(),
                     spendtx.serialize(with_witness=True, with_scriptsig=True))
        assert_equal(spendtx.serialize(with_witness=False),
                     spendtx.serialize(with_witness=True, with_scriptsig=True))
        assert_not_equal(
            spendtx.serialize(with_witness=False),
            spendtx.serialize(with_witness=True, with_scriptsig=False))
        assert_equal(spendtx.serialize(with_witness=False),
                     spendtx.serialize_without_witness(with_scriptsig=True))
        assert_equal(spendtx.serialize_with_witness(with_scriptsig=True),
                     spendtx.serialize_without_witness(with_scriptsig=True))
        assert_equal(spendtx.serialize_with_witness(with_scriptsig=False),
                     spendtx.serialize_without_witness(with_scriptsig=False))

        #Create block with only non-DER signature P2SH transaction
        tip = self.nodes[0].getbestblockhash()
        block_time = self.nodes[0].getblockheader(tip)['mediantime'] + 1
        block = create_block(int(tip, 16), create_coinbase(CHAIN_HEIGHT + 2),
                             block_time)
        block.vtx.append(spendtx)
        block.hashMerkleRoot = block.calc_merkle_root()
        block.hashImMerkleRoot = block.calc_immutable_merkle_root()
        block.rehash()
        block.solve(self.signblockprivkeys)

        # serialize with and without witness block remains the same
        assert_equal(block.serialize(with_witness=True), block.serialize())
        assert_equal(block.serialize(with_witness=True),
                     block.serialize(with_witness=False))
        assert_equal(block.serialize(with_witness=True),
                     block.serialize(with_witness=True, with_scriptsig=True))

        self.log.info("Reject block with non-DER signature")
        self.nodes[0].p2p.send_and_ping(msg_block(block))
        assert_equal(self.nodes[0].getbestblockhash(), tip)

        wait_until(lambda: "reject" in self.nodes[0].p2p.last_message.keys(),
                   lock=mininode_lock)
        with mininode_lock:
            assert_equal(self.nodes[0].p2p.last_message["reject"].code,
                         REJECT_INVALID)
            assert_equal(self.nodes[0].p2p.last_message["reject"].data,
                         block.sha256)
            assert_equal(self.nodes[0].p2p.last_message["reject"].reason,
                         b'block-validation-failed')

        self.log.info("Accept block with DER signature")
        #recreate block with DER sig transaction
        block = create_block(int(tip, 16), create_coinbase(CHAIN_HEIGHT + 2),
                             block_time)
        block.vtx.append(copy_spendTx)
        block.hashMerkleRoot = block.calc_merkle_root()
        block.hashImMerkleRoot = block.calc_immutable_merkle_root()
        block.rehash()
        block.solve(self.signblockprivkeys)

        self.nodes[0].p2p.send_and_ping(msg_block(block))
        assert_equal(self.nodes[0].getbestblockhash(), block.hash)

        ## redeem previous P2SH
        #########################
        self.log.info("Test using P2SH redeem transaction ")

        tx = CTransaction()
        tx.vout.append(CTxOut(1, CScript([OP_TRUE])))
        tx.vin.append(CTxIn(COutPoint(block.vtx[1].malfixsha256, 0), b''))

        (sighash, err) = SignatureHash(REDEEM_SCRIPT_1, tx, 1, SIGHASH_ALL)
        signKey = CECKey()
        signKey.set_secretbytes(b"horsebattery")
        sig = signKey.sign(sighash) + bytes(bytearray([SIGHASH_ALL]))
        scriptSig = CScript([sig, REDEEM_SCRIPT_1])

        tx.vin[0].scriptSig = scriptSig
        tx.rehash()

        spendtx_raw = self.nodes[0].signrawtransactionwithwallet(
            ToHex(tx), [], "ALL", self.options.scheme)["hex"]
        spendtx = FromHex(spendtx, spendtx_raw)
        spendtx.rehash()

        #cache hashes
        hash = spendtx.hash
        hashMalFix = spendtx.hashMalFix

        #malleate
        spendtxcopy = spendtx
        unDERify(spendtxcopy)
        spendtxcopy.rehash()

        # verify that hashMalFix remains the same even when signature is malleated and hash changes
        assert_not_equal(hash, spendtxcopy.hash)
        assert_equal(hashMalFix, spendtxcopy.hashMalFix)

        # verify that hash is spendtx.serialize()
        hash = encode(
            hash256(spendtx.serialize(with_witness=False))[::-1],
            'hex_codec').decode('ascii')
        assert_equal(hash, spendtx.hash)

        # verify that hashMalFix is spendtx.serialize(with_scriptsig=False)
        hashMalFix = encode(
            hash256(spendtx.serialize(with_witness=False,
                                      with_scriptsig=False))[::-1],
            'hex_codec').decode('ascii')
        assert_equal(hashMalFix, spendtx.hashMalFix)

        assert_not_equal(hash, hashMalFix)
        #as this transaction does not have witness data the following is true
        assert_equal(spendtx.serialize(),
                     spendtx.serialize(with_witness=True, with_scriptsig=True))
        assert_equal(spendtx.serialize(with_witness=False),
                     spendtx.serialize(with_witness=True, with_scriptsig=True))
        assert_not_equal(
            spendtx.serialize(with_witness=False),
            spendtx.serialize(with_witness=True, with_scriptsig=False))
        assert_equal(spendtx.serialize(with_witness=False),
                     spendtx.serialize_without_witness(with_scriptsig=True))
        assert_equal(spendtx.serialize_with_witness(with_scriptsig=True),
                     spendtx.serialize_without_witness(with_scriptsig=True))
        assert_equal(spendtx.serialize_with_witness(with_scriptsig=False),
                     spendtx.serialize_without_witness(with_scriptsig=False))

        #Create block with only non-DER signature P2SH redeem transaction
        tip = self.nodes[0].getbestblockhash()
        block_time = self.nodes[0].getblockheader(tip)['mediantime'] + 1
        block = create_block(int(tip, 16), create_coinbase(CHAIN_HEIGHT + 3),
                             block_time)
        block.vtx.append(spendtx)
        block.hashMerkleRoot = block.calc_merkle_root()
        block.hashImMerkleRoot = block.calc_immutable_merkle_root()
        block.rehash()
        block.solve(self.signblockprivkeys)

        # serialize with and without witness block remains the same
        assert_equal(block.serialize(with_witness=True), block.serialize())
        assert_equal(block.serialize(with_witness=True),
                     block.serialize(with_witness=False))
        assert_equal(block.serialize(with_witness=True),
                     block.serialize(with_witness=True, with_scriptsig=True))

        self.log.info("Accept block with P2SH redeem transaction")
        self.nodes[0].p2p.send_and_ping(msg_block(block))
        assert_equal(self.nodes[0].getbestblockhash(), block.hash)

        ##  p2sh_p2wpkh transaction
        ##############################
        self.log.info("Test using p2sh_p2wpkh transaction ")
        spendtxStr = create_witness_tx(self.nodes[0],
                                       True,
                                       getInput(self.coinbase_txids[4]),
                                       self.pubkey,
                                       amount=1.0)

        #get CTRansaction object from above hex
        spendtx = CTransaction()
        spendtx.deserialize(BytesIO(hex_str_to_bytes(spendtxStr)))
        spendtx.rehash()

        #cache hashes
        spendtx.rehash()
        hash = spendtx.hash
        hashMalFix = spendtx.hashMalFix
        withash = spendtx.calc_sha256(True)

        # malleate
        unDERify(spendtx)
        spendtx.rehash()
        withash2 = spendtx.calc_sha256(True)

        # verify that hashMalFix remains the same even when signature is malleated and hash changes
        assert_equal(withash, withash2)
        assert_equal(hash, spendtx.hash)
        assert_equal(hashMalFix, spendtx.hashMalFix)

        # verify that hash is spendtx.serialize()
        hash = encode(hash256(spendtx.serialize())[::-1],
                      'hex_codec').decode('ascii')
        assert_equal(hash, spendtx.hash)

        # verify that hashMalFix is spendtx.serialize(with_scriptsig=False)
        hashMalFix = encode(
            hash256(spendtx.serialize(with_scriptsig=False))[::-1],
            'hex_codec').decode('ascii')
        assert_equal(hashMalFix, spendtx.hashMalFix)

        assert_not_equal(hash, hashMalFix)
        #as this transaction does not have witness data the following is true
        assert_equal(spendtx.serialize(),
                     spendtx.serialize(with_witness=True, with_scriptsig=True))
        assert_equal(spendtx.serialize(with_witness=False),
                     spendtx.serialize(with_witness=True, with_scriptsig=True))
        assert_not_equal(
            spendtx.serialize(with_witness=False),
            spendtx.serialize(with_witness=True, with_scriptsig=False))
        assert_equal(spendtx.serialize(with_witness=False),
                     spendtx.serialize_without_witness(with_scriptsig=True))
        assert_equal(spendtx.serialize_with_witness(with_scriptsig=True),
                     spendtx.serialize_without_witness(with_scriptsig=True))
        assert_equal(spendtx.serialize_with_witness(with_scriptsig=False),
                     spendtx.serialize_without_witness(with_scriptsig=False))

        #Create block with only non-DER signature p2sh_p2wpkh transaction
        spendtxStr = self.nodes[0].signrawtransactionwithwallet(
            spendtxStr, [], "ALL", self.options.scheme)
        assert ("errors" not in spendtxStr or len(["errors"]) == 0)
        spendtxStr = spendtxStr["hex"]
        spendtx = CTransaction()
        spendtx.deserialize(BytesIO(hex_str_to_bytes(spendtxStr)))
        spendtx.rehash()

        tip = self.nodes[0].getbestblockhash()
        block_time = self.nodes[0].getblockheader(tip)['mediantime'] + 1
        block = create_block(int(tip, 16), create_coinbase(CHAIN_HEIGHT + 4),
                             block_time)
        block.vtx.append(spendtx)
        add_witness_commitment(block)
        block.hashMerkleRoot = block.calc_merkle_root()
        block.hashImMerkleRoot = block.calc_immutable_merkle_root()
        block.rehash()
        block.solve(self.signblockprivkeys)

        # serialize with and without witness
        assert_equal(block.serialize(with_witness=False), block.serialize())
        assert_not_equal(block.serialize(with_witness=True),
                         block.serialize(with_witness=False))
        assert_not_equal(
            block.serialize(with_witness=True),
            block.serialize(with_witness=False, with_scriptsig=True))

        self.log.info(
            "Reject block with p2sh_p2wpkh transaction and witness commitment")
        assert_raises_rpc_error(
            -22, "Block does not start with a coinbase",
            self.nodes[0].submitblock,
            bytes_to_hex_str(block.serialize(with_witness=True)))
        assert_equal(self.nodes[0].getbestblockhash(), tip)

        block = create_block(int(tip, 16), create_coinbase(CHAIN_HEIGHT + 4),
                             block_time)
        block.vtx.append(spendtx)
        block.hashMerkleRoot = block.calc_merkle_root()
        block.hashImMerkleRoot = block.calc_immutable_merkle_root()
        block.rehash()
        block.solve(self.signblockprivkeys)

        self.log.info("Accept block with p2sh_p2wpkh transaction")
        self.nodes[0].submitblock(
            bytes_to_hex_str(block.serialize(with_witness=True)))
        assert_equal(self.nodes[0].getbestblockhash(), block.hash)

        ##  p2sh_p2wsh transaction
        ##############################
        self.log.info("Test using p2sh_p2wsh transaction")
        spendtxStr = create_witness_tx(self.nodes[0],
                                       True,
                                       getInput(self.coinbase_txids[5]),
                                       self.pubkey,
                                       amount=1.0)

        #get CTRansaction object from above hex
        spendtx = CTransaction()
        spendtx.deserialize(BytesIO(hex_str_to_bytes(spendtxStr)))
        spendtx.rehash()

        #cache hashes
        spendtx.rehash()
        hash = spendtx.hash
        hashMalFix = spendtx.hashMalFix
        withash = spendtx.calc_sha256(True)

        # malleate
        unDERify(spendtx)
        spendtx.rehash()
        withash2 = spendtx.calc_sha256(True)

        # verify that hashMalFix remains the same even when signature is malleated and hash changes
        assert_equal(withash, withash2)
        assert_equal(hash, spendtx.hash)
        assert_equal(hashMalFix, spendtx.hashMalFix)

        # verify that hash is spendtx.serialize()
        hash = encode(hash256(spendtx.serialize())[::-1],
                      'hex_codec').decode('ascii')
        assert_equal(hash, spendtx.hash)

        # verify that hashMalFix is spendtx.serialize(with_scriptsig=False)
        hashMalFix = encode(
            hash256(spendtx.serialize(with_scriptsig=False))[::-1],
            'hex_codec').decode('ascii')
        assert_equal(hashMalFix, spendtx.hashMalFix)

        assert_not_equal(hash, hashMalFix)
        #as this transaction does not have witness data the following is true
        assert_equal(spendtx.serialize(),
                     spendtx.serialize(with_witness=True, with_scriptsig=True))
        assert_equal(spendtx.serialize(with_witness=False),
                     spendtx.serialize(with_witness=True, with_scriptsig=True))
        assert_not_equal(
            spendtx.serialize(with_witness=False),
            spendtx.serialize(with_witness=True, with_scriptsig=False))
        assert_equal(spendtx.serialize(with_witness=False),
                     spendtx.serialize_without_witness(with_scriptsig=True))
        assert_equal(spendtx.serialize_with_witness(with_scriptsig=True),
                     spendtx.serialize_without_witness(with_scriptsig=True))
        assert_equal(spendtx.serialize_with_witness(with_scriptsig=False),
                     spendtx.serialize_without_witness(with_scriptsig=False))

        #Create block with only non-DER signature p2sh_p2wsh transaction
        spendtxStr = self.nodes[0].signrawtransactionwithwallet(
            spendtxStr, [], "ALL", self.options.scheme)
        assert ("errors" not in spendtxStr or len(["errors"]) == 0)
        spendtxStr = spendtxStr["hex"]
        spendtx = CTransaction()
        spendtx.deserialize(BytesIO(hex_str_to_bytes(spendtxStr)))
        spendtx.rehash()

        tip = self.nodes[0].getbestblockhash()
        block_time = self.nodes[0].getblockheader(tip)['mediantime'] + 1
        block = create_block(int(tip, 16), create_coinbase(CHAIN_HEIGHT + 5),
                             block_time)
        block.vtx.append(spendtx)
        add_witness_commitment(block)
        block.hashMerkleRoot = block.calc_merkle_root()
        block.hashImMerkleRoot = block.calc_immutable_merkle_root()
        block.rehash()
        block.solve(self.signblockprivkeys)

        # serialize with and without witness
        assert_equal(block.serialize(with_witness=False), block.serialize())
        assert_not_equal(block.serialize(with_witness=True),
                         block.serialize(with_witness=False))
        assert_not_equal(
            block.serialize(with_witness=True),
            block.serialize(with_witness=False, with_scriptsig=True))

        self.log.info(
            "Reject block with p2sh_p2wsh transaction and witness commitment")
        assert_raises_rpc_error(
            -22, "Block does not start with a coinbase",
            self.nodes[0].submitblock,
            bytes_to_hex_str(block.serialize(with_witness=True)))
        assert_equal(self.nodes[0].getbestblockhash(), tip)

        block = create_block(int(tip, 16), create_coinbase(CHAIN_HEIGHT + 5),
                             block_time)
        block.vtx.append(spendtx)
        block.hashMerkleRoot = block.calc_merkle_root()
        block.hashImMerkleRoot = block.calc_immutable_merkle_root()
        block.rehash()
        block.solve(self.signblockprivkeys)

        self.log.info("Accept block with p2sh_p2wsh transaction")
        self.nodes[0].submitblock(
            bytes_to_hex_str(block.serialize(with_witness=True)))
        assert_equal(self.nodes[0].getbestblockhash(), block.hash)
Ejemplo n.º 19
0
    def run_test(self):
        self.address = self.nodes[0].getnewaddress()
        self.ms_address = self.nodes[0].addmultisigaddress(
            1, [self.address])['address']
        self.wit_address = self.nodes[0].addwitnessaddress(self.address)
        self.wit_ms_address = self.nodes[0].addmultisigaddress(
            1, [self.address], '', 'p2sh-segwit')['address']

        self.coinbase_blocks = self.nodes[0].generate(2)  # Block 2
        coinbase_txid = []
        for i in self.coinbase_blocks:
            coinbase_txid.append(self.nodes[0].getblock(i)['tx'][0])
        self.nodes[0].generate(427)  # Block 429
        self.lastblockhash = self.nodes[0].getbestblockhash()
        self.tip = int("0x" + self.lastblockhash, 0)
        self.lastblockheight = 429
        self.lastblocktime = int(time.time()) + 429

        self.log.info(
            "Test 1: NULLDUMMY compliant base transactions should be accepted to mempool and mined before activation [430]"
        )
        test1txs = [
            create_transaction(self.nodes[0],
                               coinbase_txid[0],
                               self.ms_address,
                               amount=49)
        ]
        txid1 = self.nodes[0].sendrawtransaction(
            bytes_to_hex_str(test1txs[0].serialize_with_witness()), True)
        test1txs.append(
            create_transaction(self.nodes[0],
                               txid1,
                               self.ms_address,
                               amount=48))
        txid2 = self.nodes[0].sendrawtransaction(
            bytes_to_hex_str(test1txs[1].serialize_with_witness()), True)
        test1txs.append(
            create_transaction(self.nodes[0],
                               coinbase_txid[1],
                               self.wit_ms_address,
                               amount=49))
        txid3 = self.nodes[0].sendrawtransaction(
            bytes_to_hex_str(test1txs[2].serialize_with_witness()), True)
        self.block_submit(self.nodes[0], test1txs, False, True)

        self.log.info(
            "Test 2: Non-NULLDUMMY base multisig transaction should not be accepted to mempool before activation"
        )
        test2tx = create_transaction(self.nodes[0],
                                     txid2,
                                     self.ms_address,
                                     amount=47)
        trueDummy(test2tx)
        assert_raises_rpc_error(
            -26, NULLDUMMY_ERROR, self.nodes[0].sendrawtransaction,
            bytes_to_hex_str(test2tx.serialize_with_witness()), True)

        self.log.info(
            "Test 3: Non-NULLDUMMY base transactions should be accepted in a block before activation [431]"
        )
        self.block_submit(self.nodes[0], [test2tx], False, True)

        self.log.info(
            "Test 4: Non-NULLDUMMY base multisig transaction is invalid after activation"
        )
        test4tx = create_transaction(self.nodes[0],
                                     test2tx.hash,
                                     self.address,
                                     amount=46)
        test6txs = [CTransaction(test4tx)]
        trueDummy(test4tx)
        assert_raises_rpc_error(
            -26, NULLDUMMY_ERROR, self.nodes[0].sendrawtransaction,
            bytes_to_hex_str(test4tx.serialize_with_witness()), True)
        self.block_submit(self.nodes[0], [test4tx])

        self.log.info(
            "Test 5: Non-NULLDUMMY P2WSH multisig transaction invalid after activation"
        )
        test5tx = create_transaction(self.nodes[0],
                                     txid3,
                                     self.wit_address,
                                     amount=48)
        test6txs.append(CTransaction(test5tx))
        test5tx.wit.vtxinwit[0].scriptWitness.stack[0] = b'\x01'
        assert_raises_rpc_error(
            -26, NULLDUMMY_ERROR, self.nodes[0].sendrawtransaction,
            bytes_to_hex_str(test5tx.serialize_with_witness()), True)
        self.block_submit(self.nodes[0], [test5tx], True)

        self.log.info(
            "Test 6: NULLDUMMY compliant base/witness transactions should be accepted to mempool and in block after activation [432]"
        )
        for i in test6txs:
            self.nodes[0].sendrawtransaction(
                bytes_to_hex_str(i.serialize_with_witness()), True)
        self.block_submit(self.nodes[0], test6txs, True, True)
Ejemplo n.º 20
0
    def run_test(self):
        # Mine some coins
        self.nodes[0].generate(110)

        # Get some addresses from the two nodes
        addr1 = [self.nodes[1].getnewaddress() for _ in range(3)]
        addr2 = [self.nodes[2].getnewaddress() for _ in range(3)]
        addrs = addr1 + addr2

        # Send 1 + 0.5 coin to each address
        [self.nodes[0].sendtoaddress(addr, 1.0) for addr in addrs]
        [self.nodes[0].sendtoaddress(addr, 0.5) for addr in addrs]

        self.nodes[0].generate(1)
        self.sync_all()

        # For each node, send 0.2 coins back to 0;
        # - node[1] should pick one 0.5 UTXO and leave the rest
        # - node[2] should pick one (1.0 + 0.5) UTXO group corresponding to a
        #   given address, and leave the rest
        txid1 = self.nodes[1].sendtoaddress(self.nodes[0].getnewaddress(), 0.2)
        tx1 = self.nodes[1].getrawtransaction(txid1, True)
        # txid1 should have 1 input and 2 outputs
        assert_equal(1, len(tx1["vin"]))
        assert_equal(2, len(tx1["vout"]))
        # one output should be 0.2, the other should be ~0.3
        v = [vout["value"] for vout in tx1["vout"]]
        v.sort()
        assert_approx(v[0], vexp=0.2, vspan=0.0001)
        assert_approx(v[1], vexp=0.3, vspan=0.0001)

        txid2 = self.nodes[2].sendtoaddress(self.nodes[0].getnewaddress(), 0.2)
        tx2 = self.nodes[2].getrawtransaction(txid2, True)
        # txid2 should have 2 inputs and 2 outputs
        assert_equal(2, len(tx2["vin"]))
        assert_equal(2, len(tx2["vout"]))
        # one output should be 0.2, the other should be ~1.3
        v = [vout["value"] for vout in tx2["vout"]]
        v.sort()
        assert_approx(v[0], vexp=0.2, vspan=0.0001)
        assert_approx(v[1], vexp=1.3, vspan=0.0001)

        # Test 'avoid partial if warranted, even if disabled'
        self.sync_all()
        self.nodes[0].generate(1)
        # Nodes 1-2 now have confirmed UTXOs (letters denote destinations):
        # Node #1:      Node #2:
        # - A  1.0      - D0 1.0
        # - B0 1.0      - D1 0.5
        # - B1 0.5      - E0 1.0
        # - C0 1.0      - E1 0.5
        # - C1 0.5      - F  ~1.3
        # - D ~0.3
        assert_approx(self.nodes[1].getbalance(), vexp=4.3, vspan=0.0001)
        assert_approx(self.nodes[2].getbalance(), vexp=4.3, vspan=0.0001)
        # Sending 1.4 rdc should pick one 1.0 + one more. For node #1,
        # this could be (A / B0 / C0) + (B1 / C1 / D). We ensure that it is
        # B0 + B1 or C0 + C1, because this avoids partial spends while not being
        # detrimental to transaction cost
        txid3 = self.nodes[1].sendtoaddress(self.nodes[0].getnewaddress(), 1.4)
        tx3 = self.nodes[1].getrawtransaction(txid3, True)
        # tx3 should have 2 inputs and 2 outputs
        assert_equal(2, len(tx3["vin"]))
        assert_equal(2, len(tx3["vout"]))
        # the accumulated value should be 1.5, so the outputs should be
        # ~0.1 and 1.4 and should come from the same destination
        values = [vout["value"] for vout in tx3["vout"]]
        values.sort()
        assert_approx(values[0], vexp=0.1, vspan=0.0001)
        assert_approx(values[1], vexp=1.4, vspan=0.0001)

        input_txids = [vin["txid"] for vin in tx3["vin"]]
        input_addrs = [
            self.nodes[1].gettransaction(txid)['details'][0]['address']
            for txid in input_txids
        ]
        assert_equal(input_addrs[0], input_addrs[1])
        # Node 2 enforces avoidpartialspends so needs no checking here

        # Test wallet option maxapsfee with Node 3
        addr_aps = self.nodes[3].getnewaddress()
        self.nodes[0].sendtoaddress(addr_aps, 1.0)
        self.nodes[0].sendtoaddress(addr_aps, 1.0)
        self.nodes[0].generate(1)
        self.sync_all()
        with self.nodes[3].assert_debug_log(
            ['Fee non-grouped = 2820, grouped = 4160, using grouped']):
            txid4 = self.nodes[3].sendtoaddress(self.nodes[0].getnewaddress(),
                                                0.1)
        tx4 = self.nodes[3].getrawtransaction(txid4, True)
        # tx4 should have 2 inputs and 2 outputs although one output would
        # have been enough and the transaction caused higher fees
        assert_equal(2, len(tx4["vin"]))
        assert_equal(2, len(tx4["vout"]))

        addr_aps2 = self.nodes[3].getnewaddress()
        [self.nodes[0].sendtoaddress(addr_aps2, 1.0) for _ in range(5)]
        self.nodes[0].generate(1)
        self.sync_all()
        with self.nodes[3].assert_debug_log(
            ['Fee non-grouped = 5520, grouped = 8240, using non-grouped']):
            txid5 = self.nodes[3].sendtoaddress(self.nodes[0].getnewaddress(),
                                                2.95)
        tx5 = self.nodes[3].getrawtransaction(txid5, True)
        # tx5 should have 3 inputs (1.0, 1.0, 1.0) and 2 outputs
        assert_equal(3, len(tx5["vin"]))
        assert_equal(2, len(tx5["vout"]))

        # Test wallet option maxapsfee with node 4, which sets maxapsfee
        # 1 sat higher, crossing the threshold from non-grouped to grouped.
        addr_aps3 = self.nodes[4].getnewaddress()
        [self.nodes[0].sendtoaddress(addr_aps3, 1.0) for _ in range(5)]
        self.nodes[0].generate(1)
        self.sync_all()
        with self.nodes[4].assert_debug_log(
            ['Fee non-grouped = 5520, grouped = 8240, using grouped']):
            txid6 = self.nodes[4].sendtoaddress(self.nodes[0].getnewaddress(),
                                                2.95)
        tx6 = self.nodes[4].getrawtransaction(txid6, True)
        # tx6 should have 5 inputs and 2 outputs
        assert_equal(5, len(tx6["vin"]))
        assert_equal(2, len(tx6["vout"]))

        # Empty out node2's wallet
        self.nodes[2].sendtoaddress(address=self.nodes[0].getnewaddress(),
                                    amount=self.nodes[2].getbalance(),
                                    subtractfeefromamount=True)
        self.sync_all()
        self.nodes[0].generate(1)

        # Fill node2's wallet with 10000 outputs corresponding to the same
        # scriptPubKey
        for _ in range(5):
            raw_tx = self.nodes[0].createrawtransaction([{
                "txid": "0" * 64,
                "vout": 0
            }], [{
                addr2[0]: 0.05
            }])
            tx = FromHex(CTransaction(), raw_tx)
            tx.vin = []
            tx.vout = [tx.vout[0]] * 2000
            funded_tx = self.nodes[0].fundrawtransaction(ToHex(tx))
            signed_tx = self.nodes[0].signrawtransactionwithwallet(
                funded_tx['hex'])
            self.nodes[0].sendrawtransaction(signed_tx['hex'])
            self.nodes[0].generate(1)

        self.sync_all()

        # Check that we can create a transaction that only requires ~100 of our
        # utxos, without pulling in all outputs and creating a transaction that
        # is way too big.
        assert self.nodes[2].sendtoaddress(address=addr2[0], amount=5)
    def test_sequence_lock_unconfirmed_inputs(self):
        # Store height so we can easily reset the chain at the end of the test
        cur_height = self.nodes[0].getblockcount()

        # Create a mempool tx.
        txid = self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), 2)
        tx1 = FromHex(CTransaction(), self.nodes[0].getrawtransaction(txid))
        tx1.rehash()

        # Anyone-can-spend mempool tx.
        # Sequence lock of 0 should pass.
        tx2 = CTransaction()
        tx2.nVersion = 2
        tx2.vin = [CTxIn(COutPoint(tx1.sha256, 0), nSequence=0)]
        tx2.vout = [CTxOut(int(tx1.vout[0].nValue - self.relayfee*COIN), CScript([b'a']))]
        tx2_raw = self.nodes[0].signrawtransactionwithwallet(ToHex(tx2))["hex"]
        tx2 = FromHex(tx2, tx2_raw)
        tx2.rehash()

        self.nodes[0].sendrawtransaction(tx2_raw)

        # Create a spend of the 0th output of orig_tx with a sequence lock
        # of 1, and test what happens when submitting.
        # orig_tx.vout[0] must be an anyone-can-spend output
        def test_nonzero_locks(orig_tx, node, relayfee, use_height_lock):
            sequence_value = 1
            if not use_height_lock:
                sequence_value |= SEQUENCE_LOCKTIME_TYPE_FLAG

            tx = CTransaction()
            tx.nVersion = 2
            tx.vin = [CTxIn(COutPoint(orig_tx.sha256, 0), nSequence=sequence_value)]
            tx.vout = [CTxOut(int(orig_tx.vout[0].nValue - relayfee * COIN), CScript([b'a' * 35]))]
            tx.rehash()

            if (orig_tx.hash in node.getrawmempool()):
                # sendrawtransaction should fail if the tx is in the mempool
                assert_raises_rpc_error(-26, NOT_FINAL_ERROR, node.sendrawtransaction, ToHex(tx))
            else:
                # sendrawtransaction should succeed if the tx is not in the mempool
                node.sendrawtransaction(ToHex(tx))

            return tx

        test_nonzero_locks(tx2, self.nodes[0], self.relayfee, use_height_lock=True)
        test_nonzero_locks(tx2, self.nodes[0], self.relayfee, use_height_lock=False)

        # Now mine some blocks, but make sure tx2 doesn't get mined.
        # Use prioritisetransaction to lower the effective feerate to 0
        self.nodes[0].prioritisetransaction(txid=tx2.hash, fee_delta=int(-self.relayfee*COIN))
        cur_time = int(time.time())
        for i in range(10):
            self.nodes[0].setmocktime(cur_time + 600)
            self.nodes[0].generate(1)
            cur_time += 600

        assert(tx2.hash in self.nodes[0].getrawmempool())

        test_nonzero_locks(tx2, self.nodes[0], self.relayfee, use_height_lock=True)
        test_nonzero_locks(tx2, self.nodes[0], self.relayfee, use_height_lock=False)

        # Mine tx2, and then try again
        self.nodes[0].prioritisetransaction(txid=tx2.hash, fee_delta=int(self.relayfee*COIN))

        # Advance the time on the node so that we can test timelocks
        self.nodes[0].setmocktime(cur_time+600)
        self.nodes[0].generate(1)
        assert(tx2.hash not in self.nodes[0].getrawmempool())

        # Now that tx2 is not in the mempool, a sequence locked spend should
        # succeed
        tx3 = test_nonzero_locks(tx2, self.nodes[0], self.relayfee, use_height_lock=False)
        assert(tx3.hash in self.nodes[0].getrawmempool())

        self.nodes[0].generate(1)
        assert(tx3.hash not in self.nodes[0].getrawmempool())

        # One more test, this time using height locks
        tx4 = test_nonzero_locks(tx3, self.nodes[0], self.relayfee, use_height_lock=True)
        assert(tx4.hash in self.nodes[0].getrawmempool())

        # Now try combining confirmed and unconfirmed inputs
        tx5 = test_nonzero_locks(tx4, self.nodes[0], self.relayfee, use_height_lock=True)
        assert(tx5.hash not in self.nodes[0].getrawmempool())

        utxos = self.nodes[0].listunspent()
        tx5.vin.append(CTxIn(COutPoint(int(utxos[0]["txid"], 16), utxos[0]["vout"]), nSequence=1))
        tx5.vout[0].nValue += int(utxos[0]["amount"]*COIN)
        raw_tx5 = self.nodes[0].signrawtransactionwithwallet(ToHex(tx5))["hex"]

        assert_raises_rpc_error(-26, NOT_FINAL_ERROR, self.nodes[0].sendrawtransaction, raw_tx5)

        # Test mempool-BIP68 consistency after reorg
        #
        # State of the transactions in the last blocks:
        # ... -> [ tx2 ] ->  [ tx3 ]
        #         tip-1        tip
        # And currently tx4 is in the mempool.
        #
        # If we invalidate the tip, tx3 should get added to the mempool, causing
        # tx4 to be removed (fails sequence-lock).
        self.nodes[0].invalidateblock(self.nodes[0].getbestblockhash())
        assert(tx4.hash not in self.nodes[0].getrawmempool())
        assert(tx3.hash in self.nodes[0].getrawmempool())

        # Now mine 2 empty blocks to reorg out the current tip (labeled tip-1 in
        # diagram above).
        # This would cause tx2 to be added back to the mempool, which in turn causes
        # tx3 to be removed.
        tip = int(self.nodes[0].getblockhash(self.nodes[0].getblockcount()-1), 16)
        height = self.nodes[0].getblockcount()
        for i in range(2):
            block = create_block(tip, create_coinbase(height), cur_time)
            block.nVersion = 3
            block.rehash()
            block.solve()
            tip = block.sha256
            height += 1
            self.nodes[0].submitblock(ToHex(block))
            cur_time += 1

        mempool = self.nodes[0].getrawmempool()
        assert(tx3.hash not in mempool)
        assert(tx2.hash in mempool)

        # Reset the chain and get rid of the mocktimed-blocks
        self.nodes[0].setmocktime(0)
        self.nodes[0].invalidateblock(self.nodes[0].getblockhash(cur_height+1))
        self.nodes[0].generate(10)
Ejemplo n.º 22
0
    def run_test(self):
        node = self.nodes[0]

        self.log.info('Start with empty mempool, and 200 blocks')
        self.mempool_size = 0
        assert_equal(node.getblockcount(), 200)
        assert_equal(node.getmempoolinfo()['size'], self.mempool_size)
        coins = node.listunspent()

        self.log.info('Should not accept garbage to testmempoolaccept')
        assert_raises_rpc_error(
            -3, 'Expected type array, got string',
            lambda: node.testmempoolaccept(rawtxs='ff00baar'))
        assert_raises_rpc_error(
            -8, 'Array must contain exactly one raw transaction for now',
            lambda: node.testmempoolaccept(rawtxs=['ff00baar', 'ff22']))
        assert_raises_rpc_error(
            -22, 'TX decode failed',
            lambda: node.testmempoolaccept(rawtxs=['ff00baar']))

        self.log.info('A transaction already in the blockchain')
        coin = coins.pop()  # Pick a random coin(base) to spend
        raw_tx_in_block = node.signrawtransactionwithwallet(
            node.createrawtransaction(
                inputs=[{
                    'txid': coin['txid'],
                    'vout': coin['vout']
                }],
                outputs=[{
                    node.getnewaddress(): 0.3
                }, {
                    node.getnewaddress(): 49
                }],
            ))['hex']
        txid_in_block = node.sendrawtransaction(hexstring=raw_tx_in_block,
                                                maxfeerate=0)
        node.generate(1)
        self.mempool_size = 0
        self.check_mempool_result(
            result_expected=[{
                'txid': txid_in_block,
                'allowed': False,
                'reject-reason': 'txn-already-known'
            }],
            rawtxs=[raw_tx_in_block],
        )

        self.log.info('A transaction not in the mempool')
        fee = 0.00000700
        raw_tx_0 = node.signrawtransactionwithwallet(
            node.createrawtransaction(
                inputs=[{
                    "txid": txid_in_block,
                    "vout": 0,
                    "sequence": BIP125_SEQUENCE_NUMBER
                }],  # RBF is used later
                outputs=[{
                    node.getnewaddress(): 0.3 - fee
                }],
            ))['hex']
        tx = CTransaction()
        tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_0)))
        txid_0 = tx.rehash()
        self.check_mempool_result(
            result_expected=[{
                'txid': txid_0,
                'allowed': True
            }],
            rawtxs=[raw_tx_0],
        )

        self.log.info('A final transaction not in the mempool')
        coin = coins.pop()  # Pick a random coin(base) to spend
        raw_tx_final = node.signrawtransactionwithwallet(
            node.createrawtransaction(
                inputs=[{
                    'txid': coin['txid'],
                    'vout': coin['vout'],
                    "sequence": 0xffffffff
                }],  # SEQUENCE_FINAL
                outputs=[{
                    node.getnewaddress(): 0.025
                }],
                locktime=node.getblockcount() + 2000,  # Can be anything
            ))['hex']
        tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_final)))
        self.check_mempool_result(
            result_expected=[{
                'txid': tx.rehash(),
                'allowed': True
            }],
            rawtxs=[tx.serialize().hex()],
            maxfeerate=0,
        )
        node.sendrawtransaction(hexstring=raw_tx_final, maxfeerate=0)
        self.mempool_size += 1

        self.log.info('A transaction in the mempool')
        node.sendrawtransaction(hexstring=raw_tx_0)
        self.mempool_size += 1
        self.check_mempool_result(
            result_expected=[{
                'txid': txid_0,
                'allowed': False,
                'reject-reason': 'txn-already-in-mempool'
            }],
            rawtxs=[raw_tx_0],
        )

        self.log.info('A transaction that replaces a mempool transaction')
        tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_0)))
        tx.vout[0].nValue -= int(fee * COIN)  # Double the fee
        tx.vin[0].nSequence = BIP125_SEQUENCE_NUMBER + 1  # Now, opt out of RBF
        raw_tx_0 = node.signrawtransactionwithwallet(
            tx.serialize().hex())['hex']
        tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_0)))
        txid_0 = tx.rehash()
        self.check_mempool_result(
            result_expected=[{
                'txid': txid_0,
                'allowed': True
            }],
            rawtxs=[raw_tx_0],
        )

        self.log.info('A transaction that conflicts with an unconfirmed tx')
        # Send the transaction that replaces the mempool transaction and opts out of replaceability
        node.sendrawtransaction(hexstring=tx.serialize().hex(), maxfeerate=0)
        # take original raw_tx_0
        tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_0)))
        tx.vout[0].nValue -= int(4 * fee * COIN)  # Set more fee
        # skip re-signing the tx
        self.check_mempool_result(
            result_expected=[{
                'txid': tx.rehash(),
                'allowed': False,
                'reject-reason': 'txn-mempool-conflict'
            }],
            rawtxs=[tx.serialize().hex()],
            maxfeerate=0,
        )

        self.log.info('A transaction with missing inputs, that never existed')
        tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_0)))
        tx.vin[0].prevout = COutPoint(hash=int('ff' * 32, 16), n=14)
        # skip re-signing the tx
        self.check_mempool_result(
            result_expected=[{
                'txid': tx.rehash(),
                'allowed': False,
                'reject-reason': 'missing-inputs'
            }],
            rawtxs=[tx.serialize().hex()],
        )

        self.log.info(
            'A transaction with missing inputs, that existed once in the past')
        tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_0)))
        tx.vin[
            0].prevout.n = 1  # Set vout to 1, to spend the other outpoint (49 coins) of the in-chain-tx we want to double spend
        raw_tx_1 = node.signrawtransactionwithwallet(
            tx.serialize().hex())['hex']
        txid_1 = node.sendrawtransaction(hexstring=raw_tx_1, maxfeerate=0)
        # Now spend both to "clearly hide" the outputs, ie. remove the coins from the utxo set by spending them
        raw_tx_spend_both = node.signrawtransactionwithwallet(
            node.createrawtransaction(inputs=[
                {
                    'txid': txid_0,
                    'vout': 0
                },
                {
                    'txid': txid_1,
                    'vout': 0
                },
            ],
                                      outputs=[{
                                          node.getnewaddress(): 0.1
                                      }]))['hex']
        txid_spend_both = node.sendrawtransaction(hexstring=raw_tx_spend_both,
                                                  maxfeerate=0)
        node.generate(1)
        self.mempool_size = 0
        # Now see if we can add the coins back to the utxo set by sending the exact txs again
        self.check_mempool_result(
            result_expected=[{
                'txid': txid_0,
                'allowed': False,
                'reject-reason': 'missing-inputs'
            }],
            rawtxs=[raw_tx_0],
        )
        self.check_mempool_result(
            result_expected=[{
                'txid': txid_1,
                'allowed': False,
                'reject-reason': 'missing-inputs'
            }],
            rawtxs=[raw_tx_1],
        )

        self.log.info('Create a signed "reference" tx for later use')
        raw_tx_reference = node.signrawtransactionwithwallet(
            node.createrawtransaction(
                inputs=[{
                    'txid': txid_spend_both,
                    'vout': 0
                }],
                outputs=[{
                    node.getnewaddress(): 0.05
                }],
            ))['hex']
        tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference)))
        # Reference tx should be valid on itself
        self.check_mempool_result(
            result_expected=[{
                'txid': tx.rehash(),
                'allowed': True
            }],
            rawtxs=[tx.serialize().hex()],
            maxfeerate=0,
        )

        self.log.info('A transaction with no outputs')
        tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference)))
        tx.vout = []
        # Skip re-signing the transaction for context independent checks from now on
        # tx.deserialize(BytesIO(hex_str_to_bytes(node.signrawtransactionwithwallet(tx.serialize().hex())['hex'])))
        self.check_mempool_result(
            result_expected=[{
                'txid': tx.rehash(),
                'allowed': False,
                'reject-reason': 'bad-txns-vout-empty'
            }],
            rawtxs=[tx.serialize().hex()],
        )

        self.log.info('A really large transaction')
        tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference)))
        tx.vin = [tx.vin[0]] * math.ceil(
            MAX_BLOCK_BASE_SIZE / len(tx.vin[0].serialize()))
        self.check_mempool_result(
            result_expected=[{
                'txid': tx.rehash(),
                'allowed': False,
                'reject-reason': 'bad-txns-oversize'
            }],
            rawtxs=[tx.serialize().hex()],
        )

        self.log.info('A transaction with negative output value')
        tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference)))
        tx.vout[0].nValue *= -1
        self.check_mempool_result(
            result_expected=[{
                'txid': tx.rehash(),
                'allowed': False,
                'reject-reason': 'bad-txns-vout-negative'
            }],
            rawtxs=[tx.serialize().hex()],
        )

        # The following two validations prevent overflow of the output amounts (see CVE-2010-5139).
        self.log.info('A transaction with too large output value')
        tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference)))
        tx.vout[0].nValue = 21000000 * COIN + 1
        self.check_mempool_result(
            result_expected=[{
                'txid': tx.rehash(),
                'allowed': False,
                'reject-reason': 'bad-txns-vout-toolarge'
            }],
            rawtxs=[tx.serialize().hex()],
        )

        self.log.info('A transaction with too large sum of output values')
        tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference)))
        tx.vout = [tx.vout[0]] * 2
        tx.vout[0].nValue = 21000000 * COIN
        self.check_mempool_result(
            result_expected=[{
                'txid': tx.rehash(),
                'allowed': False,
                'reject-reason': 'bad-txns-txouttotal-toolarge'
            }],
            rawtxs=[tx.serialize().hex()],
        )

        self.log.info('A transaction with duplicate inputs')
        tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference)))
        tx.vin = [tx.vin[0]] * 2
        self.check_mempool_result(
            result_expected=[{
                'txid': tx.rehash(),
                'allowed': False,
                'reject-reason': 'bad-txns-inputs-duplicate'
            }],
            rawtxs=[tx.serialize().hex()],
        )

        self.log.info('A coinbase transaction')
        # Pick the input of the first tx we signed, so it has to be a coinbase tx
        raw_tx_coinbase_spent = node.getrawtransaction(
            txid=node.decoderawtransaction(
                hexstring=raw_tx_in_block)['vin'][0]['txid'])
        tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_coinbase_spent)))
        self.check_mempool_result(
            result_expected=[{
                'txid': tx.rehash(),
                'allowed': False,
                'reject-reason': 'coinbase'
            }],
            rawtxs=[tx.serialize().hex()],
        )

        self.log.info('Some nonstandard transactions')
        tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference)))
        tx.nVersion = 3  # A version currently non-standard
        self.check_mempool_result(
            result_expected=[{
                'txid': tx.rehash(),
                'allowed': False,
                'reject-reason': 'version'
            }],
            rawtxs=[tx.serialize().hex()],
        )
        tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference)))
        tx.vout[0].scriptPubKey = CScript([OP_0])  # Some non-standard script
        self.check_mempool_result(
            result_expected=[{
                'txid': tx.rehash(),
                'allowed': False,
                'reject-reason': 'scriptpubkey'
            }],
            rawtxs=[tx.serialize().hex()],
        )
        tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference)))
        key = ECKey()
        key.generate()
        pubkey = key.get_pubkey().get_bytes()
        tx.vout[0].scriptPubKey = CScript(
            [OP_2, pubkey, pubkey, pubkey, OP_3,
             OP_CHECKMULTISIG])  # Some bare multisig script (2-of-3)
        self.check_mempool_result(
            result_expected=[{
                'txid': tx.rehash(),
                'allowed': False,
                'reject-reason': 'bare-multisig'
            }],
            rawtxs=[tx.serialize().hex()],
        )
        tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference)))
        tx.vin[0].scriptSig = CScript([OP_HASH160
                                       ])  # Some not-pushonly scriptSig
        self.check_mempool_result(
            result_expected=[{
                'txid': tx.rehash(),
                'allowed': False,
                'reject-reason': 'scriptsig-not-pushonly'
            }],
            rawtxs=[tx.serialize().hex()],
        )
        tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference)))
        tx.vin[0].scriptSig = CScript(
            [b'a' * 1648])  # Some too large scriptSig (>1650 bytes)
        self.check_mempool_result(
            result_expected=[{
                'txid': tx.rehash(),
                'allowed': False,
                'reject-reason': 'scriptsig-size'
            }],
            rawtxs=[tx.serialize().hex()],
        )
        tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference)))
        output_p2sh_burn = CTxOut(nValue=540,
                                  scriptPubKey=CScript(
                                      [OP_HASH160,
                                       hash160(b'burn'), OP_EQUAL]))
        num_scripts = 100000 // len(output_p2sh_burn.serialize(
        ))  # Use enough outputs to make the tx too large for our policy
        tx.vout = [output_p2sh_burn] * num_scripts
        self.check_mempool_result(
            result_expected=[{
                'txid': tx.rehash(),
                'allowed': False,
                'reject-reason': 'tx-size'
            }],
            rawtxs=[tx.serialize().hex()],
        )
        tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference)))
        tx.vout[0] = output_p2sh_burn
        tx.vout[
            0].nValue -= 1  # Make output smaller, such that it is dust for our policy
        self.check_mempool_result(
            result_expected=[{
                'txid': tx.rehash(),
                'allowed': False,
                'reject-reason': 'dust'
            }],
            rawtxs=[tx.serialize().hex()],
        )
        tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference)))
        tx.vout[0].scriptPubKey = CScript([OP_RETURN, b'\xff'])
        tx.vout = [tx.vout[0]] * 2
        self.check_mempool_result(
            result_expected=[{
                'txid': tx.rehash(),
                'allowed': False,
                'reject-reason': 'multi-op-return'
            }],
            rawtxs=[tx.serialize().hex()],
        )

        self.log.info('A timelocked transaction')
        tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference)))
        tx.vin[
            0].nSequence -= 1  # Should be non-max, so locktime is not ignored
        tx.nLockTime = node.getblockcount() + 1
        self.check_mempool_result(
            result_expected=[{
                'txid': tx.rehash(),
                'allowed': False,
                'reject-reason': 'non-final'
            }],
            rawtxs=[tx.serialize().hex()],
        )

        self.log.info('A transaction that is locked by BIP68 sequence logic')
        tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference)))
        tx.vin[
            0].nSequence = 2  # We could include it in the second block mined from now, but not the very next one
        # Can skip re-signing the tx because of early rejection
        self.check_mempool_result(
            result_expected=[{
                'txid': tx.rehash(),
                'allowed': False,
                'reject-reason': 'non-BIP68-final'
            }],
            rawtxs=[tx.serialize().hex()],
            maxfeerate=0,
        )
Ejemplo n.º 23
0
    def run_test(self):
        self.log.info('prepare some coins for multiple *rawtransaction commands')
        self.nodes[2].generate(1)
        self.sync_all()
        self.nodes[0].generate(101)
        self.sync_all()
        self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(),1.5)
        self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(),1.0)
        self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(),5.0)
        self.sync_all()
        self.nodes[0].generate(5)
        self.sync_all()

        self.log.info('Test getrawtransaction on genesis block coinbase returns an error')
        block = self.nodes[0].getblock(self.nodes[0].getblockhash(0))
        assert_raises_rpc_error(-5, "The genesis block coinbase is not considered an ordinary transaction", self.nodes[0].getrawtransaction, block['merkleroot'])

        self.log.info('Check parameter types and required parameters of createrawtransaction')
        # Test `createrawtransaction` required parameters
        assert_raises_rpc_error(-1, "createrawtransaction", self.nodes[0].createrawtransaction)
        assert_raises_rpc_error(-1, "createrawtransaction", self.nodes[0].createrawtransaction, [])

        # Test `createrawtransaction` invalid extra parameters
        assert_raises_rpc_error(-1, "createrawtransaction", self.nodes[0].createrawtransaction, [], {}, 0, False, 'foo')

        # Test `createrawtransaction` invalid `inputs`
        txid = '1d1d4e24ed99057e84c3f80fd8fbec79ed9e1acee37da269356ecea000000000'
        assert_raises_rpc_error(-3, "Expected type array", self.nodes[0].createrawtransaction, 'foo', {})
        assert_raises_rpc_error(-1, "JSON value is not an object as expected", self.nodes[0].createrawtransaction, ['foo'], {})
        assert_raises_rpc_error(-8, "txid must be hexadecimal string", self.nodes[0].createrawtransaction, [{}], {})
        assert_raises_rpc_error(-8, "txid must be hexadecimal string", self.nodes[0].createrawtransaction, [{'txid': 'foo'}], {})
        assert_raises_rpc_error(-8, "Invalid parameter, missing vout key", self.nodes[0].createrawtransaction, [{'txid': txid}], {})
        assert_raises_rpc_error(-8, "Invalid parameter, missing vout key", self.nodes[0].createrawtransaction, [{'txid': txid, 'vout': 'foo'}], {})
        assert_raises_rpc_error(-8, "Invalid parameter, vout must be positive", self.nodes[0].createrawtransaction, [{'txid': txid, 'vout': -1}], {})
        assert_raises_rpc_error(-8, "Invalid parameter, sequence number is out of range", self.nodes[0].createrawtransaction, [{'txid': txid, 'vout': 0, 'sequence': -1}], {})

        # Test `createrawtransaction` invalid `outputs`
        address = self.nodes[0].getnewaddress()
        address2 = self.nodes[0].getnewaddress()
        assert_raises_rpc_error(-1, "JSON value is not an array as expected", self.nodes[0].createrawtransaction, [], 'foo')
        self.nodes[0].createrawtransaction(inputs=[], outputs={})  # Should not throw for backwards compatibility
        self.nodes[0].createrawtransaction(inputs=[], outputs=[])
        assert_raises_rpc_error(-8, "Data must be hexadecimal string", self.nodes[0].createrawtransaction, [], {'data': 'foo'})
        assert_raises_rpc_error(-5, "Invalid Bitcash address", self.nodes[0].createrawtransaction, [], {'foo': 0})
        assert_raises_rpc_error(-3, "Invalid amount", self.nodes[0].createrawtransaction, [], {address: 'foo'})
        assert_raises_rpc_error(-3, "Amount out of range", self.nodes[0].createrawtransaction, [], {address: -1})
        assert_raises_rpc_error(-8, "Invalid parameter, duplicated address: %s" % address, self.nodes[0].createrawtransaction, [], multidict([(address, 1), (address, 1)]))
        assert_raises_rpc_error(-8, "Invalid parameter, duplicated address: %s" % address, self.nodes[0].createrawtransaction, [], [{address: 1}, {address: 1}])
        assert_raises_rpc_error(-8, "Invalid parameter, key-value pair must contain exactly one key", self.nodes[0].createrawtransaction, [], [{'a': 1, 'b': 2}])
        assert_raises_rpc_error(-8, "Invalid parameter, key-value pair not an object as expected", self.nodes[0].createrawtransaction, [], [['key-value pair1'], ['2']])

        # Test `createrawtransaction` invalid `locktime`
        assert_raises_rpc_error(-3, "Expected type number", self.nodes[0].createrawtransaction, [], {}, 'foo')
        assert_raises_rpc_error(-8, "Invalid parameter, locktime out of range", self.nodes[0].createrawtransaction, [], {}, -1)
        assert_raises_rpc_error(-8, "Invalid parameter, locktime out of range", self.nodes[0].createrawtransaction, [], {}, 4294967296)

        # Test `createrawtransaction` invalid `replaceable`
        assert_raises_rpc_error(-3, "Expected type bool", self.nodes[0].createrawtransaction, [], {}, 0, 'foo')

        self.log.info('Check that createrawtransaction accepts an array and object as outputs')
        tx = CTransaction()
        # One output
        tx.deserialize(BytesIO(hex_str_to_bytes(self.nodes[2].createrawtransaction(inputs=[{'txid': txid, 'vout': 9}], outputs={address: 99}))))
        assert_equal(len(tx.vout), 1)
        assert_equal(
            bytes_to_hex_str(tx.serialize()),
            self.nodes[2].createrawtransaction(inputs=[{'txid': txid, 'vout': 9}], outputs=[{address: 99}]),
        )
        # Two outputs
        tx.deserialize(BytesIO(hex_str_to_bytes(self.nodes[2].createrawtransaction(inputs=[{'txid': txid, 'vout': 9}], outputs=OrderedDict([(address, 99), (address2, 99)])))))
        assert_equal(len(tx.vout), 2)
        assert_equal(
            bytes_to_hex_str(tx.serialize()),
            self.nodes[2].createrawtransaction(inputs=[{'txid': txid, 'vout': 9}], outputs=[{address: 99}, {address2: 99}]),
        )
        # Two data outputs
        tx.deserialize(BytesIO(hex_str_to_bytes(self.nodes[2].createrawtransaction(inputs=[{'txid': txid, 'vout': 9}], outputs=multidict([('data', '99'), ('data', '99')])))))
        assert_equal(len(tx.vout), 2)
        assert_equal(
            bytes_to_hex_str(tx.serialize()),
            self.nodes[2].createrawtransaction(inputs=[{'txid': txid, 'vout': 9}], outputs=[{'data': '99'}, {'data': '99'}]),
        )
        # Multiple mixed outputs
        tx.deserialize(BytesIO(hex_str_to_bytes(self.nodes[2].createrawtransaction(inputs=[{'txid': txid, 'vout': 9}], outputs=multidict([(address, 99), ('data', '99'), ('data', '99')])))))
        assert_equal(len(tx.vout), 3)
        assert_equal(
            bytes_to_hex_str(tx.serialize()),
            self.nodes[2].createrawtransaction(inputs=[{'txid': txid, 'vout': 9}], outputs=[{address: 99}, {'data': '99'}, {'data': '99'}]),
        )

        self.log.info('sendrawtransaction with missing input')
        inputs  = [ {'txid' : "1d1d4e24ed99057e84c3f80fd8fbec79ed9e1acee37da269356ecea000000000", 'vout' : 1}] #won't exists
        outputs = { self.nodes[0].getnewaddress() : 4.998 }
        rawtx   = self.nodes[2].createrawtransaction(inputs, outputs)
        rawtx   = self.nodes[2].signrawtransactionwithwallet(rawtx)

        # This will raise an exception since there are missing inputs
        assert_raises_rpc_error(-25, "Missing inputs", self.nodes[2].sendrawtransaction, rawtx['hex'])

        #####################################
        # getrawtransaction with block hash #
        #####################################

        # make a tx by sending then generate 2 blocks; block1 has the tx in it
        tx = self.nodes[2].sendtoaddress(self.nodes[1].getnewaddress(), 1)
        block1, block2 = self.nodes[2].generate(2)
        self.sync_all()
        # We should be able to get the raw transaction by providing the correct block
        gottx = self.nodes[0].getrawtransaction(tx, True, block1)
        assert_equal(gottx['txid'], tx)
        assert_equal(gottx['in_active_chain'], True)
        # We should not have the 'in_active_chain' flag when we don't provide a block
        gottx = self.nodes[0].getrawtransaction(tx, True)
        assert_equal(gottx['txid'], tx)
        assert 'in_active_chain' not in gottx
        # We should not get the tx if we provide an unrelated block
        assert_raises_rpc_error(-5, "No such transaction found", self.nodes[0].getrawtransaction, tx, True, block2)
        # An invalid block hash should raise the correct errors
        assert_raises_rpc_error(-8, "parameter 3 must be hexadecimal", self.nodes[0].getrawtransaction, tx, True, True)
        assert_raises_rpc_error(-8, "parameter 3 must be hexadecimal", self.nodes[0].getrawtransaction, tx, True, "foobar")
        assert_raises_rpc_error(-8, "parameter 3 must be of length 64", self.nodes[0].getrawtransaction, tx, True, "abcd1234")
        assert_raises_rpc_error(-5, "Block hash not found", self.nodes[0].getrawtransaction, tx, True, "0000000000000000000000000000000000000000000000000000000000000000")
        # Undo the blocks and check in_active_chain
        self.nodes[0].invalidateblock(block1)
        gottx = self.nodes[0].getrawtransaction(txid=tx, verbose=True, blockhash=block1)
        assert_equal(gottx['in_active_chain'], False)
        self.nodes[0].reconsiderblock(block1)
        assert_equal(self.nodes[0].getbestblockhash(), block2)

        #########################
        # RAW TX MULTISIG TESTS #
        #########################
        # 2of2 test
        addr1 = self.nodes[2].getnewaddress()
        addr2 = self.nodes[2].getnewaddress()

        addr1Obj = self.nodes[2].getaddressinfo(addr1)
        addr2Obj = self.nodes[2].getaddressinfo(addr2)

        # Tests for createmultisig and addmultisigaddress
        assert_raises_rpc_error(-5, "Invalid public key", self.nodes[0].createmultisig, 1, ["01020304"])
        self.nodes[0].createmultisig(2, [addr1Obj['pubkey'], addr2Obj['pubkey']]) # createmultisig can only take public keys
        assert_raises_rpc_error(-5, "Invalid public key", self.nodes[0].createmultisig, 2, [addr1Obj['pubkey'], addr1]) # addmultisigaddress can take both pubkeys and addresses so long as they are in the wallet, which is tested here.

        mSigObj = self.nodes[2].addmultisigaddress(2, [addr1Obj['pubkey'], addr1])['address']

        #use balance deltas instead of absolute values
        bal = self.nodes[2].getbalance()

        # send 1.2 BITC to msig adr
        txId = self.nodes[0].sendtoaddress(mSigObj, 1.2)
        self.sync_all()
        self.nodes[0].generate(1)
        self.sync_all()
        assert_equal(self.nodes[2].getbalance(), bal+Decimal('1.20000000')) #node2 has both keys of the 2of2 ms addr., tx should affect the balance


        # 2of3 test from different nodes
        bal = self.nodes[2].getbalance()
        addr1 = self.nodes[1].getnewaddress()
        addr2 = self.nodes[2].getnewaddress()
        addr3 = self.nodes[2].getnewaddress()

        addr1Obj = self.nodes[1].getaddressinfo(addr1)
        addr2Obj = self.nodes[2].getaddressinfo(addr2)
        addr3Obj = self.nodes[2].getaddressinfo(addr3)

        mSigObj = self.nodes[2].addmultisigaddress(2, [addr1Obj['pubkey'], addr2Obj['pubkey'], addr3Obj['pubkey']])['address']

        txId = self.nodes[0].sendtoaddress(mSigObj, 2.2)
        decTx = self.nodes[0].gettransaction(txId)
        rawTx = self.nodes[0].decoderawtransaction(decTx['hex'])
        self.sync_all()
        self.nodes[0].generate(1)
        self.sync_all()

        #THIS IS AN INCOMPLETE FEATURE
        #NODE2 HAS TWO OF THREE KEY AND THE FUNDS SHOULD BE SPENDABLE AND COUNT AT BALANCE CALCULATION
        assert_equal(self.nodes[2].getbalance(), bal) #for now, assume the funds of a 2of3 multisig tx are not marked as spendable

        txDetails = self.nodes[0].gettransaction(txId, True)
        rawTx = self.nodes[0].decoderawtransaction(txDetails['hex'])
        vout = False
        for outpoint in rawTx['vout']:
            if outpoint['value'] == Decimal('2.20000000'):
                vout = outpoint
                break

        bal = self.nodes[0].getbalance()
        inputs = [{ "txid" : txId, "vout" : vout['n'], "scriptPubKey" : vout['scriptPubKey']['hex'], "amount" : vout['value']}]
        outputs = { self.nodes[0].getnewaddress() : 2.19 }
        rawTx = self.nodes[2].createrawtransaction(inputs, outputs)
        rawTxPartialSigned = self.nodes[1].signrawtransactionwithwallet(rawTx, inputs)
        assert_equal(rawTxPartialSigned['complete'], False) #node1 only has one key, can't comp. sign the tx

        rawTxSigned = self.nodes[2].signrawtransactionwithwallet(rawTx, inputs)
        assert_equal(rawTxSigned['complete'], True) #node2 can sign the tx compl., own two of three keys
        self.nodes[2].sendrawtransaction(rawTxSigned['hex'])
        rawTx = self.nodes[0].decoderawtransaction(rawTxSigned['hex'])
        self.sync_all()
        self.nodes[0].generate(1)
        self.sync_all()
        assert_equal(self.nodes[0].getbalance(), bal+Decimal('50.00000000')+Decimal('2.19000000')) #block reward + tx

        # 2of2 test for combining transactions
        bal = self.nodes[2].getbalance()
        addr1 = self.nodes[1].getnewaddress()
        addr2 = self.nodes[2].getnewaddress()

        addr1Obj = self.nodes[1].getaddressinfo(addr1)
        addr2Obj = self.nodes[2].getaddressinfo(addr2)

        self.nodes[1].addmultisigaddress(2, [addr1Obj['pubkey'], addr2Obj['pubkey']])['address']
        mSigObj = self.nodes[2].addmultisigaddress(2, [addr1Obj['pubkey'], addr2Obj['pubkey']])['address']
        mSigObjValid = self.nodes[2].getaddressinfo(mSigObj)

        txId = self.nodes[0].sendtoaddress(mSigObj, 2.2)
        decTx = self.nodes[0].gettransaction(txId)
        rawTx2 = self.nodes[0].decoderawtransaction(decTx['hex'])
        self.sync_all()
        self.nodes[0].generate(1)
        self.sync_all()

        assert_equal(self.nodes[2].getbalance(), bal) # the funds of a 2of2 multisig tx should not be marked as spendable

        txDetails = self.nodes[0].gettransaction(txId, True)
        rawTx2 = self.nodes[0].decoderawtransaction(txDetails['hex'])
        vout = False
        for outpoint in rawTx2['vout']:
            if outpoint['value'] == Decimal('2.20000000'):
                vout = outpoint
                break

        bal = self.nodes[0].getbalance()
        inputs = [{ "txid" : txId, "vout" : vout['n'], "scriptPubKey" : vout['scriptPubKey']['hex'], "redeemScript" : mSigObjValid['hex'], "amount" : vout['value']}]
        outputs = { self.nodes[0].getnewaddress() : 2.19 }
        rawTx2 = self.nodes[2].createrawtransaction(inputs, outputs)
        rawTxPartialSigned1 = self.nodes[1].signrawtransactionwithwallet(rawTx2, inputs)
        self.log.debug(rawTxPartialSigned1)
        assert_equal(rawTxPartialSigned1['complete'], False) #node1 only has one key, can't comp. sign the tx

        rawTxPartialSigned2 = self.nodes[2].signrawtransactionwithwallet(rawTx2, inputs)
        self.log.debug(rawTxPartialSigned2)
        assert_equal(rawTxPartialSigned2['complete'], False) #node2 only has one key, can't comp. sign the tx
        rawTxComb = self.nodes[2].combinerawtransaction([rawTxPartialSigned1['hex'], rawTxPartialSigned2['hex']])
        self.log.debug(rawTxComb)
        self.nodes[2].sendrawtransaction(rawTxComb)
        rawTx2 = self.nodes[0].decoderawtransaction(rawTxComb)
        self.sync_all()
        self.nodes[0].generate(1)
        self.sync_all()
        assert_equal(self.nodes[0].getbalance(), bal+Decimal('50.00000000')+Decimal('2.19000000')) #block reward + tx

        # decoderawtransaction tests
        # witness transaction
        encrawtx = "010000000001010000000000000072c1a6a246ae63f74f931e8365e15a089c68d61900000000000000000000ffffffff0100e1f50500000000000000000000"
        decrawtx = self.nodes[0].decoderawtransaction(encrawtx, True) # decode as witness transaction
        assert_equal(decrawtx['vout'][0]['value'], Decimal('1.00000000'))
        assert_raises_rpc_error(-22, 'TX decode failed', self.nodes[0].decoderawtransaction, encrawtx, False) # force decode as non-witness transaction
        # non-witness transaction
        encrawtx = "01000000010000000000000072c1a6a246ae63f74f931e8365e15a089c68d61900000000000000000000ffffffff0100e1f505000000000000000000"
        decrawtx = self.nodes[0].decoderawtransaction(encrawtx, False) # decode as non-witness transaction
        assert_equal(decrawtx['vout'][0]['value'], Decimal('1.00000000'))

        # getrawtransaction tests
        # 1. valid parameters - only supply txid
        txHash = rawTx["hash"]
        assert_equal(self.nodes[0].getrawtransaction(txHash), rawTxSigned['hex'])

        # 2. valid parameters - supply txid and 0 for non-verbose
        assert_equal(self.nodes[0].getrawtransaction(txHash, 0), rawTxSigned['hex'])

        # 3. valid parameters - supply txid and False for non-verbose
        assert_equal(self.nodes[0].getrawtransaction(txHash, False), rawTxSigned['hex'])

        # 4. valid parameters - supply txid and 1 for verbose.
        # We only check the "hex" field of the output so we don't need to update this test every time the output format changes.
        assert_equal(self.nodes[0].getrawtransaction(txHash, 1)["hex"], rawTxSigned['hex'])

        # 5. valid parameters - supply txid and True for non-verbose
        assert_equal(self.nodes[0].getrawtransaction(txHash, True)["hex"], rawTxSigned['hex'])

        # 6. invalid parameters - supply txid and string "Flase"
        assert_raises_rpc_error(-1, "not a boolean", self.nodes[0].getrawtransaction, txHash, "Flase")

        # 7. invalid parameters - supply txid and empty array
        assert_raises_rpc_error(-1, "not a boolean", self.nodes[0].getrawtransaction, txHash, [])

        # 8. invalid parameters - supply txid and empty dict
        assert_raises_rpc_error(-1, "not a boolean", self.nodes[0].getrawtransaction, txHash, {})

        inputs  = [ {'txid' : "1d1d4e24ed99057e84c3f80fd8fbec79ed9e1acee37da269356ecea000000000", 'vout' : 1, 'sequence' : 1000}]
        outputs = { self.nodes[0].getnewaddress() : 1 }
        rawtx   = self.nodes[0].createrawtransaction(inputs, outputs)
        decrawtx= self.nodes[0].decoderawtransaction(rawtx)
        assert_equal(decrawtx['vin'][0]['sequence'], 1000)

        # 9. invalid parameters - sequence number out of range
        inputs  = [ {'txid' : "1d1d4e24ed99057e84c3f80fd8fbec79ed9e1acee37da269356ecea000000000", 'vout' : 1, 'sequence' : -1}]
        outputs = { self.nodes[0].getnewaddress() : 1 }
        assert_raises_rpc_error(-8, 'Invalid parameter, sequence number is out of range', self.nodes[0].createrawtransaction, inputs, outputs)

        # 10. invalid parameters - sequence number out of range
        inputs  = [ {'txid' : "1d1d4e24ed99057e84c3f80fd8fbec79ed9e1acee37da269356ecea000000000", 'vout' : 1, 'sequence' : 4294967296}]
        outputs = { self.nodes[0].getnewaddress() : 1 }
        assert_raises_rpc_error(-8, 'Invalid parameter, sequence number is out of range', self.nodes[0].createrawtransaction, inputs, outputs)

        inputs  = [ {'txid' : "1d1d4e24ed99057e84c3f80fd8fbec79ed9e1acee37da269356ecea000000000", 'vout' : 1, 'sequence' : 4294967294}]
        outputs = { self.nodes[0].getnewaddress() : 1 }
        rawtx   = self.nodes[0].createrawtransaction(inputs, outputs)
        decrawtx= self.nodes[0].decoderawtransaction(rawtx)
        assert_equal(decrawtx['vin'][0]['sequence'], 4294967294)

        ####################################
        # TRANSACTION VERSION NUMBER TESTS #
        ####################################

        # Test the minimum transaction version number that fits in a signed 32-bit integer.
        tx = CTransaction()
        tx.nVersion = -0x80000000
        rawtx = ToHex(tx)
        decrawtx = self.nodes[0].decoderawtransaction(rawtx)
        assert_equal(decrawtx['version'], -0x80000000)

        # Test the maximum transaction version number that fits in a signed 32-bit integer.
        tx = CTransaction()
        tx.nVersion = 0x7fffffff
        rawtx = ToHex(tx)
        decrawtx = self.nodes[0].decoderawtransaction(rawtx)
        assert_equal(decrawtx['version'], 0x7fffffff)
Ejemplo n.º 24
0
 def get_tx(self):
     tx = CTransaction()
     tx.vin.append(self.valid_txin)
     tx.calc_sha256()
     return tx
Ejemplo n.º 25
0
    def run_test(self):
        peer = self.nodes[0].add_p2p_connection(P2PInterface())
        wallet = MiniWallet(self.nodes[0], mode=MiniWalletMode.RAW_OP_TRUE)

        self.test_cltv_info(is_active=False)

        self.log.info("Mining %d blocks", CLTV_HEIGHT - 2)
        self.generate(wallet, 10)
        self.generate(self.nodes[0], CLTV_HEIGHT - 2 - 10)
        assert_equal(self.nodes[0].getblockcount(), CLTV_HEIGHT - 2)

        self.log.info(
            "Test that invalid-according-to-CLTV transactions can still appear in a block"
        )

        # create one invalid tx per CLTV failure reason (5 in total) and collect them
        invalid_cltv_txs = []
        for i in range(5):
            spendtx = wallet.create_self_transfer(
                from_node=self.nodes[0])['tx']
            cltv_invalidate(spendtx, i)
            invalid_cltv_txs.append(spendtx)

        tip = self.nodes[0].getbestblockhash()
        block_time = self.nodes[0].getblockheader(tip)['mediantime'] + 1
        block = create_block(int(tip, 16), create_coinbase(CLTV_HEIGHT - 1),
                             block_time)
        block.nVersion = 3
        block.vtx.extend(invalid_cltv_txs)
        block.hashMerkleRoot = block.calc_merkle_root()
        block.solve()

        self.test_cltv_info(
            is_active=False
        )  # Not active as of current tip and next block does not need to obey rules
        peer.send_and_ping(msg_block(block))
        self.test_cltv_info(
            is_active=True
        )  # Not active as of current tip, but next block must obey rules
        assert_equal(self.nodes[0].getbestblockhash(), block.hash)

        self.log.info("Test that blocks must now be at least version 4")
        tip = block.sha256
        block_time += 1
        block = create_block(tip, create_coinbase(CLTV_HEIGHT), block_time)
        block.nVersion = 3
        block.solve()

        with self.nodes[0].assert_debug_log(
                expected_msgs=[f'{block.hash}, bad-version(0x00000003)']):
            peer.send_and_ping(msg_block(block))
            assert_equal(int(self.nodes[0].getbestblockhash(), 16), tip)
            peer.sync_with_ping()

        self.log.info(
            "Test that invalid-according-to-CLTV transactions cannot appear in a block"
        )
        block.nVersion = 4
        block.vtx.append(CTransaction(
        ))  # dummy tx after coinbase that will be replaced later

        # create and test one invalid tx per CLTV failure reason (5 in total)
        for i in range(5):
            spendtx = wallet.create_self_transfer(
                from_node=self.nodes[0])['tx']
            cltv_invalidate(spendtx, i)

            expected_cltv_reject_reason = [
                "non-mandatory-script-verify-flag (Operation not valid with the current stack size)",
                "non-mandatory-script-verify-flag (Negative locktime)",
                "non-mandatory-script-verify-flag (Locktime requirement not satisfied)",
                "non-mandatory-script-verify-flag (Locktime requirement not satisfied)",
                "non-mandatory-script-verify-flag (Locktime requirement not satisfied)",
            ][i]
            # First we show that this tx is valid except for CLTV by getting it
            # rejected from the mempool for exactly that reason.
            assert_equal(
                [{
                    'txid': spendtx.hash,
                    'wtxid': spendtx.getwtxid(),
                    'allowed': False,
                    'reject-reason': expected_cltv_reject_reason,
                }],
                self.nodes[0].testmempoolaccept(
                    rawtxs=[spendtx.serialize().hex()], maxfeerate=0),
            )

            # Now we verify that a block with this transaction is also invalid.
            block.vtx[1] = spendtx
            block.hashMerkleRoot = block.calc_merkle_root()
            block.solve()

            with self.nodes[0].assert_debug_log(expected_msgs=[
                    f'CheckInputScripts on {block.vtx[-1].hash} failed with {expected_cltv_reject_reason}'
            ]):
                peer.send_and_ping(msg_block(block))
                assert_equal(int(self.nodes[0].getbestblockhash(), 16), tip)
                peer.sync_with_ping()

        self.log.info(
            "Test that a version 4 block with a valid-according-to-CLTV transaction is accepted"
        )
        cltv_validate(spendtx, CLTV_HEIGHT - 1)

        block.vtx.pop(1)
        block.vtx.append(spendtx)
        block.hashMerkleRoot = block.calc_merkle_root()
        block.solve()

        self.test_cltv_info(
            is_active=True
        )  # Not active as of current tip, but next block must obey rules
        peer.send_and_ping(msg_block(block))
        self.test_cltv_info(is_active=True)  # Active as of current tip
        assert_equal(int(self.nodes[0].getbestblockhash(), 16), block.sha256)
Ejemplo n.º 26
0
 def get_tx(self):
     tx = CTransaction()
     tx.calc_sha256()
     return tx
Ejemplo n.º 27
0
    def test_opt_in(self):
        """Replacing should only work if orig tx opted in"""
        tx0_outpoint = make_utxo(self.nodes[0], int(1.1 * COIN))

        # Create a non-opting in transaction
        tx1a = CTransaction()
        tx1a.vin = [CTxIn(tx0_outpoint, nSequence=0xffffffff)]
        tx1a.vout = [CTxOut(1 * COIN, DUMMY_P2WPKH_SCRIPT)]
        tx1a_hex = txToHex(tx1a)
        tx1a_txid = self.nodes[0].sendrawtransaction(tx1a_hex, 0)

        # This transaction isn't shown as replaceable
        assert_equal(
            self.nodes[0].getmempoolentry(tx1a_txid)['bip125-replaceable'],
            False)

        # Shouldn't be able to double-spend
        tx1b = CTransaction()
        tx1b.vin = [CTxIn(tx0_outpoint, nSequence=0)]
        tx1b.vout = [CTxOut(int(0.9 * COIN), DUMMY_P2WPKH_SCRIPT)]
        tx1b_hex = txToHex(tx1b)

        # This will raise an exception
        assert_raises_rpc_error(-26, "txn-mempool-conflict",
                                self.nodes[0].sendrawtransaction, tx1b_hex, 0)

        tx1_outpoint = make_utxo(self.nodes[0], int(1.1 * COIN))

        # Create a different non-opting in transaction
        tx2a = CTransaction()
        tx2a.vin = [CTxIn(tx1_outpoint, nSequence=0xfffffffe)]
        tx2a.vout = [CTxOut(1 * COIN, DUMMY_P2WPKH_SCRIPT)]
        tx2a_hex = txToHex(tx2a)
        tx2a_txid = self.nodes[0].sendrawtransaction(tx2a_hex, 0)

        # Still shouldn't be able to double-spend
        tx2b = CTransaction()
        tx2b.vin = [CTxIn(tx1_outpoint, nSequence=0)]
        tx2b.vout = [CTxOut(int(0.9 * COIN), DUMMY_P2WPKH_SCRIPT)]
        tx2b_hex = txToHex(tx2b)

        # This will raise an exception
        assert_raises_rpc_error(-26, "txn-mempool-conflict",
                                self.nodes[0].sendrawtransaction, tx2b_hex, 0)

        # Now create a new transaction that spends from tx1a and tx2a
        # opt-in on one of the inputs
        # Transaction should be replaceable on either input

        tx1a_txid = int(tx1a_txid, 16)
        tx2a_txid = int(tx2a_txid, 16)

        tx3a = CTransaction()
        tx3a.vin = [
            CTxIn(COutPoint(tx1a_txid, 0), nSequence=0xffffffff),
            CTxIn(COutPoint(tx2a_txid, 0), nSequence=0xfffffffd)
        ]
        tx3a.vout = [
            CTxOut(int(0.9 * COIN), CScript([b'c'])),
            CTxOut(int(0.9 * COIN), CScript([b'd']))
        ]
        tx3a_hex = txToHex(tx3a)

        tx3a_txid = self.nodes[0].sendrawtransaction(tx3a_hex, 0)

        # This transaction is shown as replaceable
        assert_equal(
            self.nodes[0].getmempoolentry(tx3a_txid)['bip125-replaceable'],
            True)

        tx3b = CTransaction()
        tx3b.vin = [CTxIn(COutPoint(tx1a_txid, 0), nSequence=0)]
        tx3b.vout = [CTxOut(int(0.5 * COIN), DUMMY_P2WPKH_SCRIPT)]
        tx3b_hex = txToHex(tx3b)

        tx3c = CTransaction()
        tx3c.vin = [CTxIn(COutPoint(tx2a_txid, 0), nSequence=0)]
        tx3c.vout = [CTxOut(int(0.5 * COIN), DUMMY_P2WPKH_SCRIPT)]
        tx3c_hex = txToHex(tx3c)

        self.nodes[0].sendrawtransaction(tx3b_hex, 0)
        # If tx3b was accepted, tx3c won't look like a replacement,
        # but make sure it is accepted anyway
        self.nodes[0].sendrawtransaction(tx3c_hex, 0)
Ejemplo n.º 28
0
 def get_tx(self):
     tx = CTransaction()
     tx.vin.append(self.valid_txin)
     tx.vout.append(CTxOut(0, sc.CScript([sc.OP_TRUE])))
     tx.calc_sha256()
     return tx
Ejemplo n.º 29
0
    def test_multiple_children(self):
        node = self.nodes[0]

        self.log.info(
            "Testmempoolaccept a package in which a transaction has two children within the package"
        )
        first_coin = self.coins.pop()
        value = (first_coin["amount"] - Decimal("0.0002")
                 ) / 2  # Deduct reasonable fee and make 2 outputs
        inputs = [{"txid": first_coin["txid"], "vout": 0}]
        outputs = [{self.address: value}, {ADDRESS_BCRT1_P2WSH_OP_TRUE: value}]
        rawtx = node.createrawtransaction(inputs, outputs)

        parent_signed = node.signrawtransactionwithkey(hexstring=rawtx,
                                                       privkeys=self.privkeys)
        parent_tx = CTransaction()
        assert parent_signed["complete"]
        parent_tx.deserialize(BytesIO(hex_str_to_bytes(parent_signed["hex"])))
        parent_txid = parent_tx.rehash()
        assert node.testmempoolaccept([parent_signed["hex"]])[0]["allowed"]

        parent_locking_script_a = parent_tx.vout[0].scriptPubKey.hex()
        child_value = value - Decimal("0.0001")

        # Child A
        (_, tx_child_a_hex, _,
         _) = self.chain_transaction(parent_txid, child_value, 0,
                                     parent_locking_script_a)
        assert not node.testmempoolaccept([tx_child_a_hex])[0]["allowed"]

        # Child B
        rawtx_b = node.createrawtransaction([{
            "txid": parent_txid,
            "vout": 1
        }], {self.address: child_value})
        tx_child_b = CTransaction()
        tx_child_b.deserialize(BytesIO(hex_str_to_bytes(rawtx_b)))
        tx_child_b.wit.vtxinwit = [CTxInWitness()]
        tx_child_b.wit.vtxinwit[0].scriptWitness.stack = [CScript([OP_TRUE])]
        tx_child_b_hex = tx_child_b.serialize().hex()
        assert not node.testmempoolaccept([tx_child_b_hex])[0]["allowed"]

        self.log.info(
            "Testmempoolaccept with entire package, should work with children in either order"
        )
        testres_multiple_ab = node.testmempoolaccept(
            rawtxs=[parent_signed["hex"], tx_child_a_hex, tx_child_b_hex])
        testres_multiple_ba = node.testmempoolaccept(
            rawtxs=[parent_signed["hex"], tx_child_b_hex, tx_child_a_hex])
        assert all([
            testres["allowed"]
            for testres in testres_multiple_ab + testres_multiple_ba
        ])

        testres_single = []
        # Test accept and then submit each one individually, which should be identical to package testaccept
        for rawtx in [parent_signed["hex"], tx_child_a_hex, tx_child_b_hex]:
            testres = node.testmempoolaccept([rawtx])
            testres_single.append(testres[0])
            # Submit the transaction now so its child should have no problem validating
            node.sendrawtransaction(rawtx)
        assert_equal(testres_single, testres_multiple_ab)
    def _zmq_test(self):
        num_blocks = 5
        self.log.info("Generate %(n)d blocks (and %(n)d coinbase txes)" %
                      {"n": num_blocks})
        genhashes = self.nodes[0].generatetoaddress(num_blocks,
                                                    ADDRESS_BCRT1_UNSPENDABLE)
        self.sync_all()

        for x in range(num_blocks):
            # Should receive the coinbase txid.
            txid = self.hashtx.receive()

            # Should receive the coinbase raw transaction.
            hex = self.rawtx.receive()
            tx = CTransaction()
            tx.deserialize(BytesIO(hex))
            tx.calc_sha256()
            assert_equal(tx.hash, bytes_to_hex_str(txid))

            # Should receive the generated block hash.
            hash = bytes_to_hex_str(self.hashblock.receive())
            assert_equal(genhashes[x], hash)
            # The block should only have the coinbase txid.
            assert_equal([bytes_to_hex_str(txid)],
                         self.nodes[1].getblock(hash)["tx"])

            # Should receive the generated raw block.
            block = self.rawblock.receive()
            assert_equal(genhashes[x], bytes_to_hex_str(hash256(block[:80])))

        if self.is_wallet_compiled():
            self.log.info("Wait for tx from second node")
            payment_txid = self.nodes[1].sendtoaddress(
                self.nodes[0].getnewaddress(), 1.0)
            self.sync_all()

            # Should receive the broadcasted txid.
            txid = self.hashtx.receive()
            assert_equal(payment_txid, bytes_to_hex_str(txid))

            # Should receive the broadcasted raw transaction.
            hex = self.rawtx.receive()
            assert_equal(payment_txid, bytes_to_hex_str(hash256(hex)))

        self.log.info("Test the getzmqnotifications RPC")
        assert_equal(self.nodes[0].getzmqnotifications(), [
            {
                "type": "pubhashblock",
                "address": ADDRESS
            },
            {
                "type": "pubhashtx",
                "address": ADDRESS
            },
            {
                "type": "pubrawblock",
                "address": ADDRESS
            },
            {
                "type": "pubrawtx",
                "address": ADDRESS
            },
        ])

        assert_equal(self.nodes[1].getzmqnotifications(), [])