diff --git a/jmbase/jmbase/commands.py b/jmbase/jmbase/commands.py index 7f00dd6..d0db13f 100644 --- a/jmbase/jmbase/commands.py +++ b/jmbase/jmbase/commands.py @@ -220,3 +220,11 @@ class JMTXReceived(JMCommand): arguments = [(b'nick', Unicode()), (b'txhex', Unicode()), (b'offer', Unicode())] + +class JMTXBroadcast(JMCommand): + """ Accept a bitcoin transaction + sent over the wire by a counterparty + and relay it to the client for network + broadcast. + """ + arguments = [(b'txhex', Unicode())] diff --git a/jmbase/test/test_commands.py b/jmbase/test/test_commands.py index bc43792..12bceca 100644 --- a/jmbase/test/test_commands.py +++ b/jmbase/test/test_commands.py @@ -111,7 +111,9 @@ class JMTestServerProtocol(JMBaseProtocol): hashlen=4, max_encoded=5, hostid="hostid2") - self.defaultCallbacks(d3) + self.defaultCallbacks(d3) + d4 = self.callRemote(JMTXBroadcast, txhex="deadbeef") + self.defaultCallbacks(d4) return {'accepted': True} @@ -216,6 +218,11 @@ class JMTestClientProtocol(JMBaseProtocol): self.defaultCallbacks(d) return {'accepted': True} + @JMTXBroadcast.responder + def on_JM_TX_BROADCAST(self, txhex): + show_receipt("JMTXBROADCAST", txhex) + return {"accepted": True} + class JMTestClientProtocolFactory(protocol.ClientFactory): protocol = JMTestClientProtocol diff --git a/jmclient/jmclient/client_protocol.py b/jmclient/jmclient/client_protocol.py index b580c88..6d6fb5c 100644 --- a/jmclient/jmclient/client_protocol.py +++ b/jmclient/jmclient/client_protocol.py @@ -301,6 +301,22 @@ class JMMakerClientProtocol(JMClientProtocol): self.defaultCallbacks(d) return {"accepted": True} + @commands.JMTXBroadcast.responder + def on_JM_TX_BROADCAST(self, txhex): + """ Makers have no issue broadcasting anything, + so only need to prevent crashes. + Note in particular we don't check the return value, + since the transaction being accepted or not is not + our (maker)'s concern. + """ + try: + txbin = hextobin(txhex) + jm_single().bc_interface.pushtx(txbin) + except: + jlog.info("We received an invalid transaction broadcast " + "request: " + txhex) + return {"accepted": True} + def tx_match(self, txd): for k,v in self.finalized_offers.items(): # Tx considered defined by its output set diff --git a/jmclient/jmclient/taker.py b/jmclient/jmclient/taker.py index cf06cf0..27ce7c6 100644 --- a/jmclient/jmclient/taker.py +++ b/jmclient/jmclient/taker.py @@ -830,8 +830,7 @@ class Taker(object): self.on_finished_callback(False, fromtx=True) else: if nick_to_use: - # TODO option not currently functional - return (nick_to_use, self.latest_tx.serialize()) + return (nick_to_use, bintohex(self.latest_tx.serialize())) #if push was not successful, return None def self_sign_and_push(self): diff --git a/jmdaemon/jmdaemon/daemon_protocol.py b/jmdaemon/jmdaemon/daemon_protocol.py index f6e7544..1967484 100644 --- a/jmdaemon/jmdaemon/daemon_protocol.py +++ b/jmdaemon/jmdaemon/daemon_protocol.py @@ -9,6 +9,7 @@ from .protocol import (COMMAND_PREFIX, ORDER_KEYS, NICK_HASH_LENGTH, COMMITMENT_PREFIXES) from .irc import IRCMessageChannel +from jmbase import hextobin from jmbase.commands import * from twisted.protocols import amp from twisted.internet import reactor, ssl @@ -432,9 +433,16 @@ class JMDaemonServerProtocol(amp.AMP, OrderbookWatch): @maker_only def on_push_tx(self, nick, txhex): - """Not yet implemented; ignore rather than raise. + """Broadcast unquestioningly, except checking + hex format. """ - log.msg('received pushtx message, ignoring, TODO') + try: + dummy = hextobin(txhex) + except: + return + d = self.callRemote(JMTXBroadcast, + txhex=txhex) + self.defaultCallbacks(d) @maker_only def on_seen_tx(self, nick, txhex):