Repository: bitcoin/bitcoin
File: test/functional/test_framework/util.py (Python)

Code before:


# Transaction/Block functions
#############################


# Create large OP_RETURN txouts that can be appended to a transaction
# to make it large (helper for constructing large transactions). The
# total serialized size of the txouts is about 66k vbytes.
def gen_return_txouts():
    from .messages import CTxOut
    from .script import CScript, OP_RETURN
    txouts = [CTxOut(nValue=0, scriptPubKey=CScript([OP_RETURN, b'\x01'*67437]))]
    assert_equal(sum([len(txout.serialize()) for txout in txouts]), 67456)
    return txouts


# Create a spend of each passed-in utxo, splicing in "txouts" to each raw
# transaction to make it large.  See gen_return_txouts() above.
def create_lots_of_big_transactions(mini_wallet, node, fee, tx_batch_size, txouts, utxos=None):
    txids = []
    use_internal_utxos = utxos is None
    for _ in range(tx_batch_size):
        tx = mini_wallet.create_self_transfer(
            utxo_to_spend=None if use_internal_utxos else utxos.pop(),
            fee=fee,
        )["tx"]
        tx.vout.extend(txouts)
        res = node.testmempoolaccept([tx.serialize().hex()])[0]
        assert_equal(res['fees']['base'], fee)
        txids.append(node.sendrawtransaction(tx.serialize().hex()))
    return txids


def mine_large_block(test_framework, mini_wallet, node):
    # generate a 66k transaction,
    # and 14 of them is close to the 1MB block limit
    txouts = gen_return_txouts()
    fee = 100 * node.getnetworkinfo()["relayfee"]
    create_lots_of_big_transactions(mini_wallet, node, fee, 14, txouts)
    test_framework.generate(node, 1)


def find_vout_for_address(node, txid, addr):
    """
    Locate the vout index of the given transaction sending to the
    given address. Raises runtime error exception if not found.
    """
    tx = node.getrawtransaction(txid, True)
    for i in range(len(tx["vout"])):
        if addr == tx["vout"][i]["scriptPubKey"]["address"]:

Review comment (refactor):
In "Move fill_mempool to util function" (cc770e4b36e6f04cbd588ad3e7a19f122c21d38d):

Nit: If a commit is described as a move, I would expect no changes in the code beyond what’s necessary to update the callsites. While these changes are minor and obviously do not entail a functional change, I would have expected the updated commentary and refactor to be a separate commit—I’m wondering whether my understanding of the modus operandi is correct.

Code after:

def fill_mempool(test_framework, node, miniwallet):
    """Fill mempool until eviction.

    Allows for simpler testing of scenarios with floating mempoolminfee > minrelay
    Requires -datacarriersize=100000 and
   -maxmempool=5.
    It will not ensure mempools become synced as it
    is based on a single node and assumes -minrelaytxfee
    is 1 sat/vbyte.
    """
    test_framework.log.info("Fill the mempool until eviction is triggered and the mempoolminfee rises")
    txouts = gen_return_txouts()
    relayfee = node.getnetworkinfo()['relayfee']

    assert_equal(relayfee, Decimal('0.00001000'))

    tx_batch_size = 1
    num_of_batches = 75
    # Generate UTXOs to flood the mempool
    # 1 to create a tx initially that will be evicted from the mempool later
    # 75 transactions each with a fee rate higher than the previous one
    test_framework.generate(miniwallet, 1 + (num_of_batches * tx_batch_size))

    # Mine COINBASE_MATURITY - 1 blocks so that the UTXOs are allowed to be spent
    test_framework.generate(node, 100 - 1)

    test_framework.log.debug("Create a mempool tx that will be evicted")
    tx_to_be_evicted_id = miniwallet.send_self_transfer(from_node=node, fee_rate=relayfee)["txid"]

    # Increase the tx fee rate to give the subsequent transactions a higher priority in the mempool
    # The tx has an approx. vsize of 65k, i.e. multiplying the previous fee rate (in sats/kvB)
    # by 130 should result in a fee that corresponds to 2x of that fee rate
    base_fee = relayfee * 130

    test_framework.log.debug("Fill up the mempool with txs with higher fee rate")
    with node.assert_debug_log(["rolling minimum fee bumped"]):
        for batch_of_txid in range(num_of_batches):
            fee = (batch_of_txid + 1) * base_fee
            create_lots_of_big_transactions(miniwallet, node, fee, tx_batch_size, txouts)

    test_framework.log.debug("The tx should be evicted by now")
    # The number of transactions created should be greater than the ones present in the mempool
    assert_greater_than(tx_batch_size * num_of_batches, len(node.getrawmempool()))
    # Initial tx created should not be present in the mempool anymore as it had a lower fee rate
    assert tx_to_be_evicted_id not in node.getrawmempool()

    test_framework.log.debug("Check that mempoolminfee is larger than minrelaytxfee")
    assert_equal(node.getmempoolinfo()['minrelaytxfee'], Decimal('0.00001000'))
    assert_greater_than(node.getmempoolinfo()['mempoolminfee'], Decimal('0.00001000'))