def get_tests(self):

        # shorthand for functions
        block = self.chain.next_block
        node = get_rpc_proxy(self.nodes[0].url,
                             1,
                             timeout=6000,
                             coveragedir=self.nodes[0].coverage_dir)

        self.chain.set_genesis_hash(int(node.getbestblockhash(), 16))

        block(0)
        yield self.accepted()

        test, out, _ = prepare_init_chain(self.chain, 200, 200)

        yield test

        txHashes = []
        for i in range(18):
            txLarge = create_transaction(
                out[i].tx, out[i].n, b"", ONE_MEGABYTE * 256,
                CScript([
                    OP_FALSE, OP_RETURN,
                    bytearray([42] * (ONE_MEGABYTE * 256))
                ]))
            self.test.connections[0].send_message(msg_tx(txLarge))
            self.check_mempool(node, [txLarge], timeout=6000)
            txHashes.append([txLarge.hash, txLarge.sha256])

        txOverflow = create_transaction(
            out[18].tx, out[18].n, b"", ONE_MEGABYTE * 305,
            CScript(
                [OP_FALSE, OP_RETURN,
                 bytearray([42] * (ONE_MEGABYTE * 305))]))
        self.test.connections[0].send_message(msg_tx(txOverflow))
        self.check_mempool(node, [txOverflow], timeout=6000)
        txHashes.append([txOverflow.hash, txOverflow.sha256])

        txOverflow = create_transaction(
            out[19].tx, out[19].n, b"", ONE_MEGABYTE,
            CScript([OP_FALSE, OP_RETURN,
                     bytearray([42] * ONE_MEGABYTE)]))
        self.test.connections[0].send_message(msg_tx(txOverflow))
        self.check_mempool(node, [txOverflow], timeout=6000)
        txHashes.append([txOverflow.hash, txOverflow.sha256])

        # Mine block with new transactions.
        self.log.info("BLOCK 2 - mining")
        minedBlock2 = node.generate(1)
        self.log.info("BLOCK 2 - mined")

        for txHash in txHashes:
            tx = FromHex(CTransaction(),
                         self.nodes[0].getrawtransaction(txHash[0]))
            tx.rehash()
            assert_equal(tx.sha256, txHash[1])
예제 #2
0
    def run_test(self):
        for node in self.nodes:
            self.consolidation_factor = int(
                node.getnetworkinfo()['minconsolidationfactor'])
            self.minConfirmations = int(
                node.getnetworkinfo()['minconsolidationinputmaturity'])
            self.log.info("consolidation factor: {}".format(
                self.consolidation_factor))
            self.log.info("minimum input confirmations: {}".format(
                self.minConfirmations))

            node.generate(300)

            # test ratio between size of input script and size of output script
            tx_hex = self.create_and_sign_tx(node, 1, min_confirmations=1)
            tx = FromHex(CTransaction(), tx_hex)
            tx.rehash()
            sin = len(getInputScriptPubKey(node, tx.vin[0], 0))
            sout = len(tx.vout[0].scriptPubKey)

            enough_inputs = sout * self.consolidation_factor // sin
            enough_inputs = max(enough_inputs, 2)
            enough_confirmations = self.minConfirmations

            # FAILING CONDITION: input_sizes <= consolidation_factor * output_size
            # We assume scriptSig ~ 4 * scriptPubKey
            tx_hex = self.create_and_sign_tx(
                node,
                in_count=enough_inputs - 1,
                min_confirmations=enough_confirmations)
            assert_raises_rpc_error(-26, "66: insufficient priority",
                                    node.sendrawtransaction, tx_hex)
            self.log.info("test 1: PASS")

            # FAILING CONDITION: not enough input confirmations
            tx_hex = self.create_and_sign_tx(
                node,
                in_count=enough_inputs,
                min_confirmations=enough_confirmations - 1)
            assert_raises_rpc_error(-26, "66: insufficient priority",
                                    node.sendrawtransaction, tx_hex)
            self.log.info("test 2: PASS")

            # ALL CONDITIONS MET: must succeed
            tx_hex = self.create_and_sign_tx(
                node,
                in_count=enough_inputs,
                min_confirmations=enough_confirmations)
            txid = node.sendrawtransaction(tx_hex)
            node.generate(1)
            tx = node.getrawtransaction(txid, 1)
            confirmations = tx.get('confirmations', 0)
            assert_equal(confirmations, 1)
            self.log.info("test 3: PASS")
