Browse Source

Support maxcjfee settings for tumble in Qt

Also refactor tumbler offer filter callback to tumble_support
Add default values for first page of tumbler wizard (Qt)
master
Adam Gibson 9 years ago
parent
commit
cdd072eb8c
No known key found for this signature in database
GPG Key ID: B3AE09F1E9A3197A
  1. 3
      jmclient/jmclient/__init__.py
  2. 16
      jmclient/jmclient/tumble_support.py
  3. 10
      scripts/joinmarket-qt.py
  4. 34
      scripts/qtsupport.py
  5. 17
      scripts/tumbler.py

3
jmclient/jmclient/__init__.py

@ -35,7 +35,8 @@ from .schedule import (get_schedule, get_tumble_schedule, schedule_to_text,
schedule_to_text) schedule_to_text)
from .commitment_utils import get_utxo_info, validate_utxo_data, quit from .commitment_utils import get_utxo_info, validate_utxo_data, quit
from .tumble_support import (tumbler_taker_finished_update, restart_waiter, from .tumble_support import (tumbler_taker_finished_update, restart_waiter,
restart_wait, get_tumble_log) restart_wait, get_tumble_log,
tumbler_filter_orders_callback)
# Set default logging handler to avoid "No handler found" warnings. # Set default logging handler to avoid "No handler found" warnings.
try: try:

16
jmclient/jmclient/tumble_support.py

