From 1597b75b006a996b9d942b33a6050e9c6a32d667 Mon Sep 17 00:00:00 2001 From: Adam Gibson Date: Thu, 24 Nov 2016 17:08:06 +0200 Subject: [PATCH] Bugfix in taker sign_tx for "wallet" type. Re-add needed encode/decode fns in btc.py joinmarketd now has correct logic for timeout of on_ioauth wait. --- jmclient/btc.py | 38 +++++++++++++++++++++++++++++++++- jmclient/taker.py | 2 +- scripts/joinmarketd.py | 46 +++++++++++++++++++++--------------------- 3 files changed, 61 insertions(+), 25 deletions(-) diff --git a/jmclient/btc.py b/jmclient/btc.py index 657d105..5694ced 100644 --- a/jmclient/btc.py +++ b/jmclient/btc.py @@ -28,7 +28,43 @@ except ImportError: raise NotImplementedError not_supported_string = "not supported by: " + interface - + + # Base switching + code_strings = { + 2: '01', + 10: '0123456789', + 16: '0123456789abcdef', + 32: 'abcdefghijklmnopqrstuvwxyz234567', + 58: '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz', + 256: ''.join([chr(x) for x in range(256)]) + } + def get_code_string(base): + if base in code_strings: + return code_strings[base] + else: + raise ValueError("Invalid base!") + + def encode(val, base, minlen=0): + base, minlen = int(base), int(minlen) + code_string = get_code_string(base) + result = "" + while val > 0: + result = code_string[val % base] + result + val //= base + return code_string[0] * max(minlen - len(result), 0) + result + + def decode(string, base): + base = int(base) + code_string = get_code_string(base) + result = 0 + if base == 16: + string = string.lower() + while len(string) > 0: + result *= base + result += code_string.find(string[0]) + string = string[1:] + return result + #Electrum specific code starts here import electrum.bitcoin as ebt import electrum.transaction as etr diff --git a/jmclient/taker.py b/jmclient/taker.py index 5e48f10..3e9b6f2 100644 --- a/jmclient/taker.py +++ b/jmclient/taker.py @@ -591,7 +591,7 @@ class Taker(object): if utxo not in self.input_utxos.keys(): continue addrs[index] = self.input_utxos[utxo]['address'] - tx = self.wallet.sign_tx(btc.serialize(wallet_tx), addrs) + tx = self.wallet.sign_tx(tx, addrs) else: for index, ins in enumerate(self.latest_tx['ins']): utxo = ins['outpoint']['hash'] + ':' + str(ins['outpoint']['index']) diff --git a/scripts/joinmarketd.py b/scripts/joinmarketd.py index cf8f69b..18374d9 100644 --- a/scripts/joinmarketd.py +++ b/scripts/joinmarketd.py @@ -157,7 +157,7 @@ class JMDaemonServerProtocol(amp.AMP, OrderbookWatch): rows = self.db.execute('SELECT * FROM orderbook;').fetchall() self.orderbook = [dict([(k, o[k]) for k in ORDER_KEYS]) for o in rows] log.msg("About to send orderbook of size: " + str(len(self.orderbook))) - string_orderbook = json.dumps(self.orderbook) + string_orderbook = json.dumps(self.orderbook[:100]) d = self.callRemote(JMOffers, orderbook=string_orderbook) d.addCallback(self.checkClientResponse) @@ -177,7 +177,7 @@ class JMDaemonServerProtocol(amp.AMP, OrderbookWatch): offer_fill_msg = " ".join([str(offer_dict["oid"]), str(amount), str( self.kp.hex_pk()), str(commitment)]) self.mcc.prepare_privmsg(nick, "fill", offer_fill_msg) - self.first_stage_timer = time.time() + reactor.callLater(self.maker_timeout_sec, self.completeStage1) self.jm_state = 2 return {'accepted': True} @@ -203,34 +203,34 @@ class JMDaemonServerProtocol(amp.AMP, OrderbookWatch): they've all been received; note that we must also pass back the maker_pk so it can be verified against the btc-sigs for anti-MITM """ - def respond(accepted): - d = self.callRemote(JMFillResponse, - success=accepted, - ioauth_data = json.dumps(self.ioauth_data)) - if not accepted: - #Client simply accepts failure TODO - d.addCallback(self.checkClientResponse) - else: - #Act differently if *we* provided utxos, but - #client does not accept for some reason - d.addCallback(self.checkUtxosAccepted) - if nick not in self.active_orders.keys(): print("Got an unexpected ioauth from nick: " + str(nick)) return self.ioauth_data[nick] = [utxo_list, auth_pub, cj_addr, change_addr, btc_sig, self.crypto_boxes[nick][0]] if self.ioauth_data.keys() == self.active_orders.keys(): - respond(True) + #Finish early if we got all + self.respondToIoauths(True) + + def respondToIoauths(self, accepted): + d = self.callRemote(JMFillResponse, + success=accepted, + ioauth_data = json.dumps(self.ioauth_data)) + if not accepted: + #Client simply accepts failure TODO + d.addCallback(self.checkClientResponse) else: - time_taken = time.time() - self.first_stage_timer - #if the timer has run out, either pass through if we have - #at least minmakers, else return a failure condition - if time_taken > self.maker_timeout_sec: - if len(self.ioauth_data.keys()) >= self.minmakers: - respond(True) - else: - respond(False) + #Act differently if *we* provided utxos, but + #client does not accept for some reason + d.addCallback(self.checkUtxosAccepted) + + def completeStage1(self): + """Timeout of stage 1 requests; + either send success + ioauth data if enough makers, + else send failure to client. + """ + response = True if len(self.ioauth_data.keys()) >= self.minmakers else False + self.respondToIoauths(response) def checkUtxosAccepted(self, accepted): if not accepted: