def on_JM_INIT(self, bcsource, network, irc_configs, minmakers, maker_timeout_sec): self.maker_timeout_sec = int(maker_timeout_sec) self.minmakers = int(minmakers) mcs = [DummyMC(None)] self.mcc = MessageChannelCollection(mcs) #The following is a hack to get the counterparties marked seen/active; #note it must happen before callign set_msgchan for OrderbookWatch self.mcc.on_order_seen = None for c in [o['counterparty'] for o in t_orderbook]: self.mcc.on_order_seen_trigger(mcs[0], c, "a", "b", "c", "d", "e", "f") OrderbookWatch.set_msgchan(self, self.mcc) #register taker-specific msgchan callbacks here self.mcc.register_taker_callbacks(self.on_error, self.on_pubkey, self.on_ioauth, self.on_sig) self.mcc.set_daemon(self) self.restart_mc_required = True d = self.callRemote(JMInitProto, nick_hash_length=NICK_HASH_LENGTH, nick_max_encoded=NICK_MAX_ENCODED, joinmarket_nick_header=JOINMARKET_NICK_HEADER, joinmarket_version=JM_VERSION) self.defaultCallbacks(d) return {'accepted': True}
def test_mc_run(failuretype, mcindex, wait): ob = OrderbookWatch() ob.on_welcome = dummy_on_welcome dmcs = [DummyMessageChannel(None, hostid="hostid"+str(x)) for x in range(3)] mcc = MessageChannelCollection(dmcs) #this sets orderbookwatch callbacks ob.set_msgchan(mcc) dummydaemon = DaemonForSigns(mcc) mcc.set_daemon(dummydaemon) #need to override thread run() class FIThread(MChannelThread): def run(self): self.mc.run() fi = FIThread(mcc) fi.start() time.sleep(wait+0.5)
def getmc(nick): dm = DummyDaemon() mc = DummyMC(get_irc_mchannels()[0], nick, dm) mc.register_orderbookwatch_callbacks(on_order_seen=on_order_seen) mc.register_taker_callbacks(on_pubkey=on_pubkey) mc.on_connect = on_connect mc.on_disconnect = on_disconnect mc.on_welcome = on_welcome mcc = MessageChannelCollection([mc]) return dm, mc, mcc
def main(): parser = OptionParser( usage='usage: %prog [options]', description='Runs a webservice which shows the orderbook.') add_base_options(parser) parser.add_option('-H', '--host', action='store', type='string', dest='host', default='localhost', help='hostname or IP to bind to, default=localhost') parser.add_option('-p', '--port', action='store', type='int', dest='port', help='port to listen on, default=62601', default=62601) (options, args) = parser.parse_args() load_program_config(config_path=options.datadir) hostport = (options.host, options.port) mcs = [ObIRCMessageChannel(c) for c in get_irc_mchannels()] mcc = MessageChannelCollection(mcs) mcc.set_nick(get_dummy_nick()) taker = ObBasic(mcc, hostport) log.info("Starting ob-watcher") mcc.run()
def main(): global bond_exponent parser = OptionParser( usage='usage: %prog [options]', description='Runs a webservice which shows the orderbook.') add_base_options(parser) parser.add_option('-H', '--host', action='store', type='string', dest='host', default='localhost', help='hostname or IP to bind to, default=localhost') parser.add_option('-p', '--port', action='store', type='int', dest='port', help='port to listen on, default=62601', default=62601) (options, args) = parser.parse_args() load_program_config(config_path=options.datadir) # needed to display notional units of FB valuation bond_exponent = jm_single().config.get("POLICY", "bond_value_exponent") try: float(bond_exponent) except ValueError: log.error("Invalid entry for bond_value_exponent, should be decimal " "number: {}".format(bond_exponent)) sys.exit(EXIT_FAILURE) check_and_start_tor() hostport = (options.host, options.port) mcs = [] chan_configs = get_mchannels(mode="PASSIVE") for c in chan_configs: if "type" in c and c["type"] == "onion": mcs.append(OnionMessageChannel(c)) else: # default is IRC; TODO allow others mcs.append(IRCMessageChannel(c)) IRCMessageChannel.on_privmsg = on_privmsg OnionMessageChannel.on_privmsg = on_privmsg mcc = MessageChannelCollection(mcs) mcc.set_nick(get_dummy_nick()) taker = ObBasic(mcc, hostport) log.info("Starting ob-watcher") mcc.run()
def main(): parser = OptionParser( usage='usage: %prog [options]', description='Runs a webservice which shows the orderbook.') add_base_options(parser) parser.add_option('-H', '--host', action='store', type='string', dest='host', default='localhost', help='hostname or IP to bind to, default=localhost') parser.add_option('-p', '--port', action='store', type='int', dest='port', help='port to listen on, default=62601', default=62601) (options, args) = parser.parse_args() load_program_config(config_path=options.datadir) check_and_start_tor() hostport = (options.host, options.port) mcs = [] chan_configs = get_mchannels(mode="PASSIVE") for c in chan_configs: if "type" in c and c["type"] == "onion": mcs.append(OnionMessageChannel(c)) else: # default is IRC; TODO allow others mcs.append(IRCMessageChannel(c)) IRCMessageChannel.on_privmsg = on_privmsg OnionMessageChannel.on_privmsg = on_privmsg mcc = MessageChannelCollection(mcs) mcc.set_nick(get_dummy_nick()) taker = ObBasic(mcc, hostport) log.info("Starting ob-watcher") mcc.run()
class JMDaemonTestServerProtocol(JMDaemonServerProtocol): def __init__(self, factory): super(JMDaemonTestServerProtocol, self).__init__(factory) #respondtoioauths should do nothing unless jmstate = 2 self.respondToIoauths(True) #calling on_JM_MAKE_TX should also do nothing in wrong state assert super(JMDaemonTestServerProtocol, self).on_JM_MAKE_TX( 1, 2) == {'accepted': False} #calling on_JM_FILL with negative amount should reject assert super(JMDaemonTestServerProtocol, self).on_JM_FILL( -1000, 2, 3, 4) == {'accepted': False} #checkutxos also does nothing for rejection at the moment self.checkUtxosAccepted(False) #None should be returned requesting a cryptobox for an unknown cp assert self.get_crypto_box_from_nick("notrealcp") == None #does nothing yet self.on_error("dummy error") @JMRequestOffers.responder def on_JM_REQUEST_OFFERS(self): for o in t_orderbook: #counterparty, oid, ordertype, minsize, maxsize,txfee, cjfee): self.on_order_seen(o["counterparty"], o["oid"], o["ordertype"], o["minsize"], o["maxsize"], o["txfee"], o["cjfee"]) return super(JMDaemonTestServerProtocol, self).on_JM_REQUEST_OFFERS() @JMInit.responder def on_JM_INIT(self, bcsource, network, irc_configs, minmakers, maker_timeout_sec): self.maker_timeout_sec = int(maker_timeout_sec) self.minmakers = int(minmakers) mcs = [DummyMC(None)] self.mcc = MessageChannelCollection(mcs) #The following is a hack to get the counterparties marked seen/active; #note it must happen before callign set_msgchan for OrderbookWatch self.mcc.on_order_seen = None for c in [o['counterparty'] for o in t_orderbook]: self.mcc.on_order_seen_trigger(mcs[0], c, "a", "b", "c", "d", "e", "f") OrderbookWatch.set_msgchan(self, self.mcc) #register taker-specific msgchan callbacks here self.mcc.register_taker_callbacks(self.on_error, self.on_pubkey, self.on_ioauth, self.on_sig) self.mcc.set_daemon(self) self.restart_mc_required = True d = self.callRemote(JMInitProto, nick_hash_length=NICK_HASH_LENGTH, nick_max_encoded=NICK_MAX_ENCODED, joinmarket_nick_header=JOINMARKET_NICK_HEADER, joinmarket_version=JM_VERSION) self.defaultCallbacks(d) return {'accepted': True} @JMFill.responder def on_JM_FILL(self, amount, commitment, revelation, filled_offers): tmpfo = json.loads(filled_offers) dummypub = "073732a7ca60470f709f23c602b2b8a6b1ba62ee8f3f83a61e5484ab5cbf9c3d" #trigger invalid on_pubkey conditions reactor.callLater(1, self.on_pubkey, "notrealcp", dummypub) reactor.callLater(2, self.on_pubkey, tmpfo.keys()[0], dummypub + "deadbeef") #trigger invalid on_ioauth condition reactor.callLater(2, self.on_ioauth, "notrealcp", 1, 2, 3, 4, 5) #trigger msg sig verify request operation for a dummy message #currently a pass-through reactor.callLater(1, self.request_signature_verify, "1", "!push abcd abc def", "3", "4", str(tmpfo.keys()[0]), 6, 7, self.mcc.mchannels[0].hostid) #send "valid" onpubkey, onioauth messages for k, v in tmpfo.iteritems(): reactor.callLater(1, self.on_pubkey, k, dummypub) reactor.callLater(2, self.on_ioauth, k, ['a', 'b'], "auth_pub", "cj_addr", "change_addr", "btc_sig") return super(JMDaemonTestServerProtocol, self).on_JM_FILL(amount, commitment, revelation, filled_offers) @JMMakeTx.responder def on_JM_MAKE_TX(self, nick_list, txhex): for n in nick_list: reactor.callLater(1, self.on_sig, n, "dummytxsig") return super(JMDaemonTestServerProtocol, self).on_JM_MAKE_TX(nick_list, txhex)
def test_setup_mc(): ob = OrderbookWatch() ob.on_welcome = dummy_on_welcome dmcs = [ DummyMessageChannel(None, hostid="hostid" + str(x)) for x in range(3) ] mcc = MessageChannelCollection(dmcs) #this sets orderbookwatch callbacks ob.set_msgchan(mcc) #we want to set all the callbacks, maker and taker mcc.register_taker_callbacks(don_error, don_pubkey, don_ioauth, don_sig) mcc.register_maker_callbacks( on_orderbook_requested=don_orderbook_requested, on_order_fill=don_order_fill, on_seen_auth=don_seen_auth, on_seen_tx=don_seen_tx, on_push_tx=don_push_tx, on_commitment_seen=don_commitment_seen, on_commitment_transferred=don_commitment_transferred) mcc.set_nick("testnick") dummydaemon = DaemonForSigns(mcc) mcc.set_daemon(dummydaemon) for mc in dmcs: mc.on_welcome(mc) #instead of calling mcc.run, we'll start threads for mcs manually so we #can probe them for mc in dmcs: MChannelThread(mc).start() for m in dmcs: m.on_pubmsg("testmaker", "!orderbook") #receive invalid pubmsgs for msg in [ "!orderbook!orderbook", "!notacommand a b c", "no command prefix", "!reloffer 0 4000 5000 100" ]: dmcs[2].on_pubmsg("testmaker", msg) mcc.request_orderbook() mcc.pubmsg("outward pubmsg") #now create a verifiable counterparty nick; #to get it into active state, need to receive an orderbook from it cp1 = make_valid_nick() #Simulate order receipt on 2 of 3 msgchans from this nick; #note that it will have its active chan set to mc "1" because that #is the last it was seen on: dmcs[0].on_privmsg(cp1, "!reloffer 0 4000 5000 100 0.2 abc def") dmcs[1].on_privmsg(cp1, "!reloffer 0 4000 5000 100 0.2 abc def") time.sleep(0.5) #send back a response mcc.privmsg(cp1, "fill", "0") #trigger failure to find nick in privmsg mcc.privmsg(cp1 + "XXX", "fill", "0") #trigger check_privmsg decorator mcc.send_error(cp1, "errormsg") mcc.push_tx(cp1, "deadbeef") #kill the chan on which the cp is marked active; #note dummychannel has no actual shutdown (call it anyway), #so change its status manually. dmcs[2].shutdown() mcc.mc_status[dmcs[1]] = 2 time.sleep(0.5) #Flush removes references to inactive channels (in this case dmcs[1]). #Dynamic switching of cp1 should occur to the other seen channel (dmcs[0]). mcc.flush_nicks() #force cp1 to be unseen on mc 0: mcc.unsee_nick(cp1, dmcs[0]) del mcc.active_channels[cp1] #try sending a privmsg again; this time it should just print a warning, #as cp1 is not seen anywhere mcc.send_error(cp1, "error") #simulate order cancels (even though we have none) mcc.cancel_orders([0, 1, 2]) #let cp1 be seen on mc2 without having got into active channels; #note that this is an illegal pubmsg and is ignored for everything *except* #nick_seen (what we need here) dmcs[2].on_pubmsg(cp1, "random") mcc.send_error(cp1, "error") #Try using the proper way of setting up privsmgs #first try without box mcc.prepare_privmsg(cp1, "auth", "a b c") dummydaemon.crypto_boxes[cp1] = ["a", DummyBox()] #now conditions are correct, should succeed: mcc.prepare_privmsg(cp1, "auth", "a b c") #try again but this time there is no active channel del mcc.active_channels[cp1] mcc.prepare_privmsg(cp1, "auth", "a b c") #try announcing orders; first public mcc.announce_orders(t_orderbook) #try on fake mc mcc.announce_orders(t_orderbook, new_mc="fakemc") #direct to one cp mcc.announce_orders(t_orderbook, nick=cp1) #direct to one cp on one mc mcc.announce_orders(t_orderbook, nick=cp1, new_mc=dmcs[0]) #Next, set up 6 counterparties and fill their offers, #send txs to them cps = [make_valid_nick(i) for i in range(1, 7)] #reuse t_chosen_orders data, but swap out the counterparty names offervals = t_chosen_orders.values() new_offers = dict(zip(cps, offervals)) #first, pretend they all showed up on all 3 mcs: for m in dmcs: for cp in cps: m.on_privmsg(cp, "!reloffer 0 400000 500000 100 0.002 abc def") #next, call main fill function mcc.fill_orders(new_offers, 1000, "dummypubkey", "dummycommit") #now send a dummy transaction to this same set. #first fails with no crypto box. mcc.send_tx(cps, "deadbeef") #Now initialize the boxes for c in cps: dummydaemon.crypto_boxes[c] = ["a", DummyBox()] mcc.send_tx(cps, "deadbeef") #try to send the transaction to a wrong cp: mcc.send_tx(["notrealcp"], "deadbeef") #At this stage, dmcs0,2 should be "up" and 1 should have been reset to 1 assert mcc.mc_status[dmcs[0]] == 1 assert mcc.mc_status[dmcs[1]] == 1 assert mcc.mc_status[dmcs[2]] == 1 #Not currently used: #simulate re-connection of dmcs[1] ; note that this code isn't used atm #mcc.on_connect_trigger(dmcs[1]) #assert mcc.mc_status[dmcs[1]] == 1 #Now trigger disconnection code; each mc one by one; the last should trigger #on_disconnect callback for m in dmcs: mcc.on_disconnect_trigger(m) #reconnect; effect is all nick references are flushed for m in dmcs: mcc.on_connect_trigger(m) assert mcc.active_channels == {} #have the cps rearrive for m in dmcs: for cp in cps: m.on_privmsg(cp, "!reloffer 0 4000 5000 100 0.2 abc def") ##################################################################### #next series of messages are to test various normal and abnormal #message receipts under normal connection conditions ##################################################################### #simulate receipt of commitments #valid dmcs[0].on_pubmsg(cps[2], "!hp2 deadbeef") #invalid missing field dmcs[0].on_pubmsg(cps[2], "!hp2") #receive commitment via privmsg to trigger commitment_transferred dmcs[0].on_privmsg(cps[2], "!hp2 deadbeef abc def") #simulate receipt of order cancellation #valid dmcs[0].on_pubmsg(cps[2], "!cancel 2") #invalid oid dmcs[0].on_pubmsg(cps[2], "!cancel x") #too short privmsg (can't even have a signature) dmcs[0].on_privmsg(cps[2], COMMAND_PREFIX) #not using correct protocol start character dmcs[0].on_privmsg(cps[2], "A B C") #unrecognized command dmcs[0].on_privmsg(cps[2], "!fakecommand A B C D") #Perhaps dubious, but currently msg after command must be non-zero dmcs[0].on_privmsg(cps[2], "!reloffer sig1 sig2") #Simulating receipt of encrypted messages: #ioauth dummy_on_ioauth_msg = b"deadbeef:0,deadbeef:1 XauthpubX XcjaddrX XchangeaddrX XbtcsigX" b64dummyioauth = base64.b64encode(dummy_on_ioauth_msg).decode('ascii') dmcs[0].on_privmsg(cps[3], "!ioauth " + b64dummyioauth + " sig1 sig2") #Try with a garbage b64 (but decodable); should throw index error at least dmcs[0].on_privmsg(cps[3], "!ioauth _*_ sig1 sig2") #Try also for receipt from an unknown counterparty; should fail with no enc box dmcs[0].on_privmsg("notrealcp", "!ioauth " + b64dummyioauth + " sig1 sig2") #Try same message from valid cp but with corrupted b64 b64dummyioauth = "999" dmcs[0].on_privmsg(cps[3], "!ioauth " + b64dummyioauth + " sig1 sig2") #sig dummy_on_sig_msg = b"dummysig" b64dummysig = base64.b64encode(dummy_on_sig_msg).decode('ascii') dmcs[0].on_privmsg(cps[3], "!sig " + b64dummysig + " sig1 sig2") #auth dummy_auth_msg = b"dummyauth" b64dummyauth = base64.b64encode(dummy_auth_msg).decode('ascii') dmcs[0].on_privmsg(cps[2], "!auth " + b64dummyauth + " sig1 sig2") #invalid auth (only no message is invalid) dmcs[0].on_privmsg( cps[3], "!auth " + base64.b64encode(b"").decode('ascii') + " sig1 sig2") #tx #valid dummy_tx = b"deadbeefdeadbeef" b64dummytx = base64.b64encode(dummy_tx) b642dummytx = base64.b64encode(b64dummytx).decode('ascii') dmcs[0].on_privmsg(cps[2], "!tx " + b642dummytx + " sig1 sig2") badbase64tx = b"999" badbase64tx2 = base64.b64encode(badbase64tx).decode('ascii') #invalid txhex; here the first round will work (msg decryption), second shouldn't dmcs[0].on_privmsg(cps[2], "!tx " + badbase64tx2 + " sig1 sig2") #push #valid dmcs[0].on_privmsg(cps[2], "!push " + b642dummytx + " sig1 sig2") #invalid dmcs[0].on_privmsg(cps[2], "!push 999 sig1 sig2") #fill #valid, no commit dmcs[0].on_privmsg(cps[4], "!fill 0 4000 dummypub sig1 sig2") #valid with commit dmcs[0].on_privmsg(cps[4], "!fill 0 4000 dummypub dummycommit sig1 sig2") #invalid length dmcs[0].on_privmsg(cps[4], "!fill 0 sig1 sig2") #pubkey dmcs[0].on_privmsg(cps[4], "!pubkey dummypub sig1 sig2") ############################################################## #End message receipts ############################################################## #simulate loss of conncetion to cp[0] for m in dmcs[::-1]: mcc.on_nick_leave_trigger(cps[0], m) #call onnickleave for something not in the ac list mcc.on_nick_leave_trigger("notrealcp", dmcs[0]) #make mcs 0,1 go down so that when cp[1] tries to dynamic switch, it fails mcc.on_disconnect_trigger(dmcs[0]) mcc.on_disconnect_trigger(dmcs[1]) mcc.on_nick_leave_trigger(cps[1], dmcs[2]) mcc.shutdown()