Browse Source

Merge #750: Quiet/make more accurate fee information in sends

8cdf3e0 address comments of @kristapsk and @PulpCattel (Adam Gibson)
bb15aa0 Quiet/make more accurate fee information in sends (Adam Gibson)
master
Adam Gibson 5 years ago
parent
commit
9299191af1
No known key found for this signature in database
GPG Key ID: 141001A1AF77F20B
  1. 59
      jmclient/jmclient/blockchaininterface.py
  2. 3
      jmclient/jmclient/wallet.py
  3. 12
      scripts/sendpayment.py

59
jmclient/jmclient/blockchaininterface.py

@ -409,39 +409,58 @@ class BitcoinCoreInterface(BlockchainInterface):
return result
def estimate_fee_per_kb(self, N):
""" The argument N may be either a number of blocks target,
for estimation of feerate by Core, or a number of satoshis
per kilo-vbyte (see `fee_per_kb_has_been_manually_set` for
how this is distinguished).
In the latter case, it is prevented from falling below the
minimum allowed feerate for relay on the Bitcoin network.
In case of failure to connect, None is returned.
In case of failure to source a specific minimum fee relay rate
(which is used to sanity check user's chosen fee rate), 1000
is used.
In case of failure to source a feerate estimate for targeted
number of blocks, a default of 10000 is returned.
"""
if super().fee_per_kb_has_been_manually_set(N):
# use the local bitcoin core relay fee as floor to avoid relay problems
btc_relayfee = -1
# use the local bitcoin core relay fee as floor to avoid relay
# problems
rpc_result = self._rpc('getnetworkinfo', None)
btc_relayfee = rpc_result.get('relayfee', btc_relayfee)
if btc_relayfee > 0:
relayfee_in_sat = int(Decimal(1e8) * Decimal(btc_relayfee))
log.info("Using this min relay fee as tx fee floor: " +
btc.fee_per_kb_to_str(relayfee_in_sat))
return int(max(relayfee_in_sat, random.uniform(N * float(0.8), N * float(1.2))))
else: # cannot get valid relayfee: fall back to 1000 sat/kbyte
log.info("Using this min relay fee as tx fee floor " +
"(fallback): " + btc.fee_per_kb_to_str(1000))
return int(max(1000, random.uniform(N * float(0.8), N * float(1.2))))
if not rpc_result:
# in case of connection error:
return None
btc_relayfee = rpc_result.get('relayfee', 1000)
relayfee_in_sat = int(Decimal(1e8) * Decimal(btc_relayfee))
log.debug("Using this min relay fee as tx feerate floor: " +
btc.fee_per_kb_to_str(relayfee_in_sat))
return int(max(relayfee_in_sat, random.uniform(N * float(0.8),
N * float(1.2))))
# Special bitcoin core case: sometimes the highest priority
# cannot be estimated in that case the 2nd highest priority
# should be used instead of falling back to hardcoded values
tries = 2 if N == 1 else 1
estimate = -1
retval = -1
for i in range(tries):
rpc_result = self._rpc('estimatesmartfee', [N + i])
estimate = rpc_result.get('feerate', estimate)
if estimate > 0:
if not rpc_result:
# in case of connection error:
return None
estimate = rpc_result.get('feerate')
# `estimatesmartfee` will currently return in the format
# `{'errors': ['Insufficient data or no feerate found'], 'blocks': N}`
# if it is not able to make an estimate. We insist that
# the 'feerate' key is found and contains a positive value:
if estimate and estimate > 0:
retval = int(Decimal(1e8) * Decimal(estimate))
break
else: # estimate <= 0
else: # cannot get a valid estimate after `tries` tries:
log.warn("Could not source a fee estimate from Core, " +
"falling back to default.")
retval = 10000
if retval == -1:
retval = int(Decimal(1e8) * Decimal(estimate))
log.info("Using tx fee: " + btc.fee_per_kb_to_str(retval))
log.info("Using bitcoin network feerate: " +\
btc.fee_per_kb_to_str(retval))
return retval
def get_current_block_height(self):

3
jmclient/jmclient/wallet.py

@ -55,6 +55,9 @@ def estimate_tx_fee(ins, outs, txtype='p2pkh', extra_bytes=0):
"without blockchain source.")
fee_per_kb = jm_single().bc_interface.estimate_fee_per_kb(
jm_single().config.getint("POLICY","tx_fees"))
if fee_per_kb is None:
raise RuntimeError("Cannot estimate fee per kB, possibly" +
" a failure of connection to the blockchain.")
absurd_fee = jm_single().config.getint("POLICY", "absurd_fee_per_kb")
if fee_per_kb > absurd_fee:
#This error is considered critical; for safety reasons, shut down.

12
scripts/sendpayment.py

@ -172,17 +172,19 @@ def main():
# the sync call here will now be a no-op:
wallet_service.startService()
# Dynamically estimate a realistic fee.
# Dynamically estimate a realistic fee, for coinjoins.
# At this point we do not know even the number of our own inputs, so
# we guess conservatively with 2 inputs and 2 outputs each.
fee_per_cp_guess = estimate_tx_fee(2, 2, txtype=wallet_service.get_txtype())
log.debug("Estimated miner/tx fee for each cj participant: " + str(
fee_per_cp_guess))
if options.makercount != 0:
fee_per_cp_guess = estimate_tx_fee(2, 2,
txtype=wallet_service.get_txtype())
log.debug("Estimated miner/tx fee for each cj participant: " +
btc.amount_to_str(fee_per_cp_guess))
# From the estimated tx fees, check if the expected amount is a
# significant value compared the the cj amount; currently enabled
# only for single join (the predominant, non-advanced case)
if options.schedule == '':
if options.schedule == '' and options.makercount != 0:
total_cj_amount = amount
if total_cj_amount == 0:
total_cj_amount = wallet_service.get_balance_by_mixdepth()[options.mixdepth]

Loading…
Cancel
Save