Skip to content

Commit 2c41a23

Browse files
authored
Merge pull request #302 from f321x/mempoolminfee
implements mempool.get_info and clarifies comments of relayfee
2 parents fb28dc2 + 25001fd commit 2c41a23

File tree

4 files changed

+66
-9
lines changed

4 files changed

+66
-9
lines changed

docs/rpc-interface.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@ A typical result is as follows (with annotated comments)::
9898
"getinfo": 3,
9999
"groups": 1,
100100
"mempool.get_fee_histogram": 3194,
101+
"mempool.get_info": 121,
101102
"server.add_peer": 9,
102103
"server.banner": 740,
103104
"server.donation_address": 754,

src/electrumx/server/daemon.py

Lines changed: 31 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,9 @@ def __init__(
7979
self._networkinfo_cache = (None, 0)
8080
self._networkinfo_lock = asyncio.Lock()
8181

82+
self._mempoolinfo_cache = (None, 0)
83+
self._mempoolinfo_lock = asyncio.Lock()
84+
8285
async def __aenter__(self):
8386
self.session = aiohttp.ClientSession(connector=self.connector())
8487
return self
@@ -284,12 +287,36 @@ async def getnetworkinfo(self):
284287
self._networkinfo_cache = (val, time.time())
285288
return val
286289

290+
async def getmempoolinfo(self):
291+
"""Return the result of the 'getmempoolinfo' RPC call."""
292+
async with self._mempoolinfo_lock:
293+
cache_val, cache_time = self._mempoolinfo_cache
294+
if time.time() - cache_time < 60: # seconds
295+
return cache_val
296+
val = await self._send_single('getmempoolinfo')
297+
self._mempoolinfo_cache = (val, time.time())
298+
return val
299+
287300
async def relayfee(self):
288-
'''The minimum fee a low-priority tx must pay in order to be accepted
289-
to the daemon's memory pool.'''
301+
"""Same as getmempoolinfo['minrelaytxfee'].
302+
The minimum fee required for a transaction to be relayed on by the daemon to the
303+
bitcoin network. Doesn't guarantee mempool acceptance."""
290304
network_info = await self.getnetworkinfo()
291305
return network_info['relayfee']
292306

307+
async def mempool_info(self) -> dict[str, float]:
308+
mempool_info = await self.getmempoolinfo()
309+
return {
310+
# Dynamic minimum fee rate in BTC/kvB for tx to be accepted.
311+
# Is the maximum of minrelaytxfee and minimum mempool fee
312+
'mempoolminfee': mempool_info['mempoolminfee'],
313+
# Minimum relay fee for transactions in BTC/kvB, operator-configurable, static.
314+
'minrelaytxfee': mempool_info['minrelaytxfee'],
315+
# Minimum fee rate increment for mempool limiting or replacement in BTC/kvB,
316+
# operator-configurable, static.
317+
'incrementalrelayfee': mempool_info['incrementalrelayfee'],
318+
}
319+
293320
async def getrawtransaction(self, hex_hash, verbose=False):
294321
'''Return the serialized raw transaction with the given hash.'''
295322
# Cast to int because some coin daemons are old and require it
@@ -350,8 +377,8 @@ async def estimatefee(self, block_count):
350377
return self.coin.ESTIMATE_FEE
351378

352379
async def relayfee(self):
353-
'''The minimum fee a low-priority tx must pay in order to be accepted
354-
to the daemon's memory pool.'''
380+
"""The minimum fee required for a transaction to be relayed on by the server to the
381+
bitcoin network. Doesn't guarantee mempool acceptance."""
355382
return self.coin.RELAY_FEE
356383

357384

src/electrumx/server/session.py

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1396,11 +1396,23 @@ async def banner(self):
13961396
return banner
13971397

13981398
async def relayfee(self):
1399-
'''The minimum fee a low-priority tx must pay in order to be accepted
1400-
to the daemon's memory pool.'''
1399+
"""The minimum fee required for a transaction to be relayed on by the daemon to the
1400+
bitcoin network. Doesn't guarantee mempool acceptance."""
14011401
self.bump_cost(1.0)
14021402
return await self.daemon_request('relayfee')
14031403

1404+
async def mempool_info(self) -> dict[str, float]:
1405+
"""
1406+
mempool.get_info, introduced in protocol 1.6.
1407+
returns: {
1408+
"mempoolminfee": BTC/kvB,
1409+
"minrelaytxfee": BTC/kvB,
1410+
"incrementalrelayfee": BTC/kvB,
1411+
}
1412+
"""
1413+
self.bump_cost(1.0)
1414+
return await self.daemon_request('mempool_info')
1415+
14041416
async def estimatefee(self, number, mode=None):
14051417
'''The estimated transaction fee per kilobyte to be paid for a
14061418
transaction to be included within a certain number of blocks.
@@ -1636,7 +1648,6 @@ def set_request_handlers(self, ptuple):
16361648
'blockchain.block.headers': self.block_headers,
16371649
'blockchain.estimatefee': self.estimatefee,
16381650
'blockchain.headers.subscribe': self.headers_subscribe,
1639-
'blockchain.relayfee': self.relayfee,
16401651
'blockchain.scripthash.get_balance': self.scripthash_get_balance,
16411652
'blockchain.scripthash.get_history': self.scripthash_get_history,
16421653
'blockchain.scripthash.get_mempool': self.scripthash_get_mempool,
@@ -1659,8 +1670,11 @@ def set_request_handlers(self, ptuple):
16591670
if ptuple >= (1, 4, 2):
16601671
handlers['blockchain.scripthash.unsubscribe'] = self.scripthash_unsubscribe
16611672

1662-
# experimental:
1663-
handlers['blockchain.transaction.broadcast_package'] = self.package_broadcast
1673+
if ptuple >= (1, 6):
1674+
handlers['blockchain.transaction.broadcast_package'] = self.package_broadcast
1675+
handlers['mempool.get_info'] = self.mempool_info
1676+
else:
1677+
handlers['blockchain.relayfee'] = self.relayfee # removed in 1.6
16641678

16651679
self.request_handlers = handlers
16661680

tests/server/test_daemon.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,21 @@ async def test_relayfee(daemon):
255255
assert await daemon.relayfee() == sats
256256

257257

258+
@pytest.mark.asyncio
259+
async def test_mempool_info(daemon):
260+
bitcoin_per_kvb = 0.00002123
261+
response = {
262+
'mempoolminfee': bitcoin_per_kvb,
263+
'minrelaytxfee': bitcoin_per_kvb,
264+
'incrementalrelayfee': bitcoin_per_kvb,
265+
'other': 'cruft',
266+
}
267+
daemon.session = ClientSessionGood(('getmempoolinfo', [], response))
268+
expected_result = dict(response)
269+
del expected_result['other']
270+
assert await daemon.mempool_info() == expected_result
271+
272+
258273
@pytest.mark.asyncio
259274
async def test_mempool_hashes(daemon):
260275
hashes = ['hex_hash1', 'hex_hash2']

0 commit comments

Comments
 (0)