You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

246 lines
8.9 KiB

#! /usr/bin/env python
from __future__ import absolute_import
'''test client-protocol interfacae.'''
import pytest
from jmclient import (get_schedule, load_program_config, start_reactor,
Taker, get_log, JMTakerClientProtocolFactory, jm_single)
from jmclient.client_protocol import JMProtocolError, JMTakerClientProtocol
import os
from twisted.python.log import startLogging, err
from twisted.python.log import msg as tmsg
from twisted.internet import protocol, reactor
from twisted.internet.error import (ConnectionLost, ConnectionAborted,
ConnectionClosed, ConnectionDone)
from twisted.protocols.amp import UnknownRemoteError
from twisted.python import failure
from twisted.protocols import amp
from jmbase.commands import *
from taker_test_data import t_raw_signed_tx
import json
import time
import jmbitcoin as bitcoin
test_completed = False
clientfactory = None
runno = 0
jlog = get_log()
class DummyTaker(Taker):
def set_fail_init(self, val):
self.failinit = val
def set_fail_utxos(self, val):
self.failutxos = val
def default_taker_info_callback(self, infotype, msg):
jlog.debug(infotype + ":" + msg)
def initialize(self, orderbook):
"""Once the daemon is active and has returned the current orderbook,
select offers, re-initialize variables and prepare a commitment,
then send it to the protocol to fill offers.
"""
if self.failinit==-1:
return (True, -1, "aa"*32, {'dummy':'revelation'},orderbook[:2])
elif self.failinit:
return (False,)
else:
return (True, 1000000, "aa"*32, {'dummy':'revelation'},
orderbook[:2])
def receive_utxos(self, ioauth_data):
"""Triggered when the daemon returns utxo data from
makers who responded; this is the completion of phase 1
of the protocol
"""
if self.failutxos:
return (False, "dummyreason")
else:
return (True, [x*64 + ":01" for x in ["a", "b", "c"]], t_raw_signed_tx)
def on_sig(self, nick, sigb64):
jlog.debug("We got a sig: " + sigb64)
end_test()
return True
class JMBaseProtocol(amp.AMP):
def checkClientResponse(self, response):
"""A generic check of client acceptance; any failure
is considered criticial.
"""
if 'accepted' not in response or not response['accepted']:
reactor.stop()
def defaultErrback(self, failure):
failure.trap(ConnectionAborted, ConnectionClosed, ConnectionDone,
ConnectionLost, UnknownRemoteError)
reactor.stop()
def defaultCallbacks(self, d):
d.addCallback(self.checkClientResponse)
d.addErrback(self.defaultErrback)
def show_receipt(name, *args):
tmsg("Received msgtype: " + name + ", args: " + ",".join([str(x) for x in args]))
def end_client(client):
client.shutdown_requested = True
def end_test():
#global runno
global test_completed
#runno += 1
#jlog.info("Updated runno to: " + str(runno))
#taker = DummyTaker(None, None)
#if runno == 1:
# jlog.info("Run number was less than 2")
# taker.set_fail_init(True)
# taker.set_fail_utxos(False)
# cfactory = JMTakerClientProtocolFactory(taker)
# reactor.connectTCP("localhost", 27184, cfactory)
# return
#elif runno == 2:
# taker.set_fail_init(False)
# taker.set_fail_utxos(True)
# cfactory = JMTakerClientProtocolFactory(taker)
# reactor.connectTCP("localhost", 27184, cfactory)
# return
test_completed = True
client = clientfactory.getClient()
reactor.callLater(2, end_client, client)
class JMTestServerProtocol(JMBaseProtocol):
@JMInit.responder
def on_JM_INIT(self, bcsource, network, irc_configs, minmakers,
maker_timeout_sec):
show_receipt("JMINIT", bcsource, network, irc_configs, minmakers,
maker_timeout_sec)
d = self.callRemote(JMInitProto,
nick_hash_length=1,
nick_max_encoded=2,
joinmarket_nick_header="J",
joinmarket_version=5)
self.defaultCallbacks(d)
return {'accepted': True}
@JMStartMC.responder
def on_JM_START_MC(self, nick):
show_receipt("STARTMC", nick)
d = self.callRemote(JMUp)
self.defaultCallbacks(d)
return {'accepted': True}
@JMSetup.responder
def on_JM_SETUP(self, role, n_counterparties):
show_receipt("JMSETUP", role,n_counterparties)
d = self.callRemote(JMSetupDone)
self.defaultCallbacks(d)
return {'accepted': True}
@JMRequestOffers.responder
def on_JM_REQUEST_OFFERS(self):
show_receipt("JMREQUESTOFFERS")
#build a huge orderbook to test BigString Argument
orderbook = ["aaaa" for _ in range(15)]
d = self.callRemote(JMOffers,
orderbook=json.dumps(orderbook))
self.defaultCallbacks(d)
return {'accepted': True}
@JMFill.responder
def on_JM_FILL(self, amount, commitment, revelation, filled_offers):
success = False if amount == -1 else True
show_receipt("JMFILL", amount, commitment, revelation, filled_offers)
d = self.callRemote(JMFillResponse,
success=success,
ioauth_data = json.dumps(['dummy', 'list']))
return {'accepted': True}
@JMMakeTx.responder
def on_JM_MAKE_TX(self, nick_list, txhex):
show_receipt("JMMAKETX", nick_list, txhex)
d = self.callRemote(JMSigReceived,
nick="dummynick",
sig="xxxsig")
self.defaultCallbacks(d)
#add dummy calls to check message sign and message verify
d2 = self.callRemote(JMRequestMsgSig,
nick="dummynickforsign",
cmd="command1",
msg="msgforsign",
msg_to_be_signed="fullmsgforsign",
hostid="hostid1")
self.defaultCallbacks(d2)
#To test, this must include a valid ecdsa sig
fullmsg = "fullmsgforverify"
priv = "aa"*32 + "01"
pub = bitcoin.privkey_to_pubkey(priv)
sig = bitcoin.ecdsa_sign(fullmsg, priv)
d3 = self.callRemote(JMRequestMsgSigVerify,
msg="msgforverify",
fullmsg=fullmsg,
sig=sig,
pubkey=pub,
nick="dummynickforverify",
hashlen=4,
max_encoded=5,
hostid="hostid2")
self.defaultCallbacks(d3)
d4 = self.callRemote(JMSigReceived,
nick="dummynick",
sig="dummysig")
self.defaultCallbacks(d4)
return {'accepted': True}
@JMMsgSignature.responder
def on_JM_MSGSIGNATURE(self, nick, cmd, msg_to_return, hostid):
show_receipt("JMMSGSIGNATURE", nick, cmd, msg_to_return, hostid)
return {'accepted': True}
@JMMsgSignatureVerify.responder
def on_JM_MSGSIGNATURE_VERIFY(self, verif_result, nick, fullmsg, hostid):
show_receipt("JMMSGSIGVERIFY", verif_result, nick, fullmsg, hostid)
return {'accepted': True}
class JMTestServerProtocolFactory(protocol.ServerFactory):
protocol = JMTestServerProtocol
class DummyClientProtocolFactory(JMTakerClientProtocolFactory):
def buildProtocol(self, addr):
return JMTakerClientProtocol(self, self.taker, nick_priv="aa"*32)
def test_jm_protocol():
"""We cannot use parametrize for different options as
we can't run in sequence; hence, parameters hardcoded as lists here
"""
params = [[False, False], [True, False], [False, True], [-1, False]]
global clientfactory
load_program_config()
jm_single().maker_timeout_sec = 1
reactor.listenTCP(27184, JMTestServerProtocolFactory())
clientfactories = []
takers = [DummyTaker(None, None) for _ in range(len(params))]
for i, p in enumerate(params):
takers[i].set_fail_init(p[0])
takers[i].set_fail_utxos(p[1])
if i != 0:
clientfactories.append(JMTakerClientProtocolFactory(takers[i]))
reactor.connectTCP("localhost", 27184, clientfactories[i])
else:
clientfactories.append(DummyClientProtocolFactory(takers[i]))
clientfactory = clientfactories[0]
start_reactor("localhost", 27184, clientfactories[0])
print("Got here")
if not test_completed:
raise Exception("Failed test")