예제 #3
0
    def get_tests(self):

        # shorthand for functions
        block = self.chain.next_block
        node = get_rpc_proxy(self.nodes[0].url, 1, timeout=6000, coveragedir=self.nodes[0].coverage_dir)

        self.chain.set_genesis_hash( int(node.getbestblockhash(), 16) )
        # Create a new block
        block(0)

        self.chain.save_spendable_output()
        yield self.accepted()

        # Now we need that block to mature so we can spend the coinbase.
        test = TestInstance(sync_every_block=False)
        for i in range(200):
            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(200):
            out.append(self.chain.get_spendable_output())

        txHashes = []
        for i in range(18):
            txLarge = create_transaction(out[i].tx, out[i].n, b"", ONE_MEGABYTE * 256, CScript([OP_FALSE, OP_RETURN, bytearray([42] * (ONE_MEGABYTE * 256))]))
            self.test.connections[0].send_message(msg_tx(txLarge))
            self.check_mempool(node, [txLarge])
            txHashes.append([txLarge.hash, txLarge.sha256])

        txOverflow = create_transaction(out[18].tx, out[18].n, b"", ONE_MEGABYTE * 305, CScript([OP_FALSE, OP_RETURN, bytearray([42] * (ONE_MEGABYTE * 305))]))
        self.test.connections[0].send_message(msg_tx(txOverflow))
        self.check_mempool(node, [txOverflow])
        txHashes.append([txOverflow.hash, txOverflow.sha256])

        txOverflow = create_transaction(out[19].tx, out[19].n, b"", ONE_MEGABYTE, CScript([OP_FALSE, OP_RETURN, bytearray([42] * ONE_MEGABYTE)]))
        self.test.connections[0].send_message(msg_tx(txOverflow))
        self.check_mempool(node, [txOverflow])
        txHashes.append([txOverflow.hash, txOverflow.sha256])

        # Mine block with new transactions.
        self.log.info("BLOCK 2 - mining")
        minedBlock2 = node.generate(1)
        self.log.info("BLOCK 2 - mined")

        for txHash in txHashes:
            tx = FromHex(CTransaction(), self.nodes[0].getrawtransaction(txHash[0]))
            tx.rehash()
            assert_equal(tx.sha256, txHash[1])
예제 #4
0
    def create_utxos_value10000(self, node, utxo_count, min_confirmations):

        utxos = []
        addr = node.getnewaddress()
        for i in range(utxo_count):
            txid = node.sendtoaddress(addr, self.utxo_test_bsvs)
            tx = FromHex(CTransaction(), node.getrawtransaction(txid))
            tx.rehash()
            utxos.append(tx)

        if min_confirmations > 0:
            node.generate(min_confirmations)

        return utxos
예제 #5
0
    def test_basics(self, xt_node, test_node):
        self.log.info("bip64: basic checks")
        txid = xt_node.sendtoaddress(xt_node.getnewaddress(), 0.1)
        tx = FromHex(CTransaction(), xt_node.getrawtransaction(txid))
        tx.rehash()

        new_outpoint = COutPoint(tx.sha256, 0)
        prev_outpoint = tx.vin[0].prevout

        # Test that the utxo doesn't exist in the chain.
        self.get_utxos([new_outpoint], checkmempool=False)
        assert_equal(test_node.utxos.bitmap[0], int('0', 2))
        assert_equal(len(test_node.utxos.result), 0)

        # It does exist in the mempool.
        self.get_utxos([new_outpoint], checkmempool=True)
        assert_equal(test_node.utxos.bitmap[0], int('1', 2))
        assert_equal(len(test_node.utxos.result), 1)
        magic_inmempool_height = 2147483647
        assert_equal(test_node.utxos.result[0].height, magic_inmempool_height)

        # The prevout exists in the chain
        self.get_utxos([prev_outpoint], checkmempool=False)
        assert_equal(test_node.utxos.bitmap[0], int('1', 2))

        # The prevout is spent in the mempool.
        self.get_utxos([prev_outpoint], checkmempool=True)
        assert_equal(test_node.utxos.bitmap[0], int('0', 2))

        # Mine tx creating new_outpoint, now it should exist in the chain.
        xt_node.generate(1)
        self.get_utxos([new_outpoint], checkmempool=False)
        assert_equal(test_node.utxos.bitmap[0], int('1', 2))
        assert_equal(test_node.utxos.result[0].height, xt_node.getblockcount())

        # .. same result when including mempool
        self.get_utxos([new_outpoint], checkmempool=True)
        assert_equal(test_node.utxos.bitmap[0], int('1', 2))

        # Check that we can fetch multiple outpoints
        self.get_utxos([new_outpoint, prev_outpoint], checkmempool=False)
        assert_equal(test_node.utxos.bitmap[0], int('01', 2))
        self.get_utxos([prev_outpoint, new_outpoint], checkmempool=False)
        assert_equal(test_node.utxos.bitmap[0], int('10', 2))
        self.get_utxos([new_outpoint, prev_outpoint, new_outpoint],
                       checkmempool=False)
        assert_equal(test_node.utxos.bitmap[0], int('101', 2))
