Browse Source

persist ignored_makers in Qt app; rationalize cleanUp()

Modify tooltip for Start button to explain Abort
Retrieve nonresponsive makers in daemon and pass to client
Taker receives ignored_makers in init and client adds
master
Adam Gibson 9 years ago
parent
commit
1e49bf4ec3
No known key found for this signature in database
GPG Key ID: B3AE09F1E9A3197A
  1. 4
      jmclient/jmclient/client_protocol.py
  2. 10
      jmclient/jmclient/taker.py
  3. 7
      jmdaemon/jmdaemon/daemon_protocol.py
  4. 71
      scripts/joinmarket-qt.py

4
jmclient/jmclient/client_protocol.py

@ -180,7 +180,9 @@ class JMTakerClientProtocol(amp.AMP):
""" """
ioauth_data = json.loads(ioauth_data) ioauth_data = json.loads(ioauth_data)
if not success: if not success:
jlog.info("Makers didnt respond") nonresponders = ioauth_data
jlog.info("Makers didnt respond: " + str(nonresponders))
self.taker.add_ignored_makers(nonresponders)
return {'accepted': True} return {'accepted': True}
else: else:
jlog.info("Makers responded with: " + json.dumps(ioauth_data)) jlog.info("Makers responded with: " + json.dumps(ioauth_data))

10
jmclient/jmclient/taker.py

@ -30,7 +30,8 @@ class Taker(object):
order_chooser=weighted_order_choose, order_chooser=weighted_order_choose,
sign_method=None, sign_method=None,
callbacks=None, callbacks=None,
tdestaddrs=[]): tdestaddrs=None,
ignored_makers=None):
"""Schedule must be a list of tuples: (see sample_schedule_for_testnet """Schedule must be a list of tuples: (see sample_schedule_for_testnet
for explanation of syntax, also schedule.py module in this directory), for explanation of syntax, also schedule.py module in this directory),
which will be a sequence of joins to do. which will be a sequence of joins to do.
@ -76,11 +77,11 @@ class Taker(object):
self.wallet = wallet self.wallet = wallet
self.schedule = schedule self.schedule = schedule
self.order_chooser = order_chooser self.order_chooser = order_chooser
self.ignored_makers = None self.ignored_makers = [] if not ignored_makers else ignored_makers
self.waiting_for_conf = False self.waiting_for_conf = False
self.txid = None self.txid = None
self.schedule_index = -1 self.schedule_index = -1
self.tdestaddrs = tdestaddrs self.tdestaddrs = [] if not tdestaddrs else tdestaddrs
#allow custom wallet-based clients to use their own signing code; #allow custom wallet-based clients to use their own signing code;
#currently only setting "wallet" is allowed, calls wallet.sign_tx(tx) #currently only setting "wallet" is allowed, calls wallet.sign_tx(tx)
self.sign_method = sign_method self.sign_method = sign_method
@ -93,6 +94,9 @@ class Taker(object):
def default_taker_info_callback(self, infotype, msg): def default_taker_info_callback(self, infotype, msg):
jlog.debug(infotype + ":" + msg) jlog.debug(infotype + ":" + msg)
def add_ignored_makers(self, makers):
self.ignored_makers.extend(makers)
def initialize(self, orderbook): def initialize(self, orderbook):
"""Once the daemon is active and has returned the current orderbook, """Once the daemon is active and has returned the current orderbook,
select offers, re-initialize variables and prepare a commitment, select offers, re-initialize variables and prepare a commitment,

7
jmdaemon/jmdaemon/daemon_protocol.py

@ -224,9 +224,14 @@ class JMDaemonServerProtocol(amp.AMP, OrderbookWatch):
#do nothing #do nothing
return return
self.jm_state = 3 self.jm_state = 3
if not accepted:
#use ioauth data field to return the list of non-responsive makers
nonresponders = [x for x in self.active_orders.keys() if x not
in self.ioauth_data.keys()]
ioauth_data = self.ioauth_data if accepted else nonresponders
d = self.callRemote(JMFillResponse, d = self.callRemote(JMFillResponse,
success=accepted, success=accepted,
ioauth_data = json.dumps(self.ioauth_data)) ioauth_data = json.dumps(ioauth_data))
if not accepted: if not accepted:
#Client simply accepts failure TODO #Client simply accepts failure TODO
self.defaultCallbacks(d) self.defaultCallbacks(d)

71
scripts/joinmarket-qt.py

