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.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…
Reference in New Issue
Block a user