예제 #6
0
    def create_utxos_value100000(self, node, utxo_count, utxo_size,
                                 min_confirmations):

        utxos = []
        addr = node.getnewaddress()

        # create some confirmed UTXOs
        for i in range(utxo_count):
            txid = node.sendtoaddress(addr, self.utxo_test_bsvs)
            tx = FromHex(CTransaction(), node.getrawtransaction(txid))
            tx.rehash()
            utxos.append(tx)

        node.generate(1)

        # Convert those utxos to new UTXO's in one single transaction that anyone can spend
        tx = None
        fee = 0

        for _ in range(2):  # firs iteration is to calculate the fee
            tx = CTransaction()
            amount = self.utxo_test_sats
            check_size = 0
            for u in utxos:

                # Each UTXO will have two outputs, one for change and another one
                # amounting to roughly 10000 satoshis
                for i in range(len(u.vout)):
                    uu = u.vout[i]
                    if uu.nValue <= self.utxo_test_sats and uu.nValue > self.utxo_test_sats // 2:
                        tx.vin.append(
                            CTxIn(
                                COutPoint(
                                    uint256_from_str(
                                        hex_str_to_bytes(u.hash)[::-1]), i),
                                b''))
                        break

                adjust = 2
                scriptPubKey = CScript([OP_DROP] +
                                       ([OP_NOP] *
                                        ((utxo_size // utxo_count) - adjust)) +
                                       [OP_TRUE])

                if len(tx.vin) == utxo_count:
                    amount = amount - fee

                    while True:
                        scriptPubKey = CScript([OP_DROP] + ([OP_NOP] * (
                            (utxo_size // utxo_count) - adjust)) + [OP_TRUE])

                        if check_size + len(scriptPubKey) > utxo_size:
                            adjust = adjust + 1
                            continue
                        elif check_size + len(scriptPubKey) < utxo_size:
                            adjust = adjust - 1
                            continue
                        break

                check_size = check_size + len(scriptPubKey)
                tx.vout.append(CTxOut(amount, scriptPubKey))

            assert (len(tx.vout) == utxo_count)
            assert (check_size == utxo_size)

            # sign and send transaction
            txHex = node.signrawtransaction(ToHex(tx))['hex']
            tx = FromHex(CTransaction(), txHex)
            tx.rehash()
            tx_size = len(ToHex(tx))
            fee = int(self.blockmintxfee_sats * tx_size / 1000)

        node.sendrawtransaction(ToHex(tx))

        if min_confirmations > 0:
            node.generate(min_confirmations)

        return tx
예제 #7
0
    def run_test(self):

        # Turn on a webhook server
        self.start_webhook_server()

        # Create a P2P connection
        node = self.nodes[0]
        peer = NodeConnCB()
        connection = NodeConn('127.0.0.1', p2p_port(0), node, peer)
        peer.add_connection(connection)
        NetworkThread().start()
        peer.wait_for_verack()

        # Create an initial block with a coinbase we will split into multiple utxos
        initialBlock, _ = make_block(connection)
        coinbaseTx = initialBlock.vtx[0]

        send_by_headers(connection, [initialBlock], do_send_blocks=True)
        wait_for_tip(connection, initialBlock.hash)

        node.generate(101)
        block101hex = node.getblock(node.getbestblockhash(), False)
        block101dict = node.getblock(node.getbestblockhash(), 2)
        block101 = FromHex(CBlock(), block101hex)
        block101.height = block101dict['height']
        block101.rehash()

        # Create a block with a transaction spending coinbaseTx of a previous block and making multiple outputs for future transactions to spend
        utxoBlock, _ = make_block(connection, parent_block=block101)
        utxoTx = create_tx(coinbaseTx, 0, 1 * COIN)

        # Create additional 48 outputs (we let 1 COIN as fee)
        for _ in range(48):
            utxoTx.vout.append(CTxOut(1 * COIN, CScript([OP_TRUE])))
        # Add to block
        utxoTx.rehash()

        utxoBlock.vtx.append(utxoTx)
        utxoBlock.hashMerkleRoot = utxoBlock.calc_merkle_root()
        utxoBlock.solve()

        send_by_headers(connection, [utxoBlock], do_send_blocks=True)
        wait_for_tip(connection, utxoBlock.hash)

        # Make sure serialization/deserialization works as expected
        # Create dsdetected message. The content is not important here.
        dsdMessage = msg_dsdetected(blocksDetails=[
            BlockDetails(
                [CBlockHeader(utxoBlock),
                 CBlockHeader(initialBlock)],
                DSMerkleProof(1, utxoTx, utxoBlock.hashMerkleRoot,
                              [MerkleProofNode(utxoBlock.vtx[0].sha256)]))
        ])
        dsdBytes = dsdMessage.serialize()
        dsdMessageDeserialized = msg_dsdetected()
        dsdMessageDeserialized.deserialize(BytesIO(dsdBytes))
        assert_equal(str(dsdMessage), str(dsdMessageDeserialized))

        # Send a message containing random bytes. Webhook should not receive the notification.
        peer.send_and_ping(fake_msg_dsdetected())
        assert_equal(self.get_JSON_notification(), None)

        # Create two blocks with transactions spending the same utxo
        blockA, _ = make_block(connection, parent_block=utxoBlock)
        blockB, _ = make_block(connection, parent_block=utxoBlock)
        blockF, _ = make_block(connection, parent_block=utxoBlock)
        txA = create_tx(utxoBlock.vtx[1], 0, int(0.8 * COIN))
        txB = create_tx(utxoBlock.vtx[1], 0, int(0.9 * COIN))
        txF = create_tx(utxoBlock.vtx[1], 0, int(0.7 * COIN))
        txA.rehash()
        txB.rehash()
        txF.rehash()
        blockA.vtx.append(txA)
        blockB.vtx.append(txB)
        blockF.vtx.append(txF)
        blockA.hashMerkleRoot = blockA.calc_merkle_root()
        blockB.hashMerkleRoot = blockB.calc_merkle_root()
        blockF.hashMerkleRoot = blockF.calc_merkle_root()
        blockA.calc_sha256()
        blockB.calc_sha256()
        blockF.calc_sha256()
        blockA.solve()
        blockB.solve()
        blockF.solve()

        start_banscore = node.getpeerinfo()[0]['banscore']

        # Webhook should not receive the notification if we send dsdetected message with only one block detail.
        dsdMessage = msg_dsdetected(blocksDetails=[
            BlockDetails(
                [CBlockHeader(blockA)],
                DSMerkleProof(1, txA, blockA.hashMerkleRoot,
                              [MerkleProofNode(blockA.vtx[0].sha256)]))
        ])
        peer.send_and_ping(dsdMessage)
        assert_equal(self.get_JSON_notification(), None)

        # Webhook should not receive the notification if we send dsdetected message with two block details and one is containing no headers.
        dsdMessage = msg_dsdetected(blocksDetails=[
            BlockDetails(
                [CBlockHeader(blockA)],
                DSMerkleProof(1, txA, blockA.hashMerkleRoot,
                              [MerkleProofNode(blockA.vtx[0].sha256)])),
            BlockDetails(
                [],
                DSMerkleProof(1, txB, blockB.hashMerkleRoot,
                              [MerkleProofNode(blockB.vtx[0].sha256)]))
        ])
        peer.send_and_ping(dsdMessage)
        assert_equal(self.get_JSON_notification(), None)

        # Webhook should not receive the notification if we send dsdetected message where last headers in block details do not have a common previous block hash.
        dsdMessage = msg_dsdetected(blocksDetails=[
            BlockDetails(
                [CBlockHeader(blockA)],
                DSMerkleProof(1, txA, blockA.hashMerkleRoot,
                              [MerkleProofNode(blockA.vtx[0].sha256)])),
            BlockDetails(
                [CBlockHeader(utxoBlock)],
                DSMerkleProof(1, txB, blockB.hashMerkleRoot,
                              [MerkleProofNode(blockB.vtx[0].sha256)]))
        ])
        peer.send_and_ping(dsdMessage)
        assert_equal(self.get_JSON_notification(), None)

        # Webhook should not receive the notification if we send dsdetected message where block details does not have headers in proper order.
        dsdMessage = msg_dsdetected(blocksDetails=[
            BlockDetails(
                [CBlockHeader(blockA)],
                DSMerkleProof(1, txA, blockA.hashMerkleRoot,
                              [MerkleProofNode(blockA.vtx[0].sha256)])),
            BlockDetails(
                [CBlockHeader(utxoBlock),
                 CBlockHeader(blockB)],
                DSMerkleProof(1, txB, blockB.hashMerkleRoot,
                              [MerkleProofNode(blockB.vtx[0].sha256)]))
        ])
        peer.send_and_ping(dsdMessage)
        assert_equal(self.get_JSON_notification(), None)

        # Webhook should not receive the notification if we send dsdetected message with the empty merkle proof.
        dsdMessage = msg_dsdetected(blocksDetails=[
            BlockDetails(
                [CBlockHeader(blockA)],
                DSMerkleProof(1, txA, blockA.hashMerkleRoot,
                              [MerkleProofNode(blockA.vtx[0].sha256)])),
            BlockDetails([CBlockHeader(blockB)], DSMerkleProof())
        ])
        peer.send_and_ping(dsdMessage)
        assert_equal(self.get_JSON_notification(), None)

        # Webhook should not receive the notification if we send dsdetected message with the wrong index in the merkle proof (merkle root validation should fail)
        dsdMessage = msg_dsdetected(blocksDetails=[
            BlockDetails(
                [CBlockHeader(blockA)],
                DSMerkleProof(1, txA, blockA.hashMerkleRoot,
                              [MerkleProofNode(blockA.vtx[0].sha256)])),
            BlockDetails(
                [CBlockHeader(blockB)],
                DSMerkleProof(0, txB, blockB.hashMerkleRoot,
                              [MerkleProofNode(blockB.vtx[0].sha256)]))
        ])
        peer.send_and_ping(dsdMessage)
        assert_equal(self.get_JSON_notification(), None)

        # Webhook should not receive the notification if we send dsdetected message with the wrong transaction in the merkle proof (merkle root validation should fail)
        dsdMessage = msg_dsdetected(blocksDetails=[
            BlockDetails(
                [CBlockHeader(blockA)],
                DSMerkleProof(1, txA, blockA.hashMerkleRoot,
                              [MerkleProofNode(blockA.vtx[0].sha256)])),
            BlockDetails(
                [CBlockHeader(blockB)],
                DSMerkleProof(1, txA, blockB.hashMerkleRoot,
                              [MerkleProofNode(blockB.vtx[0].sha256)]))
        ])
        peer.send_and_ping(dsdMessage)
        assert_equal(self.get_JSON_notification(), None)

        # Webhook should not receive the notification if we send dsdetected message with the wrong merkle root (merkle root validation should fail)
        dsdMessage = msg_dsdetected(blocksDetails=[
            BlockDetails(
                [CBlockHeader(blockA)],
                DSMerkleProof(1, txA, blockA.hashMerkleRoot,
                              [MerkleProofNode(blockA.vtx[0].sha256)])),
            BlockDetails(
                [CBlockHeader(blockB)],
                DSMerkleProof(1, txB, blockA.hashMerkleRoot,
                              [MerkleProofNode(blockB.vtx[0].sha256)]))
        ])
        peer.send_and_ping(dsdMessage)
        assert_equal(self.get_JSON_notification(), None)

        # Webhook should not receive the notification if we send dsdetected message with the wrong merkle proof (merkle root validation should fail)
        dsdMessage = msg_dsdetected(blocksDetails=[
            BlockDetails(
                [CBlockHeader(blockA)],
                DSMerkleProof(1, txA, blockA.hashMerkleRoot,
                              [MerkleProofNode(blockA.vtx[0].sha256)])),
            BlockDetails(
                [CBlockHeader(blockB)],
                DSMerkleProof(1, txB, blockB.hashMerkleRoot,
                              [MerkleProofNode(blockA.hashMerkleRoot)]))
        ])
        peer.send_and_ping(dsdMessage)
        assert_equal(self.get_JSON_notification(), None)

        # Webhook should not receive the notification if we send dsdetected message with the merkle proof having an additional unexpected node (merkle root validation should fail)
        dsdMessage = msg_dsdetected(blocksDetails=[
            BlockDetails(
                [CBlockHeader(blockA)],
                DSMerkleProof(1, txA, blockA.hashMerkleRoot,
                              [MerkleProofNode(blockA.vtx[0].sha256)])),
            BlockDetails([CBlockHeader(blockB)],
                         DSMerkleProof(1, txB, blockB.hashMerkleRoot, [
                             MerkleProofNode(blockB.vtx[0].sha256),
                             MerkleProofNode(blockA.hashMerkleRoot)
                         ]))
        ])
        peer.send_and_ping(dsdMessage)
        assert_equal(self.get_JSON_notification(), None)

        # Webhook should not receive the notification if we send dsdetected message with the valid proof, but transaction is a coinbase transaction
        dsdMessage = msg_dsdetected(blocksDetails=[
            BlockDetails(
                [CBlockHeader(blockA)],
                DSMerkleProof(1, txA, blockA.hashMerkleRoot,
                              [MerkleProofNode(blockA.vtx[0].sha256)])),
            BlockDetails(
                [CBlockHeader(blockB)],
                DSMerkleProof(0, blockB.vtx[0], blockB.hashMerkleRoot,
                              [MerkleProofNode(blockB.vtx[1].sha256)]))
        ])
        peer.send_and_ping(dsdMessage)
        assert_equal(self.get_JSON_notification(), None)

        # Webhook should not receive the notification if we send dsdetected message with transactions that are not double spending
        # Create a block similar as before, but with a transaction spending a different utxo
        blockC, _ = make_block(connection, parent_block=utxoBlock)
        txC = create_tx(utxoBlock.vtx[1], 1, int(0.7 * COIN))
        blockC.vtx.append(txC)
        blockC.hashMerkleRoot = blockC.calc_merkle_root()
        blockC.solve()
        dsdMessage = msg_dsdetected(blocksDetails=[
            BlockDetails(
                [CBlockHeader(blockA)],
                DSMerkleProof(1, txA, blockA.hashMerkleRoot,
                              [MerkleProofNode(blockA.vtx[0].sha256)])),
            BlockDetails(
                [CBlockHeader(blockC)],
                DSMerkleProof(1, txC, blockC.hashMerkleRoot,
                              [MerkleProofNode(blockC.vtx[0].sha256)]))
        ])
        peer.send_and_ping(dsdMessage)
        assert_equal(self.get_JSON_notification(), None)

        # Webhook should not receive the notification if the two double spending transactions are actually the same transaction (having same txid)
        # Create a block similar as before, but with a transaction spending a different utxo
        blockD, _ = make_block(connection, parent_block=utxoBlock)
        blockD.vtx.append(txA)
        blockD.hashMerkleRoot = blockD.calc_merkle_root()
        blockD.solve()
        dsdMessage = msg_dsdetected(blocksDetails=[
            BlockDetails(
                [CBlockHeader(blockA)],
                DSMerkleProof(1, txA, blockA.hashMerkleRoot,
                              [MerkleProofNode(blockA.vtx[0].sha256)])),
            BlockDetails(
                [CBlockHeader(blockD)],
                DSMerkleProof(1, txA, blockD.hashMerkleRoot,
                              [MerkleProofNode(blockD.vtx[0].sha256)]))
        ])
        peer.send_and_ping(dsdMessage)
        assert_equal(self.get_JSON_notification(), None)

        # Webhook should not receive the notification if header cannot pow
        # note hat pow is so easy in regtest that nonce can often be hence we have to select the nonce carefully
        blockE, _ = make_block(connection, parent_block=utxoBlock)
        blockE.vtx.append(txB)
        blockE.hashMerkleRoot = blockE.calc_merkle_root()
        nonce = blockE.nNonce
        while True:
            blockE.solve()
            if blockE.nNonce > nonce:
                blockE.nNonce = nonce
                break
            nonce += 1
            blockE.nNonce = nonce

        dsdMessage = msg_dsdetected(blocksDetails=[
            BlockDetails(
                [CBlockHeader(blockA)],
                DSMerkleProof(1, txA, blockA.hashMerkleRoot,
                              [MerkleProofNode(blockA.vtx[0].sha256)])),
            BlockDetails(
                [CBlockHeader(blockE)],
                DSMerkleProof(1, txB, blockE.hashMerkleRoot,
                              [MerkleProofNode(blockE.vtx[0].sha256)]))
        ])
        peer.send_and_ping(dsdMessage)
        assert_equal(self.get_JSON_notification(), None)

        end_banscore = node.getpeerinfo()[0]['banscore']
        assert ((end_banscore - start_banscore) / 10 == 13
                )  # because we have 13 negative tests so far

        # Finally, webhook should receive the notification if we send a proper dsdetected message
        dsdMessage = msg_dsdetected(blocksDetails=[
            BlockDetails(
                [CBlockHeader(blockA)],
                DSMerkleProof(1, txA, blockA.hashMerkleRoot,
                              [MerkleProofNode(blockA.vtx[0].sha256)])),
            BlockDetails(
                [CBlockHeader(blockB)],
                DSMerkleProof(1, txB, blockB.hashMerkleRoot,
                              [MerkleProofNode(blockB.vtx[0].sha256)]))
        ])
        peer.send_and_ping(dsdMessage)
        json_notification = self.get_JSON_notification()
        # remove diverentBlockHash so we can compare with the ds-message
        assert (json_notification != None)
        for e in json_notification['blocks']:
            del e['divergentBlockHash']
        assert_equal(str(dsdMessage),
                     str(msg_dsdetected(json_notification=json_notification)))

        # Repeat previous test but change the order of the BlockDetails, the node should identify this as a duplicate
        dsdMessage = msg_dsdetected(blocksDetails=[
            BlockDetails(
                [CBlockHeader(blockB)],
                DSMerkleProof(1, txB, blockB.hashMerkleRoot,
                              [MerkleProofNode(blockB.vtx[0].sha256)])),
            BlockDetails(
                [CBlockHeader(blockA)],
                DSMerkleProof(1, txA, blockA.hashMerkleRoot,
                              [MerkleProofNode(blockA.vtx[0].sha256)]))
        ])
        peer.send_and_ping(dsdMessage)
        assert_equal(self.get_JSON_notification(), None)

        # repeat previous test but generate many blocks in the node to age the notificatoin message.
        # very old notification messages shall be ignored. We use the same thresholds as safe mode.
        # We will hardcode this threshold for now until branch we depend on is merged
        node.generate(289)
        dsdMessage = msg_dsdetected(blocksDetails=[
            BlockDetails(
                [CBlockHeader(blockA)],
                DSMerkleProof(1, txA, blockA.hashMerkleRoot,
                              [MerkleProofNode(blockA.vtx[0].sha256)])),
            BlockDetails(
                [CBlockHeader(blockF)],
                DSMerkleProof(1, txF, blockF.hashMerkleRoot,
                              [MerkleProofNode(blockF.vtx[0].sha256)]))
        ])
        peer.send_and_ping(dsdMessage)
        assert_equal(self.get_JSON_notification(), None)

        # Create number of random valid block trees and send dsdetected P2P message for each
        maxNumberOfBranches = 10
        maxNumberOfBlocksPerBranch = 30
        for _ in range(10):
            blockTree = self.createRandomBlockTree(maxNumberOfBranches,
                                                   maxNumberOfBlocksPerBranch,
                                                   utxoBlock,
                                                   [utxoBlock.vtx[1]])
            dsdMessage = self.createDsDetectedMessageFromBlockTree(blockTree)
            peer.send_and_ping(dsdMessage)
            # Notification should be received as generated dsdetected message is valid
            json_notification = self.get_JSON_notification()
            # remove diverentBlockHash so we can compare with the ds-message
            assert (json_notification != None)
            for e in json_notification['blocks']:
                del e['divergentBlockHash']
            assert_equal(
                str(dsdMessage),
                str(msg_dsdetected(json_notification=json_notification)))

        self.stop_webhook_server()
예제 #8
0
    def run_test(self):
        for node in self.nodes:
            self.consolidation_factor = int(
                node.getnetworkinfo()['minconsolidationfactor'])
            self.minConfirmations = int(
                node.getnetworkinfo()['minconfconsolidationinput'])
            self.log.info("consolidation factor: {}".format(
                self.consolidation_factor))
            self.log.info("minimum input confirmations: {}".format(
                self.minConfirmations))

            # Disconnect nodes before each generate RPC. On a busy environment generate
            # RPC might not create the provided number of blocks. While nodes are communicating
            # P2P messages can cause generateBlocks function to skip a block. Check the comment
            # in generateBlocks function for details.
            disconnect_nodes_bi(self.nodes, 0, 1)
            node.generate(300)
            connect_nodes_bi(self.nodes, 0, 1)

            # test ratio between size of input script and size of output script
            tx_hex = self.create_and_sign_tx(node, 1, min_confirmations=1)
            tx = FromHex(CTransaction(), tx_hex)
            tx.rehash()
            sin = len(getInputScriptPubKey(node, tx.vin[0], 0))
            sout = len(tx.vout[0].scriptPubKey)

            enough_inputs = sout * self.consolidation_factor // sin
            enough_inputs = max(enough_inputs, 2)
            enough_confirmations = self.minConfirmations

            # FAILING CONDITION: input_sizes <= consolidation_factor * output_size
            # We assume scriptSig ~ 4 * scriptPubKey
            tx_hex = self.create_and_sign_tx(
                node,
                in_count=enough_inputs - 1,
                min_confirmations=enough_confirmations)
            assert_raises_rpc_error(-26, "66: insufficient priority",
                                    node.sendrawtransaction, tx_hex)
            self.log.info("test 1: PASS")

            # FAILING CONDITION: not enough input confirmations
            tx_hex = self.create_and_sign_tx(
                node,
                in_count=enough_inputs,
                min_confirmations=enough_confirmations - 1)
            assert_raises_rpc_error(-26, "66: insufficient priority",
                                    node.sendrawtransaction, tx_hex)
            self.log.info("test 2: PASS")

            # ALL CONDITIONS MET: must succeed
            tx_hex = self.create_and_sign_tx(
                node,
                in_count=enough_inputs,
                min_confirmations=enough_confirmations)
            txid = node.sendrawtransaction(tx_hex)
            node.generate(1)
            tx = node.getrawtransaction(txid, 1)
            confirmations = tx.get('confirmations', 0)
            assert_equal(confirmations, 1)
            self.log.info("test 3: PASS")
            # Blocks must be synced because we do not want to start generating new blocks on node1 in the next loop iteration
            # before node1 has received all blocks generated on node0 and all pending P2P block requests have completed.
            sync_blocks(self.nodes)

        # Verify deprecated -minconsolidationinputmaturity is an alias to -minconfconsolidationinput
        self.log.info("Restarting nodes to test config options...")
        self.stop_nodes()
        self.extra_args[0].append("-minconsolidationinputmaturity=99")
        self.start_nodes(self.extra_args)
        sync_blocks(self.nodes)
        assert_equal(
            99, self.nodes[0].getnetworkinfo()['minconfconsolidationinput'])
        assert_equal(
            99,
            self.nodes[0].getnetworkinfo()['minconsolidationinputmaturity'])

        # Verify deprecation warning is logged
        self.stop_nodes()
        deprecation_log = False
        for line in open(
                glob.glob(self.options.tmpdir + "/node0" +
                          "/regtest/bitcoind.log")[0]):
            if f"Option -minconsolidationinputmaturity is deprecated, use -minconfconsolidationinput instead" in line:
                deprecation_log = True
                #self.log.info("Found line: %s", line.strip())
                break
        assert (deprecation_log)

        # Verify init error when deprecated and new option are used together
        self.extra_args[0].append("-minconfconsolidationinput=99")
        self.assert_start_raises_init_error(
            0, self.extra_args[0],
            'Cannot use both -minconfconsolidationinput and -minconsolidationinputmaturity (deprecated) at the same time'
        )
예제 #9
0
def getInputScriptPubKey(node, input, index):
    txid = hashToHex(input.prevout.hash)
    raw = node.getrawtransaction(txid)
    tx = FromHex(CTransaction(), raw)
    tx.rehash()
    return tx.vout[index].scriptPubKey
    def CheckForDoubleSpends(self, nodes):
        spent_inputs = []
        seen_transactions = []
        ds_counter = 0
        for node in nodes:
            for height in range(node.getblockcount() + 1):
                blockhash = node.getblockhash(height)
                block = node.getblock(blockhash, 2)
                blockHex = node.getblock(blockhash, False)
                for txraw in block['tx'][1:]:  # exclude coinbase
                    # skip the identical transactions in the two chains, they are no double spends
                    if txraw['txid'] in seen_transactions:
                        continue
                    else:
                        seen_transactions.append(txraw['txid'])
                    for i in txraw['vin']:
                        utxoA = (i['txid'], i['vout'])
                        blockA = FromHex(CBlock(), blockHex)
                        txA = FromHex(CTransaction(), txraw['hex'])
                        foundB = [
                            j for j in spent_inputs if j['utxo'] == utxoA
                        ]
                        if foundB:
                            ds_counter += 1
                            foundB = foundB[0]
                            blockB = foundB['block']
                            txB = foundB['tx']
                            txA.rehash()

                            txB.rehash()

                            blockA.vtx[0].rehash()
                            blockB.vtx[0].rehash()
                            sha256_A = blockA.vtx[0].sha256
                            sha256_B = blockB.vtx[0].sha256

                            dsdMessage = msg_dsdetected(blocksDetails=[
                                BlockDetails([CBlockHeader(blockA)],
                                             DSMerkleProof(
                                                 1, txA, blockA.hashMerkleRoot,
                                                 [MerkleProofNode(sha256_A)])),
                                BlockDetails([CBlockHeader(blockB)],
                                             DSMerkleProof(
                                                 1, txB, blockB.hashMerkleRoot,
                                                 [MerkleProofNode(sha256_B)]))
                            ])
                            self.message = dsdMessage

                            dsdBytes = dsdMessage.serialize()
                            dsdMessageDeserialized = msg_dsdetected()
                            dsdMessageDeserialized.deserialize(
                                BytesIO(dsdBytes))
                            assert_equal(str(dsdMessage),
                                         str(dsdMessageDeserialized))

                            break
                        else:
                            spent_inputs.append({
                                'txid': txraw['txid'],
                                'tx': txA,
                                'utxo': utxoA,
                                'block': blockA
                            })

        return ds_counter