Skip to content

Commit

Permalink
test: run mempool_limit with --disable-wallet
Browse files Browse the repository at this point in the history
Co-authored-by: Sishir Giri <sishirg27@gmail.com>
  • Loading branch information
ShubhamPalriwala and stackman27 committed Aug 11, 2021
1 parent 8193294 commit c6b17eb
Show file tree
Hide file tree
Showing 2 changed files with 63 additions and 38 deletions.
80 changes: 42 additions & 38 deletions test/functional/mempool_limit.py
Expand Up @@ -5,9 +5,12 @@
"""Test mempool limiting together/eviction with the wallet."""

from decimal import Decimal
from test_framework.blocktools import COINBASE_MATURITY

from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import assert_equal, assert_greater_than, assert_raises_rpc_error, create_confirmed_utxos, create_lots_of_big_transactions, gen_return_txouts
from test_framework.util import assert_equal, assert_greater_than, assert_raises_rpc_error, gen_return_txouts
from test_framework.wallet import MiniWallet


class MempoolLimitTest(BitcoinTestFramework):
def set_test_params(self):
Expand All @@ -20,55 +23,56 @@ def set_test_params(self):
]]
self.supports_cli = False

def skip_test_if_missing_module(self):
self.skip_if_no_wallet()

def run_test(self):
txouts = gen_return_txouts()
relayfee = self.nodes[0].getnetworkinfo()['relayfee']

node = self.nodes[0]
miniwallet = MiniWallet(node)
relayfee = node.getnetworkinfo()['relayfee']

self.log.info('Check that mempoolminfee is minrelytxfee')
assert_equal(self.nodes[0].getmempoolinfo()['minrelaytxfee'], Decimal('0.00001000'))
assert_equal(self.nodes[0].getmempoolinfo()['mempoolminfee'], Decimal('0.00001000'))
assert_equal(node.getmempoolinfo()['minrelaytxfee'], Decimal('0.00001000'))
assert_equal(node.getmempoolinfo()['mempoolminfee'], Decimal('0.00001000'))

# Generate 92 UTXOs to flood the mempool
# 1 to create a tx initially that will be evicted from the mempool later
# 90 with a fee rate much higher than the previous UTXO (3 batches of 30 with increasing fee rate)
# And 1 more to verify that this tx does not get added to the mempool with a fee rate less than the mempoolminfee
miniwallet.generate(1 + (3 * 30) + 1)

txids = []
utxos = create_confirmed_utxos(relayfee, self.nodes[0], 91)
# Mine 99 blocks so that the UTXOs are allowed to be spent
node.generate(COINBASE_MATURITY - 1)

self.log.info('Create a mempool tx that will be evicted')
us0 = utxos.pop()
inputs = [{ "txid" : us0["txid"], "vout" : us0["vout"]}]
outputs = {self.nodes[0].getnewaddress() : 0.0001}
tx = self.nodes[0].createrawtransaction(inputs, outputs)
self.nodes[0].settxfee(relayfee) # specifically fund this tx with low fee
txF = self.nodes[0].fundrawtransaction(tx)
self.nodes[0].settxfee(0) # return to automatic fee selection
txFS = self.nodes[0].signrawtransactionwithwallet(txF['hex'])
txid = self.nodes[0].sendrawtransaction(txFS['hex'])

relayfee = self.nodes[0].getnetworkinfo()['relayfee']
base_fee = relayfee*100
for i in range (3):
txids.append([])
txids[i] = create_lots_of_big_transactions(self.nodes[0], txouts, utxos[30*i:30*i+30], 30, (i+1)*base_fee)
tx_to_be_evicted_id = miniwallet.send_self_transfer(
from_node=node, fee_rate=relayfee
)["txid"]

# Increase the tx fee rate massively now to give the next transactions a higher priority in the mempool
base_fee = relayfee*1000

