From 3602b93e1be320d9a5d4612358743d20d5657a12 Mon Sep 17 00:00:00 2001 From: AdamISZ Date: Mon, 8 Jul 2019 17:06:03 -0300 Subject: [PATCH] Restarting tumbler waits on gettransaction not gettxout Fixes #362. Prior to this commit, if tumbler was invoked with the --restart flag, it waited for the presence of the 0 index output of the last seen tumbler transaction in the utxo set, which was an unreliable indicator as that output could have, in the meantime, been spent. After this commit, we utilise the fact that the transaction must be an in-wallet transaction, and use the rpc gettransaction to check whether it has 1 or more confirmations, instead, which should always work whether any outputs are spent or not. --- jmclient/jmclient/taker_utils.py | 26 +++++++++++++++++++------- scripts/joinmarket-qt.py | 2 +- scripts/tumbler.py | 2 +- 3 files changed, 21 insertions(+), 9 deletions(-) diff --git a/jmclient/jmclient/taker_utils.py b/jmclient/jmclient/taker_utils.py index 516d4e9..57b4e40 100644 --- a/jmclient/jmclient/taker_utils.py +++ b/jmclient/jmclient/taker_utils.py @@ -134,16 +134,28 @@ def get_tumble_log(logsdir): return tumble_log def restart_wait(txid): - """Here txid is of form txid:N for direct utxo query. - Returns true only if the utxo is reported to have at least 1 - confirm by the blockchain interface. + """ Returns true only if the transaction txid is seen in the wallet, + and confirmed (it must be an in-wallet transaction since it always + spends coins from the wallet). """ - res = jm_single().bc_interface.query_utxo_set(txid, includeconf=True) - if not res[0]: + try: + res = jm_single().bc_interface.rpc('gettransaction', [txid, True]) + except JsonRpcError as e: return False - if res[0]['confirms'] > 0: + if not res: + return False + if "confirmations" not in res: + log.debug("Malformed gettx result: " + str(res)) + return False + if res["confirmations"] == 0: + return False + if res["confirmations"] < 0: + log.warn("Tx: " + txid + " has a conflict, abandoning.") + sys.exit(0) + else: + log.debug("Tx: " + str(txid) + " has " + str( + res["confirmations"]) + " confirmations.") return True - return False def restart_waiter(txid): """Given a txid, wait for confirmation by polling the blockchain diff --git a/scripts/joinmarket-qt.py b/scripts/joinmarket-qt.py index 9676017..368d55c 100644 --- a/scripts/joinmarket-qt.py +++ b/scripts/joinmarket-qt.py @@ -582,7 +582,7 @@ class SpendTab(QWidget): #since we already updated state to running, user cannot #start another transactions while waiting. Also, use :0 because #it always exists - self.waitingtxid=txid+":0" + self.waitingtxid=txid self.restartTimer.timeout.connect(self.restartWaitWrap) self.restartTimer.start(5000) return diff --git a/scripts/tumbler.py b/scripts/tumbler.py index 04d3d3b..2c0d7ee 100644 --- a/scripts/tumbler.py +++ b/scripts/tumbler.py @@ -72,7 +72,7 @@ def main(): #ensure last transaction is confirmed before restart tumble_log.info("WAITING TO RESTART...") txid = schedule[0][5] - restart_waiter(txid + ":0") #add 0 index because all have it + restart_waiter(txid) #remove the already-done entry (this connects to the other TODO, #probably better *not* to truncate the done-already txs from file, #but simplest for now.