Skip to content

Commit

Permalink
[test]: test estimatefee rpc
Browse files Browse the repository at this point in the history
  • Loading branch information
ismaelsadeeq committed Jun 24, 2024
1 parent dfd8502 commit 7de6cd7
Show file tree
Hide file tree
Showing 3 changed files with 72 additions and 0 deletions.
66 changes: 66 additions & 0 deletions test/functional/feature_fee_estimation.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@

from test_framework.messages import (
COIN,
DEFAULT_BLOCK_MAX_WEIGHT,
WITNESS_SCALE_FACTOR,
)
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import (
Expand Down Expand Up @@ -128,6 +130,14 @@ def make_tx(wallet, utxo, feerate):
fee_rate=Decimal(feerate * 1000) / COIN,
)

def send_tx(wallet, node, utxo, feerate, target_weight=0):
"""Broadcast a 1in-1out transaction with a specific input and feerate (sat/vb)."""
return wallet.send_self_transfer(
from_node=node,
utxo_to_spend=utxo,
fee_rate=Decimal(feerate * 1000) / COIN,
target_weight=target_weight,
)

class EstimateFeeTest(BitcoinTestFramework):
def set_test_params(self):
Expand Down Expand Up @@ -382,6 +392,60 @@ def test_acceptstalefeeestimates_option(self):
self.start_node(0,extra_args=["-acceptstalefeeestimates"])
assert_equal(self.nodes[0].estimatesmartfee(1)["feerate"], fee_rate)

def fill_mempool_to_block_max_weight(self, fee_rates, utxos, target_weight):
"""
Fills the mempool with transactions until it reaches the block's maximum weight.
"""
for fee_rate in fee_rates:
utxo = utxos.pop(0)
send_tx(self.wallet, self.nodes[0], utxo, fee_rate, target_weight)

mempool_weight = self.nodes[0].getmempoolinfo()["bytes"] * WITNESS_SCALE_FACTOR
assert_greater_than_or_equal(mempool_weight, DEFAULT_BLOCK_MAX_WEIGHT)

def test_estimate_fee_estimate_rpc(self):
self.log.info("test estimatefee rpc")
num_txs = 20
target_weight = int(DEFAULT_BLOCK_MAX_WEIGHT / num_txs)
self.restart_node(0, extra_args=[f"-datacarriersize={target_weight}"])

self.confutxo = self.wallet.send_self_transfer_multi(
from_node=self.nodes[0],
utxos_to_spend=[self.wallet.get_utxo() for _ in range(2)],
num_outputs=num_txs * 2
)['new_utxos']

self.generate(self.nodes[0], 1, sync_fun=self.no_op)

fee_rates = list(range(num_txs + 1, 1, -1)) # fee rates from (21...2) sat/vb

self.fill_mempool_to_block_max_weight(fee_rates, self.confutxo[0:num_txs], target_weight)

estimate = self.nodes[0].estimatefee(1)
fee_rate_below_25th_percentile = fee_rates[15]
fee_rate_below_50th_percentile = fee_rates[10]

fee_rate_above_25th_percentile = fee_rates[13]
fee_rate_above_50th_percentile = fee_rates[8]

assert_greater_than(estimate["low"], Decimal((fee_rate_below_25th_percentile * 1000) / COIN))
assert_greater_than(estimate["high"], Decimal((fee_rate_below_50th_percentile * 1000) / COIN))

assert_greater_than(Decimal((fee_rate_above_25th_percentile * 1000) / COIN), estimate["low"])
assert_greater_than(Decimal((fee_rate_above_50th_percentile * 1000) / COIN), estimate["high"])

high_fee_rates = list(range((num_txs * 2) + 1, num_txs + 1, -1)) # fee rates from (41...22) sat/vb
self.fill_mempool_to_block_max_weight(high_fee_rates, self.confutxo[num_txs:num_txs * 2], target_weight)

new_estimate = self.nodes[0].estimatefee(1)

# Previous estimate was cached; so cached value will be used
self.nodes[0].assert_debug_log(expected_msgs=["Mempool Forecast: cache is not stale, using cached value"])
assert_greater_than(new_estimate["low"], Decimal((fee_rate_below_25th_percentile * 1000) / COIN))
assert_greater_than(new_estimate["high"], Decimal((fee_rate_below_50th_percentile * 1000) / COIN))

assert_greater_than(Decimal((fee_rate_above_25th_percentile * 1000) / COIN), new_estimate["low"])
assert_greater_than(Decimal((fee_rate_above_50th_percentile * 1000) / COIN), new_estimate["high"])

def run_test(self):
self.log.info("This test is time consuming, please be patient")
Expand Down Expand Up @@ -431,6 +495,8 @@ def run_test(self):
self.log.info("Testing estimates with RBF.")
self.sanity_check_rbf_estimates(self.confutxo + self.memutxo)

self.log.info("Test fee estimation module")
self.test_estimate_fee_estimate_rpc()
self.log.info("Testing that fee estimation is disabled in blocksonly.")
self.restart_node(0, ["-blocksonly"])
assert_raises_rpc_error(
Expand Down
5 changes: 5 additions & 0 deletions test/functional/rpc_estimatefee.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,12 @@ def run_test(self):
# missing required params
assert_raises_rpc_error(-1, "estimatesmartfee", self.nodes[0].estimatesmartfee)
assert_raises_rpc_error(-1, "estimaterawfee", self.nodes[0].estimaterawfee)
assert_raises_rpc_error(-1, "estimatefee", self.nodes[0].estimatefee)

# wrong type for conf_target
assert_raises_rpc_error(-3, "JSON value of type string is not of expected type number", self.nodes[0].estimatesmartfee, 'foo')
assert_raises_rpc_error(-3, "JSON value of type string is not of expected type number", self.nodes[0].estimaterawfee, 'foo')
assert_raises_rpc_error(-3, "JSON value of type string is not of expected type number", self.nodes[0].estimatefee, 'foo')

# wrong type for estimatesmartfee(estimate_mode)
assert_raises_rpc_error(-3, "JSON value of type number is not of expected type string", self.nodes[0].estimatesmartfee, 1, 1)
Expand All @@ -35,6 +37,7 @@ def run_test(self):
# extra params
assert_raises_rpc_error(-1, "estimatesmartfee", self.nodes[0].estimatesmartfee, 1, 'ECONOMICAL', 1)
assert_raises_rpc_error(-1, "estimaterawfee", self.nodes[0].estimaterawfee, 1, 1, 1)
assert_raises_rpc_error(-1, "estimatefee", self.nodes[0].estimatefee, 1, 1)

# max value of 1008 per src/policy/fees.h
assert_raises_rpc_error(-8, "Invalid conf_target, must be between 1 and 1008", self.nodes[0].estimaterawfee, 1009)
Expand All @@ -50,6 +53,8 @@ def run_test(self):
self.nodes[0].estimaterawfee(1, None)
self.nodes[0].estimaterawfee(1, 1)

self.nodes[0].estimatefee(1)


if __name__ == '__main__':
EstimateFeeTest().main()
1 change: 1 addition & 0 deletions test/functional/test_framework/messages.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@

MAX_LOCATOR_SZ = 101
MAX_BLOCK_WEIGHT = 4000000
DEFAULT_BLOCK_MAX_WEIGHT = MAX_BLOCK_WEIGHT - 4000
MAX_BLOOM_FILTER_SIZE = 36000
MAX_BLOOM_HASH_FUNCS = 50

Expand Down

0 comments on commit 7de6cd7

Please sign in to comment.