self.log.info('Fill up the mempool with txs with higher fee rate')
no_of_large_tx_created = 0
for batch_of_txid in range(1,4):
# Increment the tx fee rate gradually by a factor of (base_fee) for each batch of 30 transactions
no_of_large_tx_created += miniwallet.create_large_transactions(
node, txouts, 30, batch_of_txid * base_fee
)

self.log.info('The tx should be evicted by now')
assert txid not in self.nodes[0].getrawmempool()
txdata = self.nodes[0].gettransaction(txid)
assert txdata['confirmations'] == 0 #confirmation should still be 0
# The number of transactions created should be greater than the ones present in the mempool
assert_greater_than(no_of_large_tx_created, 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()

self.log.info('Check that mempoolminfee is larger than minrelytxfee')
assert_equal(self.nodes[0].getmempoolinfo()['minrelaytxfee'], Decimal('0.00001000'))
assert_greater_than(self.nodes[0].getmempoolinfo()['mempoolminfee'], Decimal('0.00001000'))
self.log.info('Check that mempoolminfee is larger than minrelaytxfee')
assert_equal(node.getmempoolinfo()['minrelaytxfee'], Decimal('0.00001000'))
assert_greater_than(node.getmempoolinfo()['mempoolminfee'], Decimal('0.00001000'))

# Deliberately tries to create a tx with a fee less that the minimum mempool fee to assert that it does not get added to the mempool
self.log.info('Create a mempool tx that will not pass mempoolminfee')
us0 = utxos.pop()
inputs = [{ "txid" : us0["txid"], "vout" : us0["vout"]}]
outputs = {self.nodes[0].getnewaddress() : 0.0001}
tx = self.nodes[0].createrawtransaction(inputs, outputs)
# specifically fund this tx with a fee < mempoolminfee, >= than minrelaytxfee
txF = self.nodes[0].fundrawtransaction(tx, {'feeRate': relayfee})
txFS = self.nodes[0].signrawtransactionwithwallet(txF['hex'])
assert_raises_rpc_error(-26, "mempool min fee not met", self.nodes[0].sendrawtransaction, txFS['hex'])
assert_raises_rpc_error(-26,"mempool min fee not met",miniwallet.send_self_transfer,from_node=node,fee_rate=relayfee,mempool_valid=False,)


if __name__ == '__main__':
MempoolLimitTest().main()
21 changes: 21 additions & 0 deletions test/functional/test_framework/wallet.py
Expand Up @@ -19,6 +19,7 @@
CTxInWitness,
CTxOut,
tx_from_hex,
from_hex,
)
from test_framework.script import (
CScript,
Expand Down Expand Up @@ -182,6 +183,26 @@ def sendrawtransaction(self, *, from_node, tx_hex):
from_node.sendrawtransaction(tx_hex)
self.scan_tx(from_node.decoderawtransaction(tx_hex))

def create_large_transactions(
self, node, array_of_large_tx, no_of_tx_ids, fee_rate
):
# Create large transactions by appending txouts in vout
no_of_tx_created = 0
for _ in range(no_of_tx_ids):
# Create a self transfer here to get the tx details and then append the vout to increase the tx size
hex = self.create_self_transfer(from_node=node, fee_rate=fee_rate)['hex']
# Converts it into a CTransaction() instance to append the vouts
tx_instance = from_hex(CTransaction(), hex)
for txout in array_of_large_tx:
tx_instance.vout.append(txout)
tx_hex = tx_instance.serialize().hex()
# Serializes and sends the tx to the nodes
self.sendrawtransaction(from_node=node, tx_hex=tx_hex)
no_of_tx_created += 1
assert_equal(no_of_tx_created,no_of_tx_ids)
return no_of_tx_created


def make_chain(node, address, privkeys, parent_txid, parent_value, n=0, parent_locking_script=None, fee=DEFAULT_FEE):
"""Build a transaction that spends parent_txid.vout[n] and produces one output with
amount = parent_value with a fee deducted.
Expand Down

0 comments on commit c6b17eb

Please sign in to comment.