예제 #1
0
    def generate_and_send_txchains_n(self, conn, num_of_chains, chain_length, spend, locking_script, money_to_spend=2000000, vout_size=10, timeout=60):
        # Create and send txs. In this case there will be num_txs_to_create txs of chain length equal 1.
        txchains = self.get_txchains_n(num_of_chains, chain_length, spend, CScript(), locking_script, money_to_spend, vout_size)
        for tx in range(len(txchains)):
            conn.send_message(msg_tx(txchains[tx]))
        # Check if the validation queues are empty.
        wait_for_ptv_completion(conn, num_of_chains*chain_length, timeout=timeout)

        return txchains
예제 #2
0
 def run_scenario1(self, conn, num_of_chains, chain_length, spend, timeout):
     # Create and send tx chains.
     txchains = self.get_txchains_n(num_of_chains, chain_length, spend)
     for tx in range(len(txchains)):
         conn.send_message(msg_tx(txchains[tx]))
     # Check if the validation queues are empty.
     wait_for_ptv_completion(conn,
                             num_of_chains * chain_length,
                             timeout=timeout)
     # Check if required transactions are accepted by the mempool.
     self.check_mempool(conn.rpc, txchains, timeout)
예제 #3
0
 def send_txs(self,
              rpcsend,
              conn,
              txs,
              exp_mempool_size,
              timeout=300,
              check_interval=0.1):
     conn = None if rpcsend is not None else conn
     if conn is not None:
         req_start_time = time.time()
         for tx in txs:
             conn.send_message(msg_tx(tx))
         wait_for_ptv_completion(conn,
                                 exp_mempool_size,
                                 timeout=timeout,
                                 check_interval=check_interval)
         elapsed = time.time() - req_start_time
     elif rpcsend is not None:
         elapsed = self.rpc_send_txs(rpcsend, txs)
     else:
         raise Exception("Unspecified interface!")
     return elapsed
예제 #4
0
 def run_scenario2(self,
                   conn,
                   num_of_chains,
                   chain_length,
                   spend,
                   allowhighfees=False,
                   dontcheckfee=False,
                   timeout=60):
     # Create tx chains.
     txchains = self.run_scenario1(conn, num_of_chains, chain_length, spend,
                                   allowhighfees, dontcheckfee, timeout)
     wait_for_ptv_completion(conn, len(txchains), timeout=timeout)
     # Check if txchains txns are in the mempool.
     self.check_mempool(conn.rpc, set(txchains), timeout=60)
     # Check if there is only num_of_chains * chain_length txns in the mempool.
     assert_equal(conn.rpc.getmempoolinfo()['size'], len(txchains))
     # Generate a single block.
     mined_block1 = conn.rpc.generate(1)
     # Mempool should be empty, all txns in the block.
     assert_equal(conn.rpc.getmempoolinfo()['size'], 0)
     # Use invalidateblock to re-org back; all transactions should
     # end up unconfirmed and back in the mempool.
     conn.rpc.invalidateblock(mined_block1[0])
     # There should be exactly num_of_chains * chain_length txns in the mempool.
     assert_equal(conn.rpc.getmempoolinfo()['size'], len(txchains))
     self.check_mempool(conn.rpc, set(txchains))
     # Generate another block, they should all get mined.
     mined_block2 = conn.rpc.generate(1)
     # Mempool should be empty, all txns confirmed.
     assert_equal(conn.rpc.getmempoolinfo()['size'], 0)
     # Check if txchains txns are included in the block.
     mined_block2_details = conn.rpc.getblock(mined_block2[0])
     assert_equal(mined_block2_details['num_tx'],
                  len(txchains) + 1)  # +1 for coinbase txn.
     assert_equal(
         len(
             set(mined_block2_details['tx']).intersection(
                 t.hash for t in txchains)), len(txchains))
