diff --git a/jmbase/jmbase/commands.py b/jmbase/jmbase/commands.py index da97763..ed62e29 100644 --- a/jmbase/jmbase/commands.py +++ b/jmbase/jmbase/commands.py @@ -52,6 +52,10 @@ class JMMakeTx(JMCommand): arguments = [('nick_list', String()), ('txhex', String())] +class JMPushTx(JMCommand): + arguments = [('nick', String()), + ('txhex', String())] + class JMMsgSignature(JMCommand): arguments = [('nick', String()), ('cmd', String()), diff --git a/jmclient/jmclient/client_protocol.py b/jmclient/jmclient/client_protocol.py index bee40c4..30219e8 100644 --- a/jmclient/jmclient/client_protocol.py +++ b/jmclient/jmclient/client_protocol.py @@ -225,6 +225,9 @@ class JMTakerClientProtocol(amp.AMP): @commands.JMSigReceived.responder def on_JM_SIG_RECEIVED(self, nick, sig): retval = self.taker.on_sig(nick, sig) + if retval: + nick_to_use, txhex = retval + self.push_tx(nick_to_use, txhex) return {'accepted': True} @commands.JMRequestMsgSig.responder @@ -273,6 +276,10 @@ class JMTakerClientProtocol(amp.AMP): txhex=txhex) self.defaultCallbacks(d) + def push_tx(self, nick_to_push, txhex_to_push): + d = self.callRemote(commands.JMPushTx, nick=str(nick_to_push), + txhex=str(txhex_to_push)) + self.defaultCallbacks(d) class JMTakerClientProtocolFactory(protocol.ClientFactory): protocol = JMTakerClientProtocol diff --git a/jmclient/jmclient/configure.py b/jmclient/jmclient/configure.py index 3612784..78c965c 100644 --- a/jmclient/jmclient/configure.py +++ b/jmclient/jmclient/configure.py @@ -171,11 +171,10 @@ absurd_fee_per_kb = 150000 # spends from unconfirmed inputs, which may then get malleated or double-spent! # other counterparties are likely to reject unconfirmed inputs... don't do it. -#options: self, random-peer, not-self, random-maker +#options: self, random-peer, not-self (note: random-maker is not currently supported). # self = broadcast transaction with your own ip # random-peer = everyone who took part in the coinjoin has a chance of broadcasting # not-self = never broadcast with your own ip -# random-maker = every peer on joinmarket has a chance of broadcasting, including yourself tx_broadcast = self minimum_makers = 2 #THE FOLLOWING SETTINGS ARE REQUIRED TO DEFEND AGAINST SNOOPERS. diff --git a/jmclient/jmclient/taker.py b/jmclient/jmclient/taker.py index 9ae6e0f..f65e1c1 100644 --- a/jmclient/jmclient/taker.py +++ b/jmclient/jmclient/taker.py @@ -480,8 +480,7 @@ class Taker(object): jlog.debug('all makers have sent their signatures') self.taker_info_callback("INFO", "Transaction is valid, signing..") jlog.debug("schedule item was: " + str(self.schedule[self.schedule_index])) - self.self_sign_and_push() - return True + return self.self_sign_and_push() def make_commitment(self): """The Taker default commitment function, which uses PoDLE. @@ -629,13 +628,34 @@ class Taker(object): jlog.debug('\n' + tx) self.txid = btc.txhash(tx) jlog.debug('txid = ' + self.txid) - pushed = jm_single().bc_interface.pushtx(tx) + tx_broadcast = jm_single().config.get('POLICY', 'tx_broadcast') + nick_to_use = None + if tx_broadcast == 'self': + pushed = jm_single().bc_interface.pushtx(tx) + elif tx_broadcast in ['random-peer', 'not-self']: + n = len(self.maker_utxo_data) + if tx_broadcast == 'random-peer': + i = random.randrange(n + 1) + else: + i = random.randrange(n) + if i == n: + pushed = jm_single().bc_interface.pushtx(tx) + else: + nick_to_use = self.maker_utxo_data.keys()[i] + pushed = True + else: + jlog.info("Only self, random-peer and not-self broadcast " + "methods supported. Reverting to self-broadcast.") + pushed = jm_single().bc_interface.pushtx(tx) if not pushed: self.on_finished_callback(False, fromtx=True) else: jm_single().bc_interface.add_tx_notify( self.latest_tx, self.unconfirm_callback, self.confirm_callback, self.my_cj_addr) + if nick_to_use: + return (nick_to_use, tx) + #if push was not successful, return None def self_sign_and_push(self): self.self_sign() diff --git a/jmclient/test/test_client_protocol.py b/jmclient/test/test_client_protocol.py index afd013d..de5ab24 100644 --- a/jmclient/test/test_client_protocol.py +++ b/jmclient/test/test_client_protocol.py @@ -74,7 +74,7 @@ class DummyTaker(Taker): """ jlog.debug("We got a sig: " + sigb64) end_test() - return True + return None class JMBaseProtocol(amp.AMP): diff --git a/jmdaemon/jmdaemon/daemon_protocol.py b/jmdaemon/jmdaemon/daemon_protocol.py index 140cde9..fc8c81b 100644 --- a/jmdaemon/jmdaemon/daemon_protocol.py +++ b/jmdaemon/jmdaemon/daemon_protocol.py @@ -308,6 +308,11 @@ class JMDaemonServerProtocol(amp.AMP, OrderbookWatch): hostid=hostid) self.defaultCallbacks(d) + @JMPushTx.responder + def on_JM_PushTx(self, nick, txhex): + self.mcc.push_tx(nick, txhex) + return {'accepted': True} + @JMMsgSignature.responder def on_JM_MSGSIGNATURE(self, nick, cmd, msg_to_return, hostid): self.mcc.privmsg(nick, cmd, msg_to_return, mc=hostid) diff --git a/jmdaemon/jmdaemon/message_channel.py b/jmdaemon/jmdaemon/message_channel.py index 0184e16..245f783 100644 --- a/jmdaemon/jmdaemon/message_channel.py +++ b/jmdaemon/jmdaemon/message_channel.py @@ -344,7 +344,8 @@ class MessageChannelCollection(object): #TODO supporting sending to arbitrary nicks #adds quite a bit of complexity, not supported #initially; will fail if nick is not part of TX - self.active_channels[nick].push_tx(nick, txhex) + txb64 = base64.b64encode(txhex.decode('hex')) + self.prepare_privmsg(nick, "push", txb64) def send_tx(self, nick_list, txhex): """Push out the transaction to nicks