Browse Source

use estimatesmartfee for fee estimation (#300)

* use estimatesmartfee for fee estimation, in case of BitcoinSegwit

* use estimatesmartfee in daemon if available

* daemon._is_rpc_available() now catches DaemonError instead of using HTTP error code
patch-1
SomberNight 7 years ago
committed by Neil
parent
commit
8293da1e10
  1. 36
      server/daemon.py

36
server/daemon.py

@ -20,6 +20,7 @@ import aiohttp
from lib.util import LoggedClass, int_to_varint, hex_to_bytes from lib.util import LoggedClass, int_to_varint, hex_to_bytes
from lib.hash import hex_str_to_hash from lib.hash import hex_str_to_hash
from lib.jsonrpc import JSONRPC
class DaemonError(Exception): class DaemonError(Exception):
@ -30,6 +31,7 @@ class Daemon(LoggedClass):
'''Handles connections to a daemon at the given URL.''' '''Handles connections to a daemon at the given URL.'''
WARMING_UP = -28 WARMING_UP = -28
RPC_MISC_ERROR = -1
class DaemonWarmingUpError(Exception): class DaemonWarmingUpError(Exception):
'''Raised when the daemon returns an error in its results.''' '''Raised when the daemon returns an error in its results.'''
@ -54,6 +56,7 @@ class Daemon(LoggedClass):
else: else:
self.ClientHttpProcessingError = asyncio.TimeoutError self.ClientHttpProcessingError = asyncio.TimeoutError
self.ClientPayloadError = aiohttp.ClientPayloadError self.ClientPayloadError = aiohttp.ClientPayloadError
self._available_rpcs = {} # caches results for _is_rpc_available()
def next_req_id(self): def next_req_id(self):
'''Retrns the next request ID.''' '''Retrns the next request ID.'''
@ -97,7 +100,7 @@ class Daemon(LoggedClass):
# If bitcoind can't find a tx, for some reason # If bitcoind can't find a tx, for some reason
# it returns 500 but fills out the JSON. # it returns 500 but fills out the JSON.
# Should still return 200 IMO. # Should still return 200 IMO.
if resp.status in (200, 500): if resp.status in (200, 404, 500):
return await resp.json() return await resp.json()
return (resp.status, resp.reason) return (resp.status, resp.reason)
@ -194,6 +197,34 @@ class Daemon(LoggedClass):
return await self._send(payload, processor) return await self._send(payload, processor)
return [] return []
async def _is_rpc_available(self, method):
'''Return whether given RPC method is available in the daemon.
Results are cached and the daemon will generally not be queried with
the same method more than once.'''
available = self._available_rpcs.get(method, None)
if available is None:
try:
await self._send_single(method)
available = True
except DaemonError as e:
err = e.args[0]
error_code = err.get("code")
if error_code == JSONRPC.METHOD_NOT_FOUND:
available = False
elif error_code == self.RPC_MISC_ERROR:
# method found but exception was thrown in command handling
# probably because we did not provide arguments
available = True
else:
self.logger.warning('unexpected error (code {:d}: {}) when '
'testing RPC availability of method {}'
.format(error_code, err.get("message"),
method))
available = False
self._available_rpcs[method] = available
return available
async def block_hex_hashes(self, first, count): async def block_hex_hashes(self, first, count):
'''Return the hex hashes of count block starting at height first.''' '''Return the hex hashes of count block starting at height first.'''
params_iterable = ((h, ) for h in range(first, first + count)) params_iterable = ((h, ) for h in range(first, first + count))
@ -216,6 +247,9 @@ class Daemon(LoggedClass):
async def estimatefee(self, params): async def estimatefee(self, params):
'''Return the fee estimate for the given parameters.''' '''Return the fee estimate for the given parameters.'''
if await self._is_rpc_available('estimatesmartfee'):
estimate = await self._send_single('estimatesmartfee', params)
return estimate['feerate']
return await self._send_single('estimatefee', params) return await self._send_single('estimatefee', params)
async def getnetworkinfo(self): async def getnetworkinfo(self):

Loading…
Cancel
Save