Пример #1
0
    def generate_small_transactions(node, count, utxo_list):
        fee = 100000000  # TODO: replace this with node relay fee based calculation
        num_transactions = 0
        random.shuffle(utxo_list)
        utxo = None
        while len(utxo_list) >= 2 and num_transactions < count:
            tx = CTransaction()
            input_amount = 0
            for _ in range(2):
                utxo = utxo_list.pop()
                tx.vin.append(
                    CTxIn(COutPoint(int(utxo['txid'], 16), utxo['vout'])))
                input_amount += int(utxo['amount'] * COIN)
            output_amount = (input_amount - fee) // 3

            if output_amount <= 0:
                # Sanity check -- if we chose inputs that are too small, skip
                continue

            for _ in range(3):
                if utxo is not None:
                    tx.vout.append(
                        CTxOut(output_amount,
                               hex_str_to_bytes(utxo['scriptPubKey'])))

            # Sign and send the transaction to get into the mempool
            tx_signed_hex = node.signrawtransaction(to_hex(tx))['hex']
            node.sendrawtransaction(tx_signed_hex)
            num_transactions += 1
Пример #2
0
    def get_tests(self):
        # shorthand for functions
        block = self.chain.next_block

        node = self.nodes[0]
        self.chain.set_genesis_hash(int(node.getbestblockhash(), 16))

        # Now we need that block to mature so we can spend the coinbase.
        test = TestInstance(sync_every_block=False)
        for i in range(105):
            block(5000 + i)
            test.blocks_and_transactions.append([self.chain.tip, True])
            self.chain.save_spendable_output()
        yield test

        # collect spendable outputs now to avoid cluttering the code later on
        out = []
        for i in range(105):
            out.append(self.chain.get_spendable_output())

        assert_equal(node.getblock(node.getbestblockhash())['height'], 105)

        block(1)

        redeem_script = CScript([OP_TRUE, OP_RETURN, b"a" * 5000])

        spend_tx1 = CTransaction()
        spend_tx1.vin.append(
            CTxIn(COutPoint(out[2].tx.sha256, out[2].n), CScript(),
                  0xffffffff))
        spend_tx1.vout.append(CTxOut(500, redeem_script))
        spend_tx1.vout.append(CTxOut(500, redeem_script))
        spend_tx1.calc_sha256()
        self.log.info(spend_tx1.hash)

        self.chain.update_block(1, [spend_tx1])
        yield self.accepted()

        tx1 = CTransaction()
        tx1.vout = [CTxOut(499, CScript([OP_TRUE]))]
        tx1.vin.append(
            CTxIn(COutPoint(spend_tx1.sha256, 0), CScript(), 0xfffffff))
        tx1.vin.append(
            CTxIn(COutPoint(spend_tx1.sha256, 1), CScript(), 0xfffffff))
        tx1.calc_sha256()
        self.log.info(tx1.hash)
        yield TestInstance(
            [[tx1, RejectResult(16, b'bad-txns-inputs-too-large')]])
    def get_tests(self):
        # shorthand for functions
        block = self.chain.next_block

        node = self.nodes[0]
        self.chain.set_genesis_hash(int(node.getbestblockhash(), 16))

        test, out, _ = prepare_init_chain(self.chain, 105, 105, block_0=False)

        yield test

        assert_equal(node.getblock(node.getbestblockhash())['height'], 105)

        block(1)

        redeem_script = CScript([OP_TRUE, OP_RETURN, b"a" * 5000])

        spend_tx1 = CTransaction()
        spend_tx1.vin.append(
            CTxIn(COutPoint(out[2].tx.sha256, out[2].n), CScript(),
                  0xffffffff))
        spend_tx1.vout.append(CTxOut(500, redeem_script))
        spend_tx1.vout.append(CTxOut(500, redeem_script))
        spend_tx1.calc_sha256()
        self.log.info(spend_tx1.hash)

        self.chain.update_block(1, [spend_tx1])
        yield self.accepted()

        tx1 = CTransaction()
        tx1.vout = [CTxOut(499, CScript([OP_TRUE]))]
        tx1.vin.append(
            CTxIn(COutPoint(spend_tx1.sha256, 0), CScript(), 0xfffffff))
        tx1.vin.append(
            CTxIn(COutPoint(spend_tx1.sha256, 1), CScript(), 0xfffffff))
        tx1.calc_sha256()
        self.log.info(tx1.hash)
        yield TestInstance(
            [[tx1, RejectResult(16, b'bad-txns-inputs-too-large')]])
    def _zmq_test(self):
        block_hashes = self.nodes[0].generate(101)
        """Test case 1"""
        tx_hash1 = self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(),
                                               1.0)
        tx_hash2 = self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(),
                                               1.0)

        block_hash1 = self.nodes[0].generate(1)[0]
        # sync blocks so we are synchronized later in test
        sync_blocks(self.nodes)

        # receive notifications for txs to be included in block
        msg1 = self.zmqSubSocket.recv_multipart()
        assert_equal(msg1[0], b"removedfrommempoolblock")
        msg1_body = json.loads(msg1[1])
        assert_equal(msg1_body["reason"], "included-in-block")
        msg2 = self.zmqSubSocket.recv_multipart()
        assert_equal(msg2[0], b"removedfrommempoolblock")
        msg2_body = json.loads(msg2[1])
        assert_equal(msg2_body["reason"], "included-in-block")

        removed_tx = [msg1_body["txid"], msg2_body["txid"]]
        assert_equal(tx_hash1 in removed_tx and tx_hash2 in removed_tx, True)
        """Test case 2"""
        # bring txs back to mempool
        self.nodes[0].invalidateblock(block_hash1)
        # invalidate again so the coins that txs uses are immature
        self.nodes[0].invalidateblock(block_hashes[len(block_hashes) - 2])

        # receive notifications for txs about reorg mempool removal reason
        msg1 = self.zmqSubSocket.recv_multipart()
        assert_equal(msg1[0], b"removedfrommempoolblock")
        msg1_body = json.loads(msg1[1])
        assert_equal(msg1_body["reason"], "reorg")
        msg2 = self.zmqSubSocket.recv_multipart()
        assert_equal(msg2[0], b"removedfrommempoolblock")
        msg2_body = json.loads(msg2[1])
        assert_equal(msg2_body["reason"], "reorg")

        removed_tx = [msg1_body["txid"], msg2_body["txid"]]
        assert_equal(tx_hash1 in removed_tx and tx_hash2 in removed_tx, True)
        """Test case 3"""
        # bring both nodes on same height
        self.nodes[1].invalidateblock(block_hashes[len(block_hashes) - 2])
        self.nodes[0].generate(4)
        sync_blocks(self.nodes)
        unspent = self.nodes[0].listunspent()[0]

        # create tx with spendable output for both nodes to use
        tx_spendable_output = CTransaction()
        tx_outs = [CTxOut(4500000000, CScript([OP_TRUE]))]
        tx_spendable_output.vout = tx_outs
        tx_spendable_output.vin = [
            CTxIn(COutPoint(int(unspent["txid"], 16), 0))
        ]

        tx_hex = self.nodes[0].signrawtransaction(
            ToHex(tx_spendable_output))['hex']
        self.nodes[0].sendrawtransaction(tx_hex, True)
        tx_spendable_output = FromHex(CTransaction(), tx_hex)
        tx_spendable_output.rehash()

        self.nodes[0].generate(1)
        # ignore included in block message
        _ = self.zmqSubSocket.recv_multipart()
        sync_blocks(self.nodes)

        # disconnect nodes and create transaction tx2 on node1 and mine a block
        # then create tx1 on node0 that use same output as tx2.
        disconnect_nodes_bi(self.nodes, 0, 1)

        tx2 = CTransaction()
        tx_outs = [CTxOut(4400000000, CScript([OP_TRUE]))]
        tx2.vout = tx_outs
        tx2.vin = [CTxIn(COutPoint(int(tx_spendable_output.hash, 16), 0))]

        tx_hex = self.nodes[1].signrawtransaction(ToHex(tx2))['hex']
        tx2_size = len(tx_hex) / 2
        tx2 = FromHex(CTransaction(), tx_hex)
        tx2.rehash()
        self.nodes[1].sendrawtransaction(tx_hex, True)
        blockhash = self.nodes[1].generate(1)[0]

        tx1 = CTransaction()
        tx_outs = [CTxOut(4300000000, CScript([OP_TRUE]))]
        tx1.vout = tx_outs
        tx1.vin = [CTxIn(COutPoint(int(tx_spendable_output.hash, 16), 0))]

        tx_hex = self.nodes[0].signrawtransaction(ToHex(tx1))['hex']
        tx1 = FromHex(CTransaction(), tx_hex)
        tx1.rehash()
        self.nodes[0].sendrawtransaction(tx_hex, True)

        # connect nodes again and sync blocks, we now expect to get conflict for tx1
        # because tx2 that uses same output as tx1 is already in block.
        connect_nodes_bi(self.nodes, 0, 1)
        sync_blocks(self.nodes)

        msg = self.zmqSubSocket.recv_multipart()
        assert_equal(msg[0], b"discardedfrommempool")
        body = json.loads(msg[1])
        assert_equal(body["reason"], "collision-in-block-tx")
        assert_equal(body["txid"], tx1.hash)
        assert_equal(body["collidedWith"]["txid"], tx2.hash)
        assert_equal(body["collidedWith"]["size"], tx2_size)
        assert_equal(body["blockhash"], blockhash)
        """Test case 4"""
        # create tx with spendable output for both nodes to use
        unspent = self.nodes[0].listunspent()[0]
        tx_spendable_output = CTransaction()
        tx_outs = [CTxOut(4500000000, CScript([OP_TRUE]))]
        tx_spendable_output.vout = tx_outs
        tx_spendable_output.vin = [
            CTxIn(COutPoint(int(unspent["txid"], 16), 0))
        ]

        tx_hex = self.nodes[0].signrawtransaction(
            ToHex(tx_spendable_output))['hex']
        self.nodes[0].sendrawtransaction(tx_hex, True)
        tx_spendable_output = FromHex(CTransaction(), tx_hex)
        tx_spendable_output.rehash()

        self.nodes[0].generate(5)
        # ignore included in block message
        _ = self.zmqSubSocket.recv_multipart()
        sync_blocks(self.nodes)

        # disconnect nodes; mine few blocks on n1; create transaction tx2 on node1 and mine a block
        # then create tx1 on node0 that use same output as tx2.
        disconnect_nodes_bi(self.nodes, 0, 1)

        self.nodes[1].generate(5)
        tx2 = CTransaction()
        tx_outs = [CTxOut(4400000000, CScript([OP_TRUE]))]
        tx2.vout = tx_outs
        tx2.vin = [CTxIn(COutPoint(int(tx_spendable_output.hash, 16), 0))]

        tx_hex = self.nodes[1].signrawtransaction(ToHex(tx2))['hex']
        tx2_size = len(tx_hex) / 2
        tx2 = FromHex(CTransaction(), tx_hex)
        tx2.rehash()
        self.nodes[1].sendrawtransaction(tx_hex, True)
        blockhash_tx2 = self.nodes[1].generate(1)[0]

        tx1 = CTransaction()
        tx_outs = [CTxOut(4300000000, CScript([OP_TRUE]))]
        tx1.vout = tx_outs
        tx1.vin = [CTxIn(COutPoint(int(tx_spendable_output.hash, 16), 0))]

        tx_hex = self.nodes[0].signrawtransaction(ToHex(tx1))['hex']
        tx1 = FromHex(CTransaction(), tx_hex)
        tx1.rehash()
        self.nodes[0].sendrawtransaction(tx_hex, True)

        self.nodes[0].generate(1)
        # ignore included in block message
        _ = self.zmqSubSocket.recv_multipart()

        # connect nodes again to cause reorg to n1 chain, we now expect to
        # get conflict for tx1, because tx2 that uses same input as tx1 is already
        # in block on longer chain.
        connect_nodes_bi(self.nodes, 0, 1)
        sync_blocks(self.nodes)

        msg = self.zmqSubSocket.recv_multipart()
        assert_equal(msg[0], b"discardedfrommempool")
        body = json.loads(msg[1])
        assert_equal(body["reason"], "collision-in-block-tx")
        assert_equal(body["txid"], tx1.hash)
        assert_equal(body["collidedWith"]["txid"], tx2.hash)
        assert_equal(body["collidedWith"]["size"], tx2_size)
        assert_equal(body["blockhash"], blockhash_tx2)