@ -466,9 +466,11 @@ class SpendTab(QWidget):
lambda: checkAddress(self, self.widgets[0][1].text())) lambda: checkAddress(self, self.widgets[0][1].text()))
self.startButton = QPushButton('Start') self.startButton = QPushButton('Start')
self.startButton.setToolTip( self.startButton.setToolTip(
'You will be prompted to decide whether to accept\n' + 'If "checktx" is selected in the Settings, you will be \n'
'the transaction after connecting, and shown the\n' + 'prompted to decide whether to accept\n'
'fees to pay; you can cancel at that point if you wish.') 'the transaction after connecting, and shown the\n'
'fees to pay; you can cancel at that point, or by \n'
'pressing "Abort".')
self.startButton.clicked.connect(self.startSingle) self.startButton.clicked.connect(self.startSingle)
self.abortButton = QPushButton('Abort') self.abortButton = QPushButton('Abort')
self.abortButton.setEnabled(False) self.abortButton.setEnabled(False)
@ -587,7 +589,7 @@ class SpendTab(QWidget):
self.spendstate.updateRun('running') self.spendstate.updateRun('running')
self.startJoin() self.startJoin()
def startJoin(self, ignored_makers=None): def startJoin(self):
if not w.wallet: if not w.wallet:
JMQtMessageBox(self, "Cannot start without a loaded wallet.", JMQtMessageBox(self, "Cannot start without a loaded wallet.",
mbtype="crit", title="Error") mbtype="crit", title="Error")
@ -624,20 +626,21 @@ class SpendTab(QWidget):
callbacks=[check_offers_callback, callbacks=[check_offers_callback,
self.callback_takerInfo, self.callback_takerInfo,
self.callback_takerFinished], self.callback_takerFinished],
tdestaddrs=destaddrs) tdestaddrs=destaddrs,
if ignored_makers: ignored_makers=ignored_makers)
self.taker.ignored_makers.extend(ignored_makers)
if not self.clientfactory: if not self.clientfactory:
#First run means we need to start: create clientfactory #First run means we need to start: create clientfactory
#and start reactor Thread #and start reactor Thread
self.clientfactory = JMTakerClientProtocolFactory(self.taker) self.clientfactory = JMTakerClientProtocolFactory(self.taker)
thread = TaskThread(self) thread = TaskThread(self)
daemon = jm_single().config.getint("DAEMON", "no_daemon")
daemon = True if daemon == 1 else False
thread.add(partial(start_reactor, thread.add(partial(start_reactor,
"localhost", "localhost",
jm_single().config.getint("GUI", "daemon_port"), jm_single().config.getint("GUI", "daemon_port"),
self.clientfactory, self.clientfactory,
ish=False, ish=False,
daemon=True)) daemon=daemon))
else: else:
#This will re-use IRC connections in background (daemon), no restart #This will re-use IRC connections in background (daemon), no restart
self.clientfactory.getClient().taker = self.taker self.clientfactory.getClient().taker = self.taker
@ -830,7 +833,9 @@ class SpendTab(QWidget):
else: else:
msg = "All transactions have been confirmed." msg = "All transactions have been confirmed."
JMQtMessageBox(self, msg, title="Success") JMQtMessageBox(self, msg, title="Success")
self.cleanUp() self.cleanUp()
else:
self.giveUp()
def persistTxToHistory(self, addr, amt, txid): def persistTxToHistory(self, addr, amt, txid):
#persist the transaction to history #persist the transaction to history
@ -874,44 +879,21 @@ class SpendTab(QWidget):
self.giveUp() self.giveUp()
def giveUp(self): def giveUp(self):
"""Inform the user that the transaction failed, then reset state.
"""
log.debug("Transaction aborted.") log.debug("Transaction aborted.")
self.qtw.setTabEnabled(0, True)
self.qtw.setTabEnabled(1, True)
self.spendstate.reset()
self.tumbler_options = None
self.tumbler_destaddrs = None
w.statusBar().showMessage("Transaction aborted.") w.statusBar().showMessage("Transaction aborted.")
if len(self.taker.ignored_makers) > 0:
JMQtMessageBox(self, "These Makers did not respond, and will be \n"
"ignored in future: \n" + str(
','.join(self.taker.ignored_makers)),
title="Transaction aborted")
ignored_makers.extend(self.taker.ignored_makers)
self.cleanUp()
def cleanUp(self): def cleanUp(self):
if not self.taker.txid: """Reset state to 'ready'
if not self.taker.aborted: """
if not self.taker.ignored_makers:
w.statusBar().showMessage("Transaction failed.")
JMQtMessageBox(self,
"Transaction was not completed.",
mbtype='warn',
title="Failed")
else:
reply = JMQtMessageBox(
self,
'\n'.join([
"The following counterparties did not respond: ",
','.join(self.taker.ignored_makers),
"This sometimes happens due to bad network connections.",
"",
"If you would like to try again, ignoring those",
"counterparties, click Yes."
]),
mbtype='question',
title="Transaction not completed.")
if reply == QMessageBox.Yes:
self.startJoin(
ignored_makers=self.taker.ignored_makers)
else:
self.giveUp()
return
self.qtw.setTabEnabled(0, True)
self.qtw.setTabEnabled(1, True)
self.spendstate.reset() self.spendstate.reset()
self.tumbler_options = None self.tumbler_options = None
self.tumbler_destaddrs = None self.tumbler_destaddrs = None
@ -1590,7 +1572,8 @@ for dname in ['logs', 'wallets', 'cmtdata']:
logsdir = os.path.join(os.path.dirname(jm_single().config_location), "logs") logsdir = os.path.join(os.path.dirname(jm_single().config_location), "logs")
#tumble log will not always be used, but is made available anyway: #tumble log will not always be used, but is made available anyway:
tumble_log = get_tumble_log(logsdir) tumble_log = get_tumble_log(logsdir)
#ignored makers list persisted across entire app run
ignored_makers = []
appWindowTitle = 'JoinMarketQt' appWindowTitle = 'JoinMarketQt'
w = JMMainWindow() w = JMMainWindow()
tabWidget = QTabWidget(w) tabWidget = QTabWidget(w)

Loading…
Cancel
Save