From 5b5512865aa0a360fb3c837faba76cc278ca7505 Mon Sep 17 00:00:00 2001 From: Adam Gibson Date: Fri, 20 Jan 2017 00:06:08 +0700 Subject: [PATCH] Taker can abort the tx and schedule Clean up some stale comments. Small bugfix in cli-options. --- jmclient/jmclient/client_protocol.py | 6 +--- jmclient/jmclient/taker.py | 41 ++++++++++++++++++++-------- scripts/cli_options.py | 1 + scripts/joinmarket-qt.py | 20 ++++++++------ 4 files changed, 43 insertions(+), 25 deletions(-) diff --git a/jmclient/jmclient/client_protocol.py b/jmclient/jmclient/client_protocol.py index 4551a44..2daafba 100644 --- a/jmclient/jmclient/client_protocol.py +++ b/jmclient/jmclient/client_protocol.py @@ -143,7 +143,7 @@ class JMTakerClientProtocol(amp.AMP): """ ioauth_data = json.loads(ioauth_data) if not success: - jlog.info("Makers didnt respond blah blah") + jlog.info("Makers didnt respond") return {'accepted': True} else: jlog.info("Makers responded with: " + json.dumps(ioauth_data)) @@ -179,10 +179,6 @@ class JMTakerClientProtocol(amp.AMP): @commands.JMSigReceived.responder def on_JM_SIG_RECEIVED(self, nick, sig): retval = self.taker.on_sig(nick, sig) - if retval: - #flag indicating completion; but Taker - #handles tx pushing, just update state - self.state = 4 return {'accepted': True} @commands.JMRequestMsgSig.responder diff --git a/jmclient/jmclient/taker.py b/jmclient/jmclient/taker.py index b390c5e..1bbc951 100644 --- a/jmclient/jmclient/taker.py +++ b/jmclient/jmclient/taker.py @@ -22,7 +22,6 @@ jlog = get_log() class JMTakerError(Exception): pass -#Taker is now a class to do 1 coinjoin class Taker(object): def __init__(self, @@ -40,6 +39,7 @@ class Taker(object): 3.on finished callback: called on completion, either of the whole schedule or early if a transactoin fails. """ + self.aborted = False self.wallet = wallet self.schedule = schedule self.order_chooser = order_chooser @@ -52,16 +52,25 @@ class Taker(object): #External callers set the 3 callbacks for filtering orders, #sending info messages to client, and action on completion. #"None" is allowable for taker_info_callback, defaults to log msg. - if callbacks: - """Signature of filter_orders: - args: orders_fees, cjamount - returns: boolean representing accept/reject - """ - self.filter_orders_callback = callbacks[0] - self.taker_info_callback = callbacks[1] - if not self.taker_info_callback: - self.taker_info_callback = self.default_taker_info_callback - self.on_finished_callback = callbacks[2] + #"None" is allowable for filter_orders_callback, in which case offers + #are automatically accepted (bar insane fees). + #"None" is *not* allowable for taker_finished_callback, as it controls + #process flow after tx finished. + """Signature of filter_orders_callback: + args: orders_fees, cjamount + returns: boolean representing accept/reject + """ + self.filter_orders_callback = callbacks[0] + self.taker_info_callback = callbacks[1] + if not self.taker_info_callback: + self.taker_info_callback = self.default_taker_info_callback + """Signature of on_finished_callback: + args: res: True/False to flag success + from_tx: indicating whether all txs finished, or more to do + waittime: how long to wait before continuing to next. + returns: None + """ + self.on_finished_callback = callbacks[2] def default_taker_info_callback(self, infotype, msg): jlog.debug(infotype + ":" + msg) @@ -71,6 +80,8 @@ class Taker(object): select offers, re-initialize variables and prepare a commitment, then send it to the protocol to fill offers. """ + if self.aborted: + return (False,) self.taker_info_callback("INFO", "Received offers from joinmarket pit") #choose the next item in the schedule self.schedule_index += 1 @@ -209,6 +220,8 @@ class Taker(object): makers who responded; this is the completion of phase 1 of the protocol """ + if self.aborted: + return (False, "User aborted") rejected_counterparties = [] #Enough data, but need to authorize against the btc pubkey first. for nick, nickdata in ioauth_data.iteritems(): @@ -363,6 +376,12 @@ class Taker(object): return True def on_sig(self, nick, sigb64): + """Processes transaction signatures from counterparties. + Returns True if all signatures received correctly, else + returns False + """ + if self.aborted: + return False sig = base64.b64decode(sigb64).encode('hex') inserted_sig = False txhex = btc.serialize(self.latest_tx) diff --git a/scripts/cli_options.py b/scripts/cli_options.py index 9b17cd2..2f4e3e7 100644 --- a/scripts/cli_options.py +++ b/scripts/cli_options.py @@ -1,5 +1,6 @@ #! /usr/bin/env python from __future__ import absolute_import, print_function +import random """This exists as a separate module for two reasons: to reduce clutter in main scripts, and (TODO) refactor out diff --git a/scripts/joinmarket-qt.py b/scripts/joinmarket-qt.py index 2a136a5..13ddf8f 100644 --- a/scripts/joinmarket-qt.py +++ b/scripts/joinmarket-qt.py @@ -395,7 +395,7 @@ class SpendTab(QWidget): self.sch_startButton.clicked.connect(self.startMultiple) self.sch_abortButton = QPushButton('Abort') self.sch_abortButton.setEnabled(False) - self.sch_abortButton.clicked.connect(self.giveUp) + self.sch_abortButton.clicked.connect(self.abortTransactions) sch_buttons_box = QGroupBox("Actions") sch_buttons_layout = QVBoxLayout() @@ -430,7 +430,7 @@ class SpendTab(QWidget): buttons.addStretch(1) buttons.addWidget(self.startButton) buttons.addWidget(self.abortButton) - self.abortButton.clicked.connect(self.giveUp) + self.abortButton.clicked.connect(self.abortTransactions) innerTopLayout.addLayout(buttons, len(self.widgets) + 1, 0, 1, 2) splitter1 = QSplitter(QtCore.Qt.Vertical) self.textedit = QTextEdit() @@ -473,7 +473,6 @@ class SpendTab(QWidget): JMQtMessageBox(self, "Cannot start without a loaded wallet.", mbtype="crit", title="Error") return - self.aborted = False if not multiple and not self.validateSettings(): return if jm_single().config.get("BLOCKCHAIN", @@ -544,7 +543,7 @@ class SpendTab(QWidget): def callback_checkOffers(self, offers_fee, cjamount): """Receives the signal from the JMClient thread """ - if self.aborted: + if self.taker.aborted: log.debug("Not processing orders, user has aborted.") return False self.offers_fee = offers_fee @@ -562,8 +561,6 @@ class SpendTab(QWidget): def callback_takerInfo(self, infotype, infomsg): if infotype == "ABORT": - #Abort signal explicitly means this transaction will not continue. - self.giveUp() self.taker_info_type = 'warn' elif infotype == "INFO": self.taker_info_type = 'info' @@ -588,8 +585,10 @@ class SpendTab(QWidget): def takerInfo(self): if self.taker_info_type == "info": w.statusBar().showMessage(self.taker_infomsg) - else: + elif self.taker_info_type == "warn": JMQtMessageBox(self, self.taker_infomsg, mbtype=self.taker_info_type) + #Abort signal explicitly means this transaction will not continue. + self.abortTransactions() self.taker_info_response = True def checkOffers(self): @@ -727,8 +726,11 @@ class SpendTab(QWidget): for b, s in zip(btns, btnsettings): b.setEnabled(s) + def abortTransactions(self): + self.taker.aborted = True + self.giveUp() + def giveUp(self): - self.aborted = True log.debug("Transaction aborted.") self.qtw.setTabEnabled(0, True) self.qtw.setTabEnabled(1, True) @@ -737,7 +739,7 @@ class SpendTab(QWidget): def cleanUp(self): if not self.taker.txid: - if not self.aborted: + if not self.taker.aborted: if not self.taker.ignored_makers: w.statusBar().showMessage("Transaction failed.") JMQtMessageBox(self,