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
This commit is contained in:
parent
159db3f8e7
commit
8293da1e10
@ -20,6 +20,7 @@ import aiohttp
|
||||
|
||||
from lib.util import LoggedClass, int_to_varint, hex_to_bytes
|
||||
from lib.hash import hex_str_to_hash
|
||||
from lib.jsonrpc import JSONRPC
|
||||
|
||||
|
||||
class DaemonError(Exception):
|
||||
@ -30,6 +31,7 @@ class Daemon(LoggedClass):
|
||||
'''Handles connections to a daemon at the given URL.'''
|
||||
|
||||
WARMING_UP = -28
|
||||
RPC_MISC_ERROR = -1
|
||||
|
||||
class DaemonWarmingUpError(Exception):
|
||||
'''Raised when the daemon returns an error in its results.'''
|
||||
@ -54,6 +56,7 @@ class Daemon(LoggedClass):
|
||||
else:
|
||||
self.ClientHttpProcessingError = asyncio.TimeoutError
|
||||
self.ClientPayloadError = aiohttp.ClientPayloadError
|
||||
self._available_rpcs = {} # caches results for _is_rpc_available()
|
||||
|
||||
def next_req_id(self):
|
||||
'''Retrns the next request ID.'''
|
||||
@ -97,7 +100,7 @@ class Daemon(LoggedClass):
|
||||
# If bitcoind can't find a tx, for some reason
|
||||
# it returns 500 but fills out the JSON.
|
||||
# Should still return 200 IMO.
|
||||
if resp.status in (200, 500):
|
||||
if resp.status in (200, 404, 500):
|
||||
return await resp.json()
|
||||
return (resp.status, resp.reason)
|
||||
|
||||
@ -194,6 +197,34 @@ class Daemon(LoggedClass):
|
||||
return await self._send(payload, processor)
|
||||
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):
|
||||
'''Return the hex hashes of count block starting at height first.'''
|
||||
params_iterable = ((h, ) for h in range(first, first + count))
|
||||
@ -216,6 +247,9 @@ class Daemon(LoggedClass):
|
||||
|
||||
async def estimatefee(self, params):
|
||||
'''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)
|
||||
|
||||
async def getnetworkinfo(self):
|
||||
|
||||
Loading…
Reference in New Issue
Block a user