예제 #5
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))

        # Create a new block
        block(0, coinbase_pubkey=self.coinbase_pubkey)
        self.chain.save_spendable_output()
        yield self.accepted()

        # Now we need that block to mature so we can spend the coinbase.
        # Also, move block height on beyond Genesis activation.
        test = TestInstance(sync_every_block=False)
        for i in range(600):
            block(5000 + i, coinbase_pubkey=self.coinbase_pubkey)
            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())

        self.stop_node(0)

        #
        # Test Case 1 (TC1).
        #
        # - 10 standard txs used
        # - 1 peer connected to node0
        # All txs emplaced initially in the standard validation queue are processed and accepted by the mempool.
        # - None txn is rejected with a reason 'too-long-validation-time' (not moved into the non-std queue).
        #
        # The number of txs used in the test case.
        tc1_txs_num = 10
        # Select funding transactions to use:
        # - tc1_txs_num funding transactions are needed in this test case.
        spend_txs = out[0:tc1_txs_num]
        args = [
            '-checkmempool=0',
            '-persistmempool=0',
            '-maxstdtxvalidationduration=500',  # increasing max validation time ensures that timeout doesn't occur for standard txns, even on slower machines and on debug build
            '-maxnonstdtxnsperthreadratio=0'
        ]  # setting it to zero ensures that non-standard txs won't be processed (if there are any queued).
        with self.run_node_with_connections(
                'TC1: {} txs detected as std and then accepted.'.format(
                    tc1_txs_num),
                0,
                args + self.default_args,
                number_of_connections=1) as (conn, ):
            # Run test case.
            std_txs = self.run_scenario1(conn, spend_txs, tc1_txs_num,
                                         self.locking_script_1)
            # Check if required transactions are accepted by the mempool.
            self.check_mempool(conn.rpc, std_txs, timeout=30)
            assert_equal(conn.rpc.getmempoolinfo()['size'], tc1_txs_num)

        #
        # Test Case 2 (TC2).
        #
        # - 10 non-standard txs (with a simple locking script) used.
        # - 1 peer connected to node0.
        # The test case creates rejected txns with a reason 'too-long-validation-time' for all txs initially emplaced into the standard queue.
        # - those rejects are not taken into account to create reject messages (see explanation - point 6)
        # All txns are then forwarded to the non-standard validation queue where the validation timeout is longer (sufficient).
        #
        # The number of txs used in the test case.
        tc2_txs_num = 10
        # Select funding transactions to use:
        # - one funding transaction is needed in this test case.
        spend_txs = out[tc1_txs_num:tc1_txs_num + 1]
        args = ['-checkmempool=0', '-persistmempool=0']
        with self.run_node_with_connections(
                'TC2: {} txs with small bignums detected as non-std txs and then finally accepted.'
                .format(tc2_txs_num),
                0,
                args + self.default_args,
                number_of_connections=1) as (conn, ):
            # Run test case.
            nonstd_txs, rejected_txs = self.run_scenario2(
                conn, spend_txs, tc2_txs_num, self.locking_script_2)
            wait_for_ptv_completion(conn, len(nonstd_txs))
            # No transactions should be rejected
            assert_equal(len(rejected_txs), 0)
            # Check if required transactions are accepted by the mempool.
            self.check_mempool(conn.rpc, nonstd_txs, timeout=30)
            assert_equal(conn.rpc.getmempoolinfo()['size'], tc2_txs_num)

        #
        # Test Case 3 (TC3).
        #
        # - 10 non-standard txs (with a complex locking script) used.
        # - 1 peer connected to node0
        # The test case creates rejected txns with a reason 'too-long-validation-time' for all txs initially emplaced into the standard queue.
        # - those rejects are not taken into account to create reject messages (see explanation - point 6)
        # All txns are then forwarded to the non-standard validation queue where the validation timeout is longer (sufficient).
        #
        # The number of txs used in the test case.
        tc3_txs_num = 10
        # Select funding transactions to use:
        # - one funding transaction is needed in this test case.
        spend_txs = out[tc1_txs_num + 1:tc1_txs_num + 2]
        args = [
            '-checkmempool=0',
            '-persistmempool=0',
            '-maxnonstdtxvalidationduration=100000',  # On slow/busy machine txn validation times have to be high
            '-maxtxnvalidatorasynctasksrunduration=100001',  # This needs to mehigher then maxnonstdtxvalidationduration
            '-maxscriptsizepolicy=0',
            '-maxscriptnumlengthpolicy=250000'
        ]
        with self.run_node_with_connections(
                'TC3: {} txs with large bignums detected as non-std txs and then finally accepted.'
                .format(tc3_txs_num),
                0,
                args + self.default_args,
                number_of_connections=1) as (conn, ):
            # Run test case.
            nonstd_txs, rejected_txs = self.run_scenario2(
                conn, spend_txs, tc3_txs_num, self.locking_script_3)
            wait_for_ptv_completion(conn, len(nonstd_txs))
            # No transactions should be rejected
            assert_equal(len(rejected_txs), 0)
            # Check if required transactions are accepted by the mempool.
            self.check_mempool(conn.rpc, nonstd_txs, timeout=30)
            assert_equal(conn.rpc.getmempoolinfo()['size'], tc3_txs_num)

        #
        # Test Case 4 (TC4).
        #
        # - 10 non-standard txs (with a complex locking script) used.
        # - 1 peer connected to node0
        # The test case creates rejected txns with a reason 'too-long-validation-time' for all txs initially emplaced into the standard queue.
        # - those rejects are not taken into account to create reject messages (see explanation - point 6)
        # All txns are then forwarded to the non-standard validation queue.
        # - due to insufficient timeout config all txs are rejected again with 'too-long-validation-time' reject reason.
        # - reject messages are created for each and every txn.
        #
        # The number of txs used in the test case.
        tc4_txs_num = 10
        # Select funding transactions to use:
        # - one funding transaction is needed in this test case.
        spend_txs = out[tc1_txs_num + 2:tc1_txs_num + 3]
        args = [
            '-checkmempool=0', '-persistmempool=0', '-maxscriptsizepolicy=0',
            '-maxscriptnumlengthpolicy=250000'
        ]
        with self.run_node_with_connections(
                'TC4: {} txs with large bignums detected as non-std txs and then finally rejected.'
                .format(tc4_txs_num),
                0,
                args + self.default_args,
                number_of_connections=1) as (conn, ):
            # Run test case.
            nonstd_txs, rejected_txs = self.run_scenario2(
                conn, spend_txs, tc4_txs_num, self.locking_script_3)
            wait_for_ptv_completion(conn, 0)
            # Check rejected transactions.
            self.check_rejected(rejected_txs, nonstd_txs)
            assert_equal(len(rejected_txs), tc4_txs_num)
            # The mempool should be empty at this stage.
            assert_equal(conn.rpc.getmempoolinfo()['size'], 0)

        #
        # Test Case 5 (TC5).
        #
        # - 100 standard txs used.
        # - 10 non-standard (with a simple locking script) txs used.
        # - 1 peer connected to node0.
        # This test case is a combination of TC1 & TC2
        # - the set of std and non-std txs is shuffled before sending it to the node.
        #
        # The number of txs used in the test case.
        tc5_1_txs_num = 100
        tc5_2_txs_num = 10
        # Select funding transactions to use:
        # - tc5_1_txs_num+1 funding transactions are needed in this test case.
        spend_txs = out[tc1_txs_num + 3:tc1_txs_num + 3 + tc5_1_txs_num]
        spend_txs2 = out[tc1_txs_num + 3 + tc5_1_txs_num:tc1_txs_num + 4 +
                         tc5_1_txs_num]
        args = ['-checkmempool=0', '-persistmempool=0']
        with self.run_node_with_connections(
                'TC5: The total of {} std and nonstd txs processed and accepted.'
                .format(tc5_1_txs_num + tc5_2_txs_num),
                0,
                args + self.default_args,
                number_of_connections=1) as (conn, ):
            # Run test case.
            std_txs = self.get_txchains_n(tc5_1_txs_num, 1, spend_txs,
                                          CScript(), self.locking_script_1,
                                          2000000, 10)
            std_and_nonstd_txs, rejected_txs = self.run_scenario2(
                conn,
                spend_txs2,
                tc5_2_txs_num,
                self.locking_script_2,
                std_txs,
                shuffle_txs=True)
            wait_for_ptv_completion(conn, len(std_and_nonstd_txs))
            # Check if required transactions are accepted by the mempool.
            self.check_mempool(conn.rpc, std_and_nonstd_txs, timeout=30)
            assert_equal(conn.rpc.getmempoolinfo()['size'],
                         tc5_1_txs_num + tc5_2_txs_num)
