Skip to content

Commit

Permalink
set min relay fee to 1 (#400)
Browse files Browse the repository at this point in the history
* min relay fee

* bump min fee to 1.01

* fix weight calculation

* format workaround for minimal fee rate
  • Loading branch information
stepansnigirev authored Sep 19, 2020
1 parent 9c31f50 commit e7dec8e
Show file tree
Hide file tree
Showing 2 changed files with 25 additions and 15 deletions.
4 changes: 4 additions & 0 deletions src/cryptoadvance/specter/controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -1459,6 +1459,10 @@ def btc2sat(value):
@app.template_filter('feerate')
def feerate(value):
value = float(value)*1e8
# workaround for minimal fee rate
# because 1.01 doesn't look nice
if value <= 1.02:
value = 1
return "{:,.2f}".format(value).rstrip("0").rstrip(".")

@app.template_filter('btcunitamount')
Expand Down
36 changes: 21 additions & 15 deletions src/cryptoadvance/specter/wallet.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@ class Wallet():
IMPORT_KEYPOOL = 300
# a gap of 20 addresses is what many wallets do
GAP_LIMIT = 20
# minimal fee rate is slightly above 1 sat/vbyte
# to avoid rounding errors
MIN_FEE_RATE = 1.01
def __init__(
self,
name,
Expand Down Expand Up @@ -696,8 +699,10 @@ def labels(self):

def createpsbt(self, addresses:[str], amounts:[float], subtract:bool=False, subtract_from:int=0, fee_rate:float=1.0, selected_coins=[], readonly=False):
"""
fee_rate: in sat/B or BTC/kB. Default (None) bitcoin core sets feeRate automatically.
fee_rate: in sat/B or BTC/kB. If set to 0 Bitcoin Core sets feeRate automatically.
"""
if fee_rate > 0 and fee_rate < self.MIN_FEE_RATE:
fee_rate = self.MIN_FEE_RATE

if self.full_available_balance < sum(amounts):
raise SpecterError('The wallet does not have sufficient funds to make the transaction.')
Expand Down Expand Up @@ -737,8 +742,9 @@ def createpsbt(self, addresses:[str], amounts:[float], subtract:bool=False, subt

self.setlabel(self.change_address, "Change #{}".format(self.change_index))

# bitcoin core needs us to convert sat/B to BTC/kB
options["feeRate"] = round((fee_rate * 1000) / 1e8, 8)
if fee_rate > 0:
# bitcoin core needs us to convert sat/B to BTC/kB
options["feeRate"] = round((fee_rate * 1000) / 1e8, 8)

# don't reuse change addresses - use getrawchangeaddress instead
r = self.rpc.walletcreatefundedpsbt(
Expand All @@ -753,16 +759,13 @@ def createpsbt(self, addresses:[str], amounts:[float], subtract:bool=False, subt
psbt = self.rpc.decodepsbt(b64psbt)
if fee_rate > 0.0:
psbt_fees_sats = int(psbt['fee'] * 1e8)
tx_full_size = psbt['tx']['vsize']
for _ in psbt['inputs']:
# size is weight / 4
tx_full_size += self.weight_per_input/4
tx_full_size = ceil(tx_full_size)
# estimate final size: add weight of inputs
tx_full_size = ceil(psbt['tx']['vsize']
+ len(psbt["inputs"])*self.weight_per_input/4)
adjusted_fee_rate = fee_rate * (
fee_rate / (psbt_fees_sats / psbt['tx']['vsize'])
) * (tx_full_size / psbt['tx']['vsize'])
# add 0.5 to make sure we round up
options["feeRate"] = '%.8f' % round((adjusted_fee_rate * 1000 + 0.5) / 1e8, 8)
options["feeRate"] = '%.8f' % round((adjusted_fee_rate * 1000) / 1e8, 8)
r = self.rpc.walletcreatefundedpsbt(
extra_inputs, # inputs
[{addresses[i]: amounts[i]} for i in range(len(addresses))], # output
Expand All @@ -773,8 +776,11 @@ def createpsbt(self, addresses:[str], amounts:[float], subtract:bool=False, subt

b64psbt = r["psbt"]
psbt = self.rpc.decodepsbt(b64psbt)
psbt["tx_full_size"] = tx_full_size
psbt["fee_rate"] = options["feeRate"]
# estimate full size
tx_full_size = ceil(psbt['tx']['vsize']
+ len(psbt["inputs"])*self.weight_per_input/4)
psbt["tx_full_size"] = tx_full_size

psbt['base64'] = b64psbt
psbt["amount"] = amounts
Expand Down Expand Up @@ -888,12 +894,12 @@ def weight_per_input(self):
input_size += 75 # max sig size

if not self.recv_descriptor.startswith('wsh'):
# P2SH scriptsig: 00 20 <32-byte-hash>
input_size += 34 * 4
# P2SH scriptsig: 22 00 20 <32-byte-hash>
input_size += 35 * 4
return input_size
# else: single-sig
if self.recv_descriptor.startswith('wpkh'):
# pubkey, signature
return 75 + 34
# pubkey, signature, 4* P2SH: 00 14 20-byte-hash
return 75 + 34 + 22 * 4
# pubkey, signature, 4* P2SH: 16 00 14 20-byte-hash
return 75 + 34 + 23 * 4

0 comments on commit e7dec8e

Please sign in to comment.