Skip to content

Commit

Permalink
Delay !auth sending until all makers receive !fill
Browse files Browse the repository at this point in the history
Prior to this commit, in scenarios of very big latency differentials
between maker bots, it was possible for one maker to complete the
conversation up to !ioauth and broadcast the commitment, before another
maker had even received the !fill message. This causes incorrect local
blacklisting of commitments for that (and any other slow) maker.
After this commit, the taker does not continue Phase1 with the !auth
message, until either (a) all of the makers have sent their !pubkey
message (indicating that they have already seen the commitment in the
!fill message), or (b) a timeout of 60 seconds (after which any maker
that has not sent the !pubkey is ignored for the rest of the
conversation).
  • Loading branch information
AdamISZ committed Nov 22, 2023
1 parent d779132 commit dad3bb6
Show file tree
Hide file tree
Showing 2 changed files with 20 additions and 9 deletions.
28 changes: 19 additions & 9 deletions src/jmdaemon/daemon_protocol.py
Original file line number Diff line number Diff line change
Expand Up @@ -471,6 +471,8 @@ def process_proposals_response_from_server(self, response_body, server):

class JMDaemonServerProtocol(amp.AMP, OrderbookWatch):

PHASE_1A_DELAY = 60.0

def __init__(self, factory):
self.factory = factory
self.jm_state = 0
Expand All @@ -485,6 +487,10 @@ def __init__(self, factory):
self.use_fidelity_bond = False
self.offerlist = None
self.kp = None
# keeps track of whether we are ready to send !auth as taker:
# 0: no !pubkey received; 1: at least 1 !pubkey received,
# 2: either all !pubkey messages received, or timed out
self.phase_1a_state = 0

def checkClientResponse(self, response):
"""A generic check of client acceptance; any failure
Expand Down Expand Up @@ -876,14 +882,14 @@ def on_pubkey(self, nick, maker_pk):
# We have a time-out of 60 seconds after which a received
# pubkey message is too delayed; if we receive that here we
# have to just ignore the counterparty.
if "auth_sent" in self.active_orders.keys():
if self.phase_1a_state == 2:
return
# by the same token, as soon as we have received at least
# one !pubkey message, we start the countdown (60s) to just
# going ahead:
if not "taker_waiting_for_pubkey" in self.active_orders.keys():
reactor.callLater(60.0, self.send_all_auth)
self.active_orders["taker_waiting_for_pubkey"] = True
if self.phase_1a_state == 0:
reactor.callLater(self.PHASE_1A_DELAY, self.send_all_auth)
self.phase_1a_state = 1
if nick not in self.active_orders.keys():
log.msg("Counterparty not part of this transaction. Ignoring")
return
Expand Down Expand Up @@ -913,17 +919,19 @@ def send_all_auth(self, force:bool =False) -> None:
other makers in the `active_orders` dict to be unreachable,
and ignore them for the rest of the coinjoin construction.
"""
if not all(["received_pubkey" in x
if not all(["received_pubkey" in self.active_orders[x]
for x in self.active_orders]) and not force:
return
# the laggards should be wiped out from the dict, in order to
# continue phase 2 cleanly:
l = [k for k in self.active_orders
if "received_pubkey" in self.active_orders[k]]
self.active_orders = {k: self.active_orders[k] for k in l}
if force:
l = [k for k in self.active_orders
if "received_pubkey" in self.active_orders[k]]
self.active_orders = dict([(k,
self.active_orders[k]) for k in l])
for nick in self.active_orders:
self.mcc.prepare_privmsg(nick, "auth", str(self.revelation))
self.active_orders["auth_sent"] = True
self.phase_1a_state = 2

@taker_only
def on_ioauth(self, nick, utxo_list, auth_pub, cj_addr, change_addr,
Expand Down Expand Up @@ -1033,6 +1041,8 @@ def respondToIoauths(self, accepted):
#do nothing
return
self.jm_state = 3
# allow future phase1-s to occur:
self.phase_1a_state = 0
if not accepted:
#use ioauth data field to return the list of non-responsive makers
nonresponders = [x for x in self.active_orders
Expand Down
1 change: 1 addition & 0 deletions test/jmdaemon/test_daemon_protocol.py
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,7 @@ def end_test():
class JMDaemonTestServerProtocol(JMDaemonServerProtocol):

def __init__(self, factory):
self.PHASE_1A_DELAY = 6.0 # quick for testing
super().__init__(factory)
#respondtoioauths should do nothing unless jmstate = 2
self.respondToIoauths(True)
Expand Down

0 comments on commit dad3bb6

Please sign in to comment.