예제 #6
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))

        # Create a new block
        block(0, coinbase_pubkey=self.coinbase_pubkey)
        self.chain.save_spendable_output()
        yield self.accepted()

        # Now we need that block to mature so we can spend the coinbase.
        # Also, move block height on beyond Genesis activation.
        test = TestInstance(sync_every_block=False)
        for i in range(600):
            block(5000 + i, coinbase_pubkey=self.coinbase_pubkey)
            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())

        self.stop_node(0)

        #
        # Test Case 1 (TC1).
        #
        # - 5000 standard txs used (100 txn chains, each of length 50)
        # - 1 peer connected to node0
        #
        # The number of txs used in the test case.
        tc1_txchains_num = 100
        tc1_tx_chain_length = 50
        # Select funding transactions to use:
        # - tc1_txchains_num funding transactions are needed in this test case.
        spend_txs = self.get_front_slice(out, tc1_txchains_num)
        args = [
            '-checkmempool=0', '-persistmempool=0', '-limitancestorcount=50',
            '-txnvalidationasynchrunfreq=100', '-numstdtxvalidationthreads=6',
            '-numnonstdtxvalidationthreads=2'
        ]
        with self.run_node_with_connections(
                'TC1: {} std txn chains used, each of length {}.'.format(
                    tc1_txchains_num, tc1_tx_chain_length),
                0,
                args + self.default_args,
                number_of_connections=1) as (conn, ):
            # Run test case.
            std_txs = self.run_scenario1(conn, spend_txs, tc1_txchains_num,
                                         tc1_tx_chain_length,
                                         self.locking_script_1, 5000000000, 1)
            wait_for_ptv_completion(conn,
                                    tc1_txchains_num * tc1_tx_chain_length)
            # Check if required transactions are accepted by the mempool.
            self.check_mempool(conn.rpc, std_txs, timeout=30)
            assert_equal(conn.rpc.getmempoolinfo()['size'],
                         tc1_txchains_num * tc1_tx_chain_length)

        #
        # Test Case 2 (TC2).
        #
        # - 2400 non-standard txs (with a simple locking script) used
        # - 1 peer connected to node0
        #
        # The number of txs used in the test case.
        tc2_txs_num = 2400
        # Select funding transactions to use:
        # - one funding transaction is needed in this test case.
        spend_txs = self.get_front_slice(out, 1)
        args = ['-checkmempool=0', '-persistmempool=0']
        with self.run_node_with_connections(
                'TC2: {} non-std txs used.'.format(tc2_txs_num),
                0,
                args + self.default_args,
                number_of_connections=1) as (conn, ):
            # Run test case.
            nonstd_txs, rejected_txs = self.run_scenario2(
                conn, spend_txs, tc2_txs_num, self.locking_script_2)
            wait_for_ptv_completion(conn, tc2_txs_num)
            # Check if required transactions are accepted by the mempool.
            self.check_mempool(conn.rpc, nonstd_txs, timeout=30)
            assert_equal(len(rejected_txs), 0)
            assert_equal(conn.rpc.getmempoolinfo()['size'], tc2_txs_num)

        #
        # Test Case 3 (TC3).
        #
        # - 2400 valid non-standard txs (with a simple locking script) used
        #   - 100 double spend txs used
        # - 1 peer connected to node0
        # From the double spends set only 1 txn is accepted by the mempool.
        #
        # The number of txs used in the test case.
        tc3_txs_num = 2400
        ds_txs_num = 100
        # Select funding transactions to use:
        # - one funding transaction is needed in this test case.
        spend_txs = self.get_front_slice(out, 1)
        args = ['-checkmempool=0', '-persistmempool=0']
        with self.run_node_with_connections(
                'TC3: {} non-std txs ({} double spends) used.'.format(
                    tc3_txs_num, ds_txs_num),
                0,
                args + self.default_args,
                number_of_connections=1) as (conn, ):
            # Run test case.
            nonstd_txs, ds_txs, _ = self.run_scenario2(conn, spend_txs,
                                                       tc3_txs_num,
                                                       self.locking_script_2,
                                                       ds_txs_num)
            wait_for_ptv_completion(conn, len(nonstd_txs) + 1)
            # All txs from the nonstd_txs result set should be accepted
            self.check_mempool_with_subset(conn.rpc, nonstd_txs, timeout=30)
            # There is one more transaction in the mempool, which is a random txn from the ds_txs set
            assert_equal(conn.rpc.getmempoolinfo()['size'],
                         len(nonstd_txs) + 1)
            # Only one txn is allowed to be in the mempool from the given ds set.
            assert_equal(
                len(self.check_intersec_with_mempool(conn.rpc, ds_txs)), 1)

        #
        # Test Case 4 (TC4).
        #
        # - 10 standard txs used (as additional input set)
        # - 2400 non-standard (with a simple locking script) txs used
        #   - 100 double spend txs used
        # - 1 peer connected to node0
        # All input txs are randomly suffled before sending.
        #
        # The number of txs used in the test case.
        tc4_1_txs_num = 10
        tc4_2_txs_num = 2400
        ds_txs_num = 100
        # Select funding transactions to use:
        # - tc4_1_txs_num+1 funding transactions are needed in this test case.
        spend_txs = self.get_front_slice(out, tc4_1_txs_num)
        spend_txs2 = self.get_front_slice(out, 1)
        args = ['-checkmempool=0', '-persistmempool=0']
        with self.run_node_with_connections(
                'TC4: {} std, {} nonstd txs ({} double spends) used (shuffled set).'
                .format(tc4_1_txs_num, tc4_2_txs_num, ds_txs_num),
                0,
                args + self.default_args,
                number_of_connections=1) as (conn, ):
            # Run test case.
            # Create some additional std txs to use.
            std_txs = self.get_txchains_n(tc4_1_txs_num, 1, spend_txs,
                                          CScript(), self.locking_script_1,
                                          2000000, 10)
            # Create and send generated txs.
            std_and_nonstd_txs, ds_txs, _ = self.run_scenario2(
                conn,
                spend_txs2,
                tc4_2_txs_num,
                self.locking_script_2,
                ds_txs_num,
                std_txs,
                shuffle_txs=True)
            wait_for_ptv_completion(conn, len(std_and_nonstd_txs) + 1)
            # All txs from the std_and_nonstd_txs result set should be accepted
            self.check_mempool_with_subset(conn.rpc,
                                           std_and_nonstd_txs,
                                           timeout=30)
            # There is one more transaction in the mempool. It is a random txn from the ds_txs set
            assert_equal(conn.rpc.getmempoolinfo()['size'],
                         len(std_and_nonstd_txs) + 1)
            # Only one txn is allowed to be accepted by the mempool, from the given double spends txn set.
            assert_equal(
                len(self.check_intersec_with_mempool(conn.rpc, ds_txs)), 1)

        #
        # Test Case 5 (TC5).
        #
        # - 24K=10x2400 non-standard txs (with a simple locking script) used
        #   - 1K=10x100 double spend txs used
        # - 1 peer connected to node0
        # From each double spend set only 1 txn is accepted by the mempool.
        # - Valid non-standard txs are sent first, then double spend txs (this approach maximises a ratio of 'txn-double-spend-detected' reject msgs)
        #
        # The number of txs used in a single subset.
        tc5_txs_num = 2400
        ds_txs_num = 100
        # The number of subsets used in the test case.
        tc5_num_of_subsets = 10
        # Select funding transactions to use:
        # - tc5_num_of_subsets funding transaction are needed in this test case.
        spend_txs = self.get_front_slice(out, tc5_num_of_subsets)
        args = ['-checkmempool=0', '-persistmempool=0']
        with self.run_node_with_connections(
                'TC5: {} non-std txs ({} double spends) used.'.format(
                    tc5_txs_num * tc5_num_of_subsets,
                    ds_txs_num * tc5_num_of_subsets),
                0,
                args + self.default_args,
                number_of_connections=1) as (conn, ):
            # Run test case.
            nonstd_txs, ds_txs, rejected_txs = self.run_scenario3(
                conn, spend_txs, tc5_txs_num, self.locking_script_2,
                ds_txs_num)
            wait_for_ptv_completion(conn,
                                    len(nonstd_txs) + tc5_num_of_subsets,
                                    check_interval=0.5)
            # All txs from the nonstd_txs result set should be accepted
            self.check_mempool_with_subset(conn.rpc, nonstd_txs, timeout=60)
            # There are tc5_num_of_subsets more transaction in the mempool (random txns from the ds_txs set)
            assert_equal(conn.rpc.getmempoolinfo()['size'],
                         len(nonstd_txs) + tc5_num_of_subsets)
            # Only tc5_num_of_subsets txns are allowed to be in the mempool from the given ds set.
            assert_equal(
                len(self.check_intersec_with_mempool(conn.rpc, ds_txs)),
                tc5_num_of_subsets)

        #
        # Test Case 6 (TC6).
        #
        # - 24K=10x2400 non-standard txs (with a simple locking script) used
        #   - 1K=10x100 double spend txs used
        # - 1 peer connected to node0
        # From each double spends set only 1 txn is accepted by the mempool.
        # All input txs are randomly suffled before sending.
        # - the txs set is shuffeled first so it significantly decreases 'txn-double-spend-detected' reject msgs comparing to TC5
        # - in this case 'txn-mempool-conflict' reject reason will mostly occur
        #
        # The number of txs used in a single subset.
        tc6_txs_num = 2400
        ds_txs_num = 100
        # The number of subsets used in the test case.
        tc6_num_of_subsets = 10
        # Select funding transactions to use:
        # - tc6_num_of_subsets funding transaction are needed in this test case.
        spend_txs = self.get_front_slice(out, tc6_num_of_subsets)
        args = ['-checkmempool=0', '-persistmempool=0']
        with self.run_node_with_connections(
                'TC6: {} non-std txs ({} double spends) used (shuffled set).'.
                format(tc6_txs_num * tc6_num_of_subsets,
                       ds_txs_num * tc6_num_of_subsets),
                0,
                args + self.default_args,
                number_of_connections=1) as (conn, ):
            # Run test case.
            nonstd_txs, ds_txs, rejected_txs = self.run_scenario3(
                conn,
                spend_txs,
                tc6_txs_num,
                self.locking_script_2,
                ds_txs_num,
                shuffle_txs=True)
            wait_for_ptv_completion(conn,
                                    len(nonstd_txs) + tc6_num_of_subsets,
                                    check_interval=0.5)
            # All txs from the nonstd_txs result set should be accepted
            self.check_mempool_with_subset(conn.rpc, nonstd_txs, timeout=60)
            # There are tc6_num_of_subsets more transaction in the mempool (random txns from the ds_txs set)
            assert_equal(conn.rpc.getmempoolinfo()['size'],
                         len(nonstd_txs) + tc6_num_of_subsets)
            # Only tc6_num_of_subsets txns are allowed to be in the mempool from the given ds set.
            assert_equal(
                len(self.check_intersec_with_mempool(conn.rpc, ds_txs)),
                tc6_num_of_subsets)