@ -168,3 +168,19 @@ def tumbler_taker_finished_update(taker, schedulefile, tumble_log, options,
taker.schedule[taker.schedule_index][5] = 1 taker.schedule[taker.schedule_index][5] = 1
with open(schedulefile, "wb") as f: with open(schedulefile, "wb") as f:
f.write(schedule_to_text(taker.schedule)) f.write(schedule_to_text(taker.schedule))
def tumbler_filter_orders_callback(orders_fees, cjamount, taker, options):
"""Since the tumbler does not use interactive fee checking,
we use the -x values from the command line instead.
"""
orders, total_cj_fee = orders_fees
abs_cj_fee = 1.0 * total_cj_fee / taker.n_counterparties
rel_cj_fee = abs_cj_fee / cjamount
log.info('rel/abs average fee = ' + str(rel_cj_fee) + ' / ' + str(
abs_cj_fee))
if rel_cj_fee > options['maxcjfee'][
0] and abs_cj_fee > options['maxcjfee'][1]:
log.info("Rejected fees as too high according to options, will retry.")
return "retry"
return True

10
scripts/joinmarket-qt.py

@ -53,7 +53,7 @@ from jmclient import (load_program_config, get_network, Wallet,
get_blockchain_interface_instance, sync_wallet, get_blockchain_interface_instance, sync_wallet,
RegtestBitcoinCoreInterface, tweak_tumble_schedule, RegtestBitcoinCoreInterface, tweak_tumble_schedule,
human_readable_schedule_entry, tumbler_taker_finished_update, human_readable_schedule_entry, tumbler_taker_finished_update,
get_tumble_log, restart_wait) get_tumble_log, restart_wait, tumbler_filter_orders_callback)
from qtsupport import (ScheduleWizard, warnings, config_tips, config_types, from qtsupport import (ScheduleWizard, warnings, config_tips, config_types,
TaskThread, QtHandler, XStream, Buttons, CloseButton, TaskThread, QtHandler, XStream, Buttons, CloseButton,
@ -614,7 +614,9 @@ class SpendTab(QWidget):
#sync_wallet(w.wallet, fast=True) #sync_wallet(w.wallet, fast=True)
#Decide whether to interrupt processing to sanity check the fees #Decide whether to interrupt processing to sanity check the fees
if jm_single().config.get("GUI", "checktx") == "true": if self.tumbler_options:
check_offers_callback = self.checkOffersTumbler
elif jm_single().config.get("GUI", "checktx") == "true":
check_offers_callback = self.callback_checkOffers check_offers_callback = self.callback_checkOffers
else: else:
check_offers_callback = None check_offers_callback = None
@ -699,6 +701,10 @@ class SpendTab(QWidget):
self.abortTransactions() self.abortTransactions()
self.taker_info_response = True self.taker_info_response = True
def checkOffersTumbler(self, offers_fees, cjamount):
return tumbler_filter_orders_callback(offers_fees, cjamount,
self.taker, self.tumbler_options)
def checkOffers(self): def checkOffers(self):
"""Parse offers and total fee from client protocol, """Parse offers and total fee from client protocol,
allow the user to agree or decide. allow the user to agree or decide.

34
scripts/qtsupport.py

@ -508,24 +508,29 @@ class SchDynamicPage1(QWizardPage):
sN = ['Starting mixdepth', 'Average number of counterparties', sN = ['Starting mixdepth', 'Average number of counterparties',
'How many mixdepths to tumble through', 'How many mixdepths to tumble through',
'Average wait time between transactions, in minutes', 'Average wait time between transactions, in minutes',
'Average number of transactions per mixdepth'] 'Average number of transactions per mixdepth',
'Max relative fee per counterparty (e.g. 0.005)',
'Max fee per counterparty, satoshis (e.g. 10000)']
#Tooltips #Tooltips
sH = ["The starting mixdepth can be decided from the Wallet tab; it must " sH = ["The starting mixdepth can be decided from the Wallet tab; it must "
"have coins in it, but it's OK if some coins are in other mixdepths.", "have coins in it, but it's OK if some coins are in other mixdepths.",
"How many other participants are in each coinjoin, on average; but " "How many other participants are in each coinjoin, on average; but "
"each individual coinjoin will have a number that's slightly varied " "each individual coinjoin will have a number that's varied according to "
"from this, randomly", "settings on the next page",
"For example, if you start at mixdepth 1 and enter 4 here, the tumble " "For example, if you start at mixdepth 1 and enter 4 here, the tumble "
"will move coins from mixdepth 1 to mixdepth 5", "will move coins from mixdepth 1 to mixdepth 5",
"This is the time waited *after* 1 confirmation has occurred, and is " "This is the time waited *after* 1 confirmation has occurred, and is "
"varied randomly.", "varied randomly.",
"Will be varied randomly, with a minimum of 1 per mixdepth"] "Will be varied randomly, see advanced settings next page",
"A decimal fraction (e.g. 0.001 = 0.1%) (this AND next must be violated to reject",
"Integer number of satoshis (this AND previous must be violated to reject)"]
#types #types
sT = [int, int, int, float, int] sT = [int, int, int, float, int, float, int]
#constraints #constraints
sMM = [(0, jm_single().config.getint("GUI", "max_mix_depth") - 1), (3, 20), sMM = [(0, jm_single().config.getint("GUI", "max_mix_depth") - 1), (3, 20),
(1, 5), (0.00000001, 100.0, 8), (2, 10)] (1, 5), (0.00000001, 100.0, 8), (2, 10), (0.000001, 0.25, 6),
sD = ['', '', '', '', ''] (0, 10000000)]
sD = ['0', '4', '4', '0.25', '3', '0.005', '10000']
for x in zip(sN, sH, sT, sD, sMM): for x in zip(sN, sH, sT, sD, sMM):
ql = QLabel(x[0]) ql = QLabel(x[0])
ql.setToolTip(x[1]) ql.setToolTip(x[1])
@ -541,11 +546,13 @@ class SchDynamicPage1(QWizardPage):
layout.addWidget(x[0], i + 1, 0) layout.addWidget(x[0], i + 1, 0)
layout.addWidget(x[1], i + 1, 1, 1, 2) layout.addWidget(x[1], i + 1, 1, 1, 2)
self.setLayout(layout) self.setLayout(layout)
self.registerField("mixdepthsrc*", results[0][1]) self.registerField("mixdepthsrc", results[0][1])
self.registerField("makercount*", results[1][1]) self.registerField("makercount", results[1][1])
self.registerField("mixdepthcount*", results[2][1]) self.registerField("mixdepthcount", results[2][1])
self.registerField("timelambda*", results[3][1]) self.registerField("timelambda", results[3][1])
self.registerField("txcountparams*", results[4][1]) self.registerField("txcountparams", results[4][1])
self.registerField("maxrelfee", results[5][1])
self.registerField("maxabsfee", results[6][1])
class SchDynamicPage2(QWizardPage): class SchDynamicPage2(QWizardPage):
@ -692,6 +699,9 @@ class ScheduleWizard(QWizard):
self.opts['timelambda'] = float(self.field("timelambda").toString()) self.opts['timelambda'] = float(self.field("timelambda").toString())
self.opts['waittime'] = float(self.field("waittime").toString()) self.opts['waittime'] = float(self.field("waittime").toString())
self.opts['mincjamount'] = int(self.field("mincjamount").toString()) self.opts['mincjamount'] = int(self.field("mincjamount").toString())
relfeeval = float(self.field("maxrelfee").toString())
absfeeval = int(self.field("maxabsfee").toString())
self.opts['maxcjfee'] = (relfeeval, absfeeval)
#needed for Taker to check: #needed for Taker to check:
jm_single().mincjamount = self.opts['mincjamount'] jm_single().mincjamount = self.opts['mincjamount']
return get_tumble_schedule(self.opts, self.destaddrs) return get_tumble_schedule(self.opts, self.destaddrs)

17
scripts/tumbler.py

@ -19,7 +19,7 @@ from jmclient import (Taker, load_program_config, get_schedule,
RegtestBitcoinCoreInterface, estimate_tx_fee, RegtestBitcoinCoreInterface, estimate_tx_fee,
tweak_tumble_schedule, human_readable_schedule_entry, tweak_tumble_schedule, human_readable_schedule_entry,
schedule_to_text, restart_waiter, get_tumble_log, schedule_to_text, restart_waiter, get_tumble_log,
tumbler_taker_finished_update) tumbler_taker_finished_update, tumbler_filter_orders_callback)
from jmbase.support import get_log, debug_dump_object, get_password from jmbase.support import get_log, debug_dump_object, get_password
from cli_options import get_tumbler_parser from cli_options import get_tumbler_parser
@ -101,20 +101,9 @@ def main():
print("Progress logging to logs/TUMBLE.log") print("Progress logging to logs/TUMBLE.log")
def filter_orders_callback(orders_fees, cjamount): def filter_orders_callback(orders_fees, cjamount):
"""Since the tumbler does not use interactive fee checking, """Decide whether to accept fees
we use the -x values from the command line instead.
""" """
orders, total_cj_fee = orders_fees return tumbler_filter_orders_callback(orders_fees, cjamount, taker, options)
abs_cj_fee = 1.0 * total_cj_fee / taker.n_counterparties
rel_cj_fee = abs_cj_fee / cjamount
log.info('rel/abs average fee = ' + str(rel_cj_fee) + ' / ' + str(
abs_cj_fee))
if rel_cj_fee > options['maxcjfee'][
0] and abs_cj_fee > options['maxcjfee'][1]:
log.info("Rejected fees as too high according to options, will retry.")
return "retry"
return True
def taker_finished(res, fromtx=False, waittime=0.0, txdetails=None): def taker_finished(res, fromtx=False, waittime=0.0, txdetails=None):
"""on_finished_callback for tumbler; processing is almost entirely """on_finished_callback for tumbler; processing is almost entirely

Loading…
Cancel
Save