Ensure Particl mnemonic is loaded at startup.

2024-05-20_merge
tecnovert 4 years ago
parent 9a182646f0
commit 269d10aeda
No known key found for this signature in database
GPG Key ID: 8ED6D8750C4E3F93
  1. 1
      basicswap/base.py
  2. 26
      basicswap/basicswap.py
  3. 9
      basicswap/js_server.py
  4. 21
      basicswap/network.py
  5. 3
      bin/basicswap_run.py
  6. 175
      tests/basicswap/common.py
  7. 306
      tests/basicswap/test_network.py
  8. 180
      tests/basicswap/test_nmc.py
  9. 229
      tests/basicswap/test_run.py
  10. 278
      tests/basicswap/test_xmr.py

@ -37,6 +37,7 @@ class BaseApp:
self.coin_clients = {} self.coin_clients = {}
self.mxDB = threading.RLock() self.mxDB = threading.RLock()
self.debug = self.settings.get('debug', False) self.debug = self.settings.get('debug', False)
self._network = None
self.prepareLogging() self.prepareLogging()
self.log.info('Network: {}'.format(self.chain)) self.log.info('Network: {}'.format(self.chain))

@ -89,6 +89,7 @@ from .explorers import (
ExplorerChainz, ExplorerChainz,
) )
import basicswap.config as cfg import basicswap.config as cfg
import basicswap.network as bsn
import basicswap.protocols.atomic_swap_1 as atomic_swap_1 import basicswap.protocols.atomic_swap_1 as atomic_swap_1
@ -507,6 +508,12 @@ class BasicSwap(BaseApp):
random.seed(secrets.randbits(128)) random.seed(secrets.randbits(128))
def finalise(self):
if self._network:
self._network.stopNetwork()
self._network = None
self.log.info('Finalise')
def setCoinConnectParams(self, coin): def setCoinConnectParams(self, coin):
# Set anything that does not require the daemon to be running # Set anything that does not require the daemon to be running
chain_client_settings = self.getChainClientSettings(coin) chain_client_settings = self.getChainClientSettings(coin)
@ -642,6 +649,10 @@ class BasicSwap(BaseApp):
self.coin_clients[c]['have_spent_index'] = ci.haveSpentIndex() self.coin_clients[c]['have_spent_index'] = ci.haveSpentIndex()
# Sanity checks # Sanity checks
rv = self.callcoinrpc(c, 'extkey')
if 'result' in rv and 'No keys to list.' in rv['result']:
raise ValueError('No keys loaded.')
if self.callcoinrpc(c, 'getstakinginfo')['enabled'] is not False: if self.callcoinrpc(c, 'getstakinginfo')['enabled'] is not False:
self.log.warning('%s staking is not disabled.', ci.coin_name()) self.log.warning('%s staking is not disabled.', ci.coin_name())
elif c == Coins.XMR: elif c == Coins.XMR:
@ -649,6 +660,11 @@ class BasicSwap(BaseApp):
self.checkWalletSeed(c) self.checkWalletSeed(c)
if 'p2p_host' in self.settings:
network_key = self.getNetworkKey(1)
self._network = bsn.Network(self.settings['p2p_host'], self.settings['p2p_port'], network_key)
self._network.startNetwork()
self.initialise() self.initialise()
def stopDaemon(self, coin): def stopDaemon(self, coin):
@ -1098,7 +1114,6 @@ class BasicSwap(BaseApp):
raise ValueError('grindForEd25519Key failed') raise ValueError('grindForEd25519Key failed')
def getWalletKey(self, coin_type, key_num, for_ed25519=False): def getWalletKey(self, coin_type, key_num, for_ed25519=False):
account = self.callcoinrpc(Coins.PART, 'extkey', ['account'])
evkey = self.callcoinrpc(Coins.PART, 'extkey', ['account', 'default', 'true'])['evkey'] evkey = self.callcoinrpc(Coins.PART, 'extkey', ['account', 'default', 'true'])['evkey']
key_path_base = '44445555h/1h/{}/{}'.format(int(coin_type), key_num) key_path_base = '44445555h/1h/{}/{}'.format(int(coin_type), key_num)
@ -1110,7 +1125,6 @@ class BasicSwap(BaseApp):
return self.grindForEd25519Key(coin_type, evkey, key_path_base) return self.grindForEd25519Key(coin_type, evkey, key_path_base)
def getPathKey(self, coin_from, coin_to, offer_created_at, contract_count, key_no, for_ed25519=False): def getPathKey(self, coin_from, coin_to, offer_created_at, contract_count, key_no, for_ed25519=False):
account = self.callcoinrpc(Coins.PART, 'extkey', ['account'])
evkey = self.callcoinrpc(Coins.PART, 'extkey', ['account', 'default', 'true'])['evkey'] evkey = self.callcoinrpc(Coins.PART, 'extkey', ['account', 'default', 'true'])['evkey']
ci = self.ci(coin_to) ci = self.ci(coin_to)
@ -1124,6 +1138,14 @@ class BasicSwap(BaseApp):
return self.grindForEd25519Key(coin_to, evkey, key_path_base) return self.grindForEd25519Key(coin_to, evkey, key_path_base)
def getNetworkKey(self, key_num):
evkey = self.callcoinrpc(Coins.PART, 'extkey', ['account', 'default', 'true'])['evkey']
key_path = '44445556h/1h/{}'.format(int(key_num))
extkey = self.callcoinrpc(Coins.PART, 'extkey', ['info', evkey, key_path])['key_info']['result']
return decodeWif(self.callcoinrpc(Coins.PART, 'extkey', ['info', extkey])['key_info']['privkey'])
def getContractPubkey(self, date, contract_count): def getContractPubkey(self, date, contract_count):
account = self.callcoinrpc(Coins.PART, 'extkey', ['account']) account = self.callcoinrpc(Coins.PART, 'extkey', ['account'])

@ -102,7 +102,11 @@ def js_bids(self, url_split, post_string):
offer_id = bytes.fromhex(post_data[b'offer_id'][0].decode('utf-8')) offer_id = bytes.fromhex(post_data[b'offer_id'][0].decode('utf-8'))
assert(len(offer_id) == 28) assert(len(offer_id) == 28)
amount_from = inputAmount(post_data[b'amount_from'][0].decode('utf-8')) offer = swap_client.getOffer(offer_id)
assert(offer), 'Offer not found.'
ci_from = swap_client.ci(offer.coin_from)
amount_from = inputAmount(post_data[b'amount_from'][0].decode('utf-8'), ci_from)
addr_from = None addr_from = None
if b'addr_from' in post_data: if b'addr_from' in post_data:
@ -110,8 +114,7 @@ def js_bids(self, url_split, post_string):
if addr_from == '-1': if addr_from == '-1':
addr_from = None addr_from = None
offer = swap_client.getOffer(offer_id) if offer.swap_type == SwapTypes.XMR_SWAP:
if offer and offer.swap_type == SwapTypes.XMR_SWAP:
bid_id = swap_client.postXmrBid(offer_id, amount_from, addr_send_from=addr_from).hex() bid_id = swap_client.postXmrBid(offer_id, amount_from, addr_send_from=addr_from).hex()
else: else:
bid_id = swap_client.postBid(offer_id, amount_from, addr_send_from=addr_from).hex() bid_id = swap_client.postBid(offer_id, amount_from, addr_send_from=addr_from).hex()

@ -12,10 +12,17 @@ TODO:
import select import select
import socket import socket
import logging import logging
import threading
class NetMessage:
def __init__(self):
self._msg_type
class Peer: class Peer:
pass def __init__(self, address):
self._address = address
class Network: class Network:
@ -28,14 +35,24 @@ class Network:
self._max_connections = 10 self._max_connections = 10
self._running = True self._running = True
self._network_thread = None
self._mx = threading.Lock()
def startNetwork(self):
pass
def stopNetwork(self):
pass
def listen(self): def listen(self):
self._socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self._socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self._socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) self._socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
self._socket.bind((self._p2p_host, self._p2p_port)) self._socket.bind((self._p2p_host, self._p2p_port))
self._socket.listen(self._max_connections) self._socket.listen(self._max_connections)
timeout = 1.0
while self._running: while self._running:
readable, writable, errored = select.select([self._socket], [], []) readable, writable, errored = select.select([self._socket], [], [], timeout)
for s in readable: for s in readable:
client_socket, address = self._socket.accept() client_socket, address = self._socket.accept()
logging.info('Connection from %s', address) logging.info('Connection from %s', address)

@ -142,7 +142,8 @@ def runClient(fp, data_dir, chain):
except Exception as ex: except Exception as ex:
traceback.print_exc() traceback.print_exc()
swap_client.log.info('Stopping threads.') swap_client.finalise()
swap_client.log.info('Stopping HTTP threads.')
for t in threads: for t in threads:
t.stop() t.stop()
t.join() t.join()

@ -6,11 +6,72 @@
# file LICENSE.txt or http://www.opensource.org/licenses/mit-license.php. # file LICENSE.txt or http://www.opensource.org/licenses/mit-license.php.
import os import os
import json
import signal
import logging
from urllib.request import urlopen
from basicswap.rpc import callrpc
from basicswap.contrib.rpcauth import generate_salt, password_to_hmac
TEST_HTTP_HOST = os.getenv('TEST_HTTP_HOST', '127.0.0.1') # Set to 0.0.0.0 when used in docker TEST_HTTP_HOST = os.getenv('TEST_HTTP_HOST', '127.0.0.1') # Set to 0.0.0.0 when used in docker
TEST_HTTP_PORT = 1800 TEST_HTTP_PORT = 1800
BASE_P2P_PORT = 12792
BASE_PORT = 14792
BASE_RPC_PORT = 19792
BASE_ZMQ_PORT = 20792
BTC_BASE_PORT = 31792
BTC_BASE_RPC_PORT = 32792
BTC_BASE_ZMQ_PORT = 33792
PREFIX_SECRET_KEY_REGTEST = 0x2e
def prepareDataDir(datadir, node_id, conf_file, dir_prefix, base_p2p_port=BASE_PORT, base_rpc_port=BASE_RPC_PORT, num_nodes=3):
node_dir = os.path.join(datadir, dir_prefix + str(node_id))
if not os.path.exists(node_dir):
os.makedirs(node_dir)
cfg_file_path = os.path.join(node_dir, conf_file)
if os.path.exists(cfg_file_path):
return
with open(cfg_file_path, 'w+') as fp:
fp.write('regtest=1\n')
fp.write('[regtest]\n')
fp.write('port=' + str(base_p2p_port + node_id) + '\n')
fp.write('rpcport=' + str(base_rpc_port + node_id) + '\n')
salt = generate_salt(16)
fp.write('rpcauth={}:{}${}\n'.format('test' + str(node_id), salt, password_to_hmac(salt, 'test_pass' + str(node_id))))
fp.write('daemon=0\n')
fp.write('printtoconsole=0\n')
fp.write('server=1\n')
fp.write('discover=0\n')
fp.write('listenonion=0\n')
fp.write('bind=127.0.0.1\n')
fp.write('debug=1\n')
fp.write('debugexclude=libevent\n')
fp.write('fallbackfee=0.01\n')
fp.write('acceptnonstdtxn=0\n')
fp.write('txindex=1\n')
fp.write('findpeers=0\n')
# minstakeinterval=5 # Using walletsettings stakelimit instead
fp.write('stakethreadconddelayms=1000\n')
if base_p2p_port == BASE_PORT: # Particl
fp.write('zmqpubsmsg=tcp://127.0.0.1:{}\n'.format(BASE_ZMQ_PORT + node_id))
for i in range(0, num_nodes):
if node_id == i:
continue
fp.write('addnode=127.0.0.1:{}\n'.format(base_p2p_port + i))
def checkForks(ro): def checkForks(ro):
if 'bip9_softforks' in ro: if 'bip9_softforks' in ro:
@ -19,3 +80,117 @@ def checkForks(ro):
else: else:
assert(ro['softforks']['csv']['active']) assert(ro['softforks']['csv']['active'])
assert(ro['softforks']['segwit']['active']) assert(ro['softforks']['segwit']['active'])
def stopDaemons(daemons):
for d in daemons:
logging.info('Interrupting %d', d.pid)
try:
d.send_signal(signal.SIGINT)
except Exception as e:
logging.info('Interrupting %d, error %s', d.pid, str(e))
for d in daemons:
try:
d.wait(timeout=20)
for fp in (d.stdout, d.stderr, d.stdin):
if fp:
fp.close()
except Exception as e:
logging.info('Closing %d, error %s', d.pid, str(e))
def wait_for_bid(delay_event, swap_client, bid_id, state=None, sent=False, wait_for=20):
logging.info('wait_for_bid %s', bid_id.hex())
for i in range(wait_for):
if delay_event.is_set():
raise ValueError('Test stopped.')
delay_event.wait(1)
bids = swap_client.listBids(sent=sent)
for bid in bids:
if bid[1] == bid_id:
if state is not None and state != bid[4]:
continue
return
raise ValueError('wait_for_bid timed out.')
def wait_for_bid_tx_state(delay_event, swap_client, bid_id, initiate_state, participate_state, wait_for=30):
logging.info('wait_for_bid_tx_state %s %s %s', bid_id.hex(), str(initiate_state), str(participate_state))
for i in range(wait_for):
if delay_event.is_set():
raise ValueError('Test stopped.')
delay_event.wait(1)
bid = swap_client.getBid(bid_id)
if (initiate_state is None or bid.getITxState() == initiate_state) \
and (participate_state is None or bid.getPTxState() == participate_state):
return
raise ValueError('wait_for_bid_tx_state timed out.')
def wait_for_offer(delay_event, swap_client, offer_id, wait_for=20):
logging.info('wait_for_offer %s', offer_id.hex())
for i in range(wait_for):
if delay_event.is_set():
raise ValueError('Test stopped.')
delay_event.wait(1)
offers = swap_client.listOffers()
for offer in offers:
if offer.offer_id == offer_id:
return
raise ValueError('wait_for_offer timed out.')
def wait_for_no_offer(delay_event, swap_client, offer_id, wait_for=20):
logging.info('wait_for_no_offer %s', offer_id.hex())
for i in range(wait_for):
if delay_event.is_set():
raise ValueError('Test stopped.')
delay_event.wait(1)
offers = swap_client.listOffers()
found_offer = False
for offer in offers:
if offer.offer_id == offer_id:
found_offer = True
break
if not found_offer:
return True
raise ValueError('wait_for_offer timed out.')
def wait_for_none_active(delay_event, port, wait_for=30):
for i in range(wait_for):
if delay_event.is_set():
raise ValueError('Test stopped.')
delay_event.wait(1)
js = json.loads(urlopen('http://localhost:{}/json'.format(port)).read())
if js['num_swapping'] == 0 and js['num_watched_outputs'] == 0:
return
raise ValueError('wait_for_none_active timed out.')
def wait_for_in_progress(delay_event, swap_client, bid_id, sent=False):
logging.info('wait_for_in_progress %s', bid_id.hex())
for i in range(20):
if delay_event.is_set():
raise ValueError('Test stopped.')
delay_event.wait(1)
swaps = swap_client.listSwapsInProgress()
for b in swaps:
if b[0] == bid_id:
return
raise ValueError('wait_for_in_progress timed out.')
def delay_for(delay_event, delay_for=60):
logging.info('Delaying for {} seconds.'.format(delay_for))
delay_event.wait(delay_for)
def make_rpc_func(node_id, base_rpc_port=BASE_RPC_PORT):
node_id = node_id
auth = 'test{0}:test_pass{0}'.format(node_id)
def rpc_func(method, params=None, wallet=None):
nonlocal node_id, auth
return callrpc(base_rpc_port + node_id, auth, method, params, wallet)
return rpc_func

@ -0,0 +1,306 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# Copyright (c) 2020 tecnovert
# Distributed under the MIT software license, see the accompanying
# file LICENSE or http://www.opensource.org/licenses/mit-license.php.
import os
import json
import time
import shutil
import signal
import logging
import unittest
import traceback
import threading
from urllib.request import urlopen
import basicswap.config as cfg
from basicswap.basicswap import (
BasicSwap,
Coins,
SwapTypes,
)
from basicswap.util import (
COIN,
toWIF,
)
from basicswap.rpc import (
callrpc,
callrpc_cli,
waitForRPC,
)
from basicswap.contrib.key import (
ECKey,
)
from basicswap.http_server import (
HttpThread,
)
from tests.basicswap.common import (
prepareDataDir,
make_rpc_func,
checkForks,
stopDaemons,
wait_for_offer,
TEST_HTTP_HOST,
TEST_HTTP_PORT,
BASE_P2P_PORT,
BASE_RPC_PORT,
BASE_ZMQ_PORT,
BTC_BASE_PORT,
BTC_BASE_RPC_PORT,
PREFIX_SECRET_KEY_REGTEST,
)
from bin.basicswap_run import startDaemon
logger = logging.getLogger()
NUM_NODES = 3
NUM_BTC_NODES = 3
TEST_DIR = cfg.TEST_DATADIRS
delay_event = threading.Event()
stop_test = False
def prepare_swapclient_dir(datadir, node_id, network_key, network_pubkey):
basicswap_dir = os.path.join(datadir, 'basicswap_' + str(node_id))
if not os.path.exists(basicswap_dir):
os.makedirs(basicswap_dir)
settings_path = os.path.join(basicswap_dir, cfg.CONFIG_FILENAME)
settings = {
'debug': True,
'p2p_host': '127.0.0.1',
'p2p_port': BASE_P2P_PORT + node_id,
'zmqhost': 'tcp://127.0.0.1',
'zmqport': BASE_ZMQ_PORT + node_id,
'htmlhost': 'localhost',
'htmlport': TEST_HTTP_PORT + node_id,
'network_key': network_key,
'network_pubkey': network_pubkey,
'chainclients': {
'particl': {
'connection_type': 'rpc',
'manage_daemon': False,
'rpcport': BASE_RPC_PORT + node_id,
'rpcuser': 'test' + str(node_id),
'rpcpassword': 'test_pass' + str(node_id),
'datadir': os.path.join(datadir, 'part_' + str(node_id)),
'bindir': cfg.PARTICL_BINDIR,
'blocks_confirmed': 2, # Faster testing
},
'bitcoin': {
'connection_type': 'rpc',
'manage_daemon': False,
'rpcport': BTC_BASE_RPC_PORT + node_id,
'rpcuser': 'test' + str(node_id),
'rpcpassword': 'test_pass' + str(node_id),
'datadir': os.path.join(datadir, 'btc_' + str(node_id)),
'bindir': cfg.BITCOIN_BINDIR,
'use_segwit': True,
}
},
'check_progress_seconds': 2,
'check_watched_seconds': 4,
'check_expired_seconds': 60,
'check_events_seconds': 1,
'check_xmr_swaps_seconds': 1,
'min_delay_event': 1,
'max_delay_event': 5,
'min_delay_retry': 2,
'max_delay_retry': 10
}
with open(settings_path, 'w') as fp:
json.dump(settings, fp, indent=4)
def partRpc(cmd, node_id=0):
return callrpc_cli(cfg.PARTICL_BINDIR, os.path.join(TEST_DIR, 'part_' + str(node_id)), 'regtest', cmd, cfg.PARTICL_CLI)
def btcRpc(cmd, node_id=0):
return callrpc_cli(cfg.BITCOIN_BINDIR, os.path.join(TEST_DIR, 'btc_' + str(node_id)), 'regtest', cmd, cfg.BITCOIN_CLI)
def signal_handler(sig, frame):
global stop_test
logging.info('signal {} detected.'.format(sig))
stop_test = True
delay_event.set()
def callnoderpc(node_id, method, params=[], wallet=None, base_rpc_port=BASE_RPC_PORT):
auth = 'test{0}:test_pass{0}'.format(node_id)
return callrpc(base_rpc_port + node_id, auth, method, params, wallet)
def run_coins_loop(cls):
global stop_test
while not stop_test:
if cls.btc_addr is not None:
btcRpc('generatetoaddress 1 {}'.format(cls.btc_addr))
time.sleep(1.0)
def run_loop(cls):
global stop_test
while not stop_test:
for c in cls.swap_clients:
c.update()
time.sleep(1.0)
class Test(unittest.TestCase):
@classmethod
def setUpClass(cls):
super(Test, cls).setUpClass()
cls.update_thread = None
cls.coins_update_thread = None
cls.http_threads = []
cls.swap_clients = []
cls.part_daemons = []
cls.btc_daemons = []
cls.part_stakelimit = 0
cls.btc_addr = None
logger.propagate = False
logger.handlers = []
logger.setLevel(logging.INFO) # DEBUG shows many messages from requests.post
formatter = logging.Formatter('%(asctime)s %(levelname)s : %(message)s')
stream_stdout = logging.StreamHandler()
stream_stdout.setFormatter(formatter)
logger.addHandler(stream_stdout)
if os.path.isdir(TEST_DIR):
logging.info('Removing ' + TEST_DIR)
shutil.rmtree(TEST_DIR)
if not os.path.exists(TEST_DIR):
os.makedirs(TEST_DIR)
cls.stream_fp = logging.FileHandler(os.path.join(TEST_DIR, 'test.log'))
cls.stream_fp.setFormatter(formatter)
logger.addHandler(cls.stream_fp)
try:
logging.info('Preparing coin nodes.')
for i in range(NUM_NODES):
prepareDataDir(TEST_DIR, i, 'particl.conf', 'part_')
cls.part_daemons.append(startDaemon(os.path.join(TEST_DIR, 'part_' + str(i)), cfg.PARTICL_BINDIR, cfg.PARTICLD))
logging.info('Started %s %d', cfg.PARTICLD, cls.part_daemons[-1].pid)
for i in range(NUM_NODES):
# Load mnemonics after all nodes have started to avoid staking getting stuck in TryToSync
rpc = make_rpc_func(i)
waitForRPC(rpc)
if i == 0:
rpc('extkeyimportmaster', ['abandon baby cabbage dad eager fabric gadget habit ice kangaroo lab absorb'])
elif i == 1:
rpc('extkeyimportmaster', ['pact mammal barrel matrix local final lecture chunk wasp survey bid various book strong spread fall ozone daring like topple door fatigue limb olympic', '', 'true'])
rpc('getnewextaddress', ['lblExtTest'])
rpc('rescanblockchain')
else:
rpc('extkeyimportmaster', [rpc('mnemonic', ['new'])['master']])
# Lower output split threshold for more stakeable outputs
rpc('walletsettings', ['stakingoptions', {'stakecombinethreshold': 100, 'stakesplitthreshold': 200}])
for i in range(NUM_BTC_NODES):
prepareDataDir(TEST_DIR, i, 'bitcoin.conf', 'btc_', base_p2p_port=BTC_BASE_PORT, base_rpc_port=BTC_BASE_RPC_PORT)
cls.btc_daemons.append(startDaemon(os.path.join(TEST_DIR, 'btc_' + str(i)), cfg.BITCOIN_BINDIR, cfg.BITCOIND))
logging.info('Started %s %d', cfg.BITCOIND, cls.part_daemons[-1].pid)
waitForRPC(make_rpc_func(i, base_rpc_port=BTC_BASE_RPC_PORT))
logging.info('Preparing swap clients.')
eckey = ECKey()
eckey.generate()
cls.network_key = toWIF(PREFIX_SECRET_KEY_REGTEST, eckey.get_bytes())
cls.network_pubkey = eckey.get_pubkey().get_bytes().hex()
for i in range(NUM_NODES):
prepare_swapclient_dir(TEST_DIR, i, cls.network_key, cls.network_pubkey)
basicswap_dir = os.path.join(os.path.join(TEST_DIR, 'basicswap_' + str(i)))
settings_path = os.path.join(basicswap_dir, cfg.CONFIG_FILENAME)
with open(settings_path) as fs:
settings = json.load(fs)
fp = open(os.path.join(basicswap_dir, 'basicswap.log'), 'w')
sc = BasicSwap(fp, basicswap_dir, settings, 'regtest', log_name='BasicSwap{}'.format(i))
sc.setDaemonPID(Coins.BTC, cls.btc_daemons[i].pid)
sc.setDaemonPID(Coins.PART, cls.part_daemons[i].pid)
sc.start()
cls.swap_clients.append(sc)
t = HttpThread(cls.swap_clients[i].fp, TEST_HTTP_HOST, TEST_HTTP_PORT + i, False, cls.swap_clients[i])
cls.http_threads.append(t)
t.start()
cls.btc_addr = callnoderpc(0, 'getnewaddress', ['mining_addr', 'bech32'], base_rpc_port=BTC_BASE_RPC_PORT)
num_blocks = 500
logging.info('Mining %d Bitcoin blocks to %s', num_blocks, cls.btc_addr)
callnoderpc(0, 'generatetoaddress', [num_blocks, cls.btc_addr], base_rpc_port=BTC_BASE_RPC_PORT)
checkForks(callnoderpc(0, 'getblockchaininfo', base_rpc_port=BTC_BASE_RPC_PORT))
logging.info('Starting update thread.')
signal.signal(signal.SIGINT, signal_handler)
cls.update_thread = threading.Thread(target=run_loop, args=(cls,))
cls.update_thread.start()
cls.coins_update_thread = threading.Thread(target=run_coins_loop, args=(cls,))
cls.coins_update_thread.start()
except Exception:
traceback.print_exc()
Test.tearDownClass()
raise ValueError('setUpClass() failed.')
@classmethod
def tearDownClass(cls):
global stop_test
logging.info('Finalising')
stop_test = True
if cls.update_thread is not None:
try:
cls.update_thread.join()
except Exception:
logging.info('Failed to join update_thread')
if cls.coins_update_thread is not None:
try:
cls.coins_update_thread.join()
except Exception:
logging.info('Failed to join coins_update_thread')
for t in cls.http_threads:
t.stop()
t.join()
for c in cls.swap_clients:
c.finalise()
c.fp.close()
stopDaemons(cls.part_daemons)
stopDaemons(cls.btc_daemons)
super(Test, cls).tearDownClass()
def test_01_part_btc(self):
logging.info('---------- Test PART to BTC')
swap_clients = self.swap_clients
js_1 = json.loads(urlopen('http://localhost:1801/json/wallets').read())
offer_id = swap_clients[0].postOffer(Coins.PART, Coins.BTC, 100 * COIN, 0.1 * COIN, 100 * COIN, SwapTypes.SELLER_FIRST)
wait_for_offer(delay_event, swap_clients[1], offer_id)
if __name__ == '__main__':
unittest.main()

@ -1,7 +1,7 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# Copyright (c) 2019 tecnovert # Copyright (c) 2019-2020 tecnovert
# Distributed under the MIT software license, see the accompanying # Distributed under the MIT software license, see the accompanying
# file LICENSE or http://www.opensource.org/licenses/mit-license.php. # file LICENSE or http://www.opensource.org/licenses/mit-license.php.
@ -21,6 +21,7 @@ import signal
import threading import threading
from urllib.request import urlopen from urllib.request import urlopen
import basicswap.config as cfg
from basicswap.basicswap import ( from basicswap.basicswap import (
BasicSwap, BasicSwap,
Coins, Coins,
@ -45,12 +46,21 @@ from basicswap.http_server import (
HttpThread, HttpThread,
) )
from tests.basicswap.common import ( from tests.basicswap.common import (
checkForks,
stopDaemons,
wait_for_offer,
wait_for_bid,
wait_for_bid_tx_state,
wait_for_in_progress,
TEST_HTTP_HOST, TEST_HTTP_HOST,
TEST_HTTP_PORT, TEST_HTTP_PORT,
BASE_PORT,
BASE_RPC_PORT,
BASE_ZMQ_PORT,
PREFIX_SECRET_KEY_REGTEST,
) )
from bin.basicswap_run import startDaemon from bin.basicswap_run import startDaemon
import basicswap.config as cfg
logger = logging.getLogger() logger = logging.getLogger()
logger.level = logging.DEBUG logger.level = logging.DEBUG
@ -58,12 +68,10 @@ if not len(logger.handlers):
logger.addHandler(logging.StreamHandler(sys.stdout)) logger.addHandler(logging.StreamHandler(sys.stdout))
NUM_NODES = 3 NUM_NODES = 3
BASE_PORT = 14792
BASE_RPC_PORT = 19792
BASE_ZMQ_PORT = 20792
PREFIX_SECRET_KEY_REGTEST = 0x2e
NMC_NODE = 3 NMC_NODE = 3
BTC_NODE = 4 BTC_NODE = 4
delay_event = threading.Event()
stop_test = False stop_test = False
@ -193,6 +201,7 @@ def signal_handler(sig, frame):
global stop_test global stop_test
print('signal {} detected.'.format(sig)) print('signal {} detected.'.format(sig))
stop_test = True stop_test = True
delay_event.set()
def run_loop(self): def run_loop(self):
@ -204,6 +213,19 @@ def run_loop(self):
btcRpc('generatetoaddress 1 {}'.format(self.btc_addr)) btcRpc('generatetoaddress 1 {}'.format(self.btc_addr))
def make_part_cli_rpc_func(node_id):
node_id = node_id
def rpc_func(method, params=None, wallet=None):
nonlocal node_id
cmd = method
if params:
for p in params:
cmd += ' "' + p + '"'
return partRpc(cmd, node_id)
return rpc_func
class Test(unittest.TestCase): class Test(unittest.TestCase):
@classmethod @classmethod
@ -227,6 +249,7 @@ class Test(unittest.TestCase):
cls.daemons = [] cls.daemons = []
cls.swap_clients = [] cls.swap_clients = []
cls.http_threads = []
cls.daemons.append(startDaemon(os.path.join(cfg.TEST_DATADIRS, str(BTC_NODE)), cfg.BITCOIN_BINDIR, cfg.BITCOIND)) cls.daemons.append(startDaemon(os.path.join(cfg.TEST_DATADIRS, str(BTC_NODE)), cfg.BITCOIN_BINDIR, cfg.BITCOIND))
logging.info('Started %s %d', cfg.BITCOIND, cls.daemons[-1].pid) logging.info('Started %s %d', cfg.BITCOIND, cls.daemons[-1].pid)
@ -234,8 +257,20 @@ class Test(unittest.TestCase):
logging.info('Started %s %d', cfg.NAMECOIND, cls.daemons[-1].pid) logging.info('Started %s %d', cfg.NAMECOIND, cls.daemons[-1].pid)
for i in range(NUM_NODES): for i in range(NUM_NODES):
cls.daemons.append(startDaemon(os.path.join(cfg.TEST_DATADIRS, str(i))), cfg.PARTICL_BINDIR, cfg.PARTICLD) cls.daemons.append(startDaemon(os.path.join(cfg.TEST_DATADIRS, str(i)), cfg.PARTICL_BINDIR, cfg.PARTICLD))
logging.info('Started %s %d', cfg.PARTICLD, cls.daemons[-1].pid) logging.info('Started %s %d', cfg.PARTICLD, cls.daemons[-1].pid)
rpc = make_part_cli_rpc_func(i)
waitForRPC(rpc)
if i == 0:
rpc('extkeyimportmaster', ['abandon baby cabbage dad eager fabric gadget habit ice kangaroo lab absorb'])
elif i == 1:
rpc('extkeyimportmaster', ['pact mammal barrel matrix local final lecture chunk wasp survey bid various book strong spread fall ozone daring like topple door fatigue limb olympic', '', 'true'])
rpc('getnewextaddress', ['lblExtTest'])
rpc('rescanblockchain')
else:
rpc('extkeyimportmaster', [rpc('mnemonic', ['new'])['master']])
time.sleep(1) time.sleep(1)
for i in range(NUM_NODES): for i in range(NUM_NODES):
basicswap_dir = os.path.join(os.path.join(cfg.TEST_DATADIRS, str(i)), 'basicswap') basicswap_dir = os.path.join(os.path.join(cfg.TEST_DATADIRS, str(i)), 'basicswap')
@ -248,10 +283,10 @@ class Test(unittest.TestCase):
cls.swap_clients[-1].setDaemonPID(Coins.NMC, cls.daemons[1].pid) cls.swap_clients[-1].setDaemonPID(Coins.NMC, cls.daemons[1].pid)
cls.swap_clients[-1].setDaemonPID(Coins.PART, cls.daemons[2 + i].pid) cls.swap_clients[-1].setDaemonPID(Coins.PART, cls.daemons[2 + i].pid)
cls.swap_clients[-1].start() cls.swap_clients[-1].start()
cls.swap_clients[0].callrpc('extkeyimportmaster', ['abandon baby cabbage dad eager fabric gadget habit ice kangaroo lab absorb'])
cls.swap_clients[1].callrpc('extkeyimportmaster', ['pact mammal barrel matrix local final lecture chunk wasp survey bid various book strong spread fall ozone daring like topple door fatigue limb olympic', '', 'true']) t = HttpThread(cls.swap_clients[i].fp, TEST_HTTP_HOST, TEST_HTTP_PORT + i, False, cls.swap_clients[i])
cls.swap_clients[1].callrpc('getnewextaddress', ['lblExtTest']) cls.http_threads.append(t)
cls.swap_clients[1].callrpc('rescanblockchain') t.start()
waitForRPC(nmcRpc) waitForRPC(nmcRpc)
num_blocks = 500 num_blocks = 500
@ -275,18 +310,11 @@ class Test(unittest.TestCase):
btcRpc('generatetoaddress {} {}'.format(num_blocks, cls.btc_addr)) btcRpc('generatetoaddress {} {}'.format(num_blocks, cls.btc_addr))
ro = btcRpc('getblockchaininfo') ro = btcRpc('getblockchaininfo')
assert(ro['bip9_softforks']['csv']['status'] == 'active') checkForks(ro)
assert(ro['bip9_softforks']['segwit']['status'] == 'active')
ro = nmcRpc('getwalletinfo') ro = nmcRpc('getwalletinfo')
print('nmcRpc', ro) print('nmcRpc', ro)
cls.http_threads = []
for i in range(3):
t = HttpThread(cls.swap_clients[i].fp, TEST_HTTP_HOST, TEST_HTTP_PORT + i, False, cls.swap_clients[i])
cls.http_threads.append(t)
t.start()
signal.signal(signal.SIGINT, signal_handler) signal.signal(signal.SIGINT, signal_handler)
cls.update_thread = threading.Thread(target=run_loop, args=(cls,)) cls.update_thread = threading.Thread(target=run_loop, args=(cls,))
cls.update_thread.start() cls.update_thread.start()
@ -301,68 +329,12 @@ class Test(unittest.TestCase):
t.stop() t.stop()
t.join() t.join()
for c in cls.swap_clients: for c in cls.swap_clients:
c.finalise()
c.fp.close() c.fp.close()
for d in cls.daemons:
logging.info('Terminating %d', d.pid)
d.terminate()
d.wait(timeout=10)
if d.stdout:
d.stdout.close()
if d.stderr:
d.stderr.close()
if d.stdin:
d.stdin.close()
super(Test, cls).tearDownClass() stopDaemons(cls.daemons)
def wait_for_offer(self, swap_client, offer_id): super(Test, cls).tearDownClass()
logging.info('wait_for_offer %s', offer_id.hex())
for i in range(20):
time.sleep(1)
offers = swap_client.listOffers()
for offer in offers:
if offer.offer_id == offer_id:
return
raise ValueError('wait_for_offer timed out.')
def wait_for_bid(self, swap_client, bid_id):
logging.info('wait_for_bid %s', bid_id.hex())
for i in range(20):
time.sleep(1)
bids = swap_client.listBids()
for bid in bids:
if bid[1] == bid_id and int(bid[5]) == 1:
return
raise ValueError('wait_for_bid timed out.')
def wait_for_in_progress(self, swap_client, bid_id, sent=False):
logging.info('wait_for_in_progress %s', bid_id.hex())
for i in range(20):
time.sleep(1)
swaps = swap_client.listSwapsInProgress()
for b in swaps:
if b[0] == bid_id:
return
raise ValueError('wait_for_in_progress timed out.')
def wait_for_bid_state(self, swap_client, bid_id, state, sent=False, seconds_for=30):
logging.info('wait_for_bid_state %s %s', bid_id.hex(), str(state))
for i in range(seconds_for):
time.sleep(1)
bid = swap_client.getBid(bid_id)
if bid.state >= state:
return
raise ValueError('wait_for_bid_state timed out.')
def wait_for_bid_tx_state(self, swap_client, bid_id, initiate_state, participate_state, seconds_for=30):
logging.info('wait_for_bid_tx_state %s %s %s', bid_id.hex(), str(initiate_state), str(participate_state))
for i in range(seconds_for):
time.sleep(1)
bid = swap_client.getBid(bid_id)
if (initiate_state is None or bid.getITxState() == initiate_state) \
and (participate_state is None or bid.getPTxState() == participate_state):
return
raise ValueError('wait_for_bid_tx_state timed out.')
def test_02_part_ltc(self): def test_02_part_ltc(self):
logging.info('---------- Test PART to NMC') logging.info('---------- Test PART to NMC')
@ -370,21 +342,21 @@ class Test(unittest.TestCase):
offer_id = swap_clients[0].postOffer(Coins.PART, Coins.NMC, 100 * COIN, 0.1 * COIN, 100 * COIN, SwapTypes.SELLER_FIRST, ABS_LOCK_TIME) offer_id = swap_clients[0].postOffer(Coins.PART, Coins.NMC, 100 * COIN, 0.1 * COIN, 100 * COIN, SwapTypes.SELLER_FIRST, ABS_LOCK_TIME)
self.wait_for_offer(swap_clients[1], offer_id) wait_for_offer(delay_event, swap_clients[1], offer_id)
offers = swap_clients[1].listOffers() offers = swap_clients[1].listOffers()
assert(len(offers) == 1) assert(len(offers) == 1)
for offer in offers: for offer in offers:
if offer.offer_id == offer_id: if offer.offer_id == offer_id:
bid_id = swap_clients[1].postBid(offer_id, offer.amount_from) bid_id = swap_clients[1].postBid(offer_id, offer.amount_from)
self.wait_for_bid(swap_clients[0], bid_id) wait_for_bid(delay_event, swap_clients[0], bid_id)
swap_clients[0].acceptBid(bid_id) swap_clients[0].acceptBid(bid_id)
self.wait_for_in_progress(swap_clients[1], bid_id, sent=True) wait_for_in_progress(delay_event, swap_clients[1], bid_id, sent=True)
self.wait_for_bid_state(swap_clients[0], bid_id, BidStates.SWAP_COMPLETED, seconds_for=60) wait_for_bid(delay_event, swap_clients[0], bid_id, BidStates.SWAP_COMPLETED, wait_for=60)
self.wait_for_bid_state(swap_clients[1], bid_id, BidStates.SWAP_COMPLETED, sent=True, seconds_for=60) wait_for_bid(delay_event, swap_clients[1], bid_id, BidStates.SWAP_COMPLETED, sent=True, wait_for=60)
js_0 = json.loads(urlopen('http://localhost:1800/json').read()) js_0 = json.loads(urlopen('http://localhost:1800/json').read())
js_1 = json.loads(urlopen('http://localhost:1801/json').read()) js_1 = json.loads(urlopen('http://localhost:1801/json').read())
@ -397,19 +369,19 @@ class Test(unittest.TestCase):
offer_id = swap_clients[1].postOffer(Coins.NMC, Coins.PART, 10 * COIN, 9.0 * COIN, 10 * COIN, SwapTypes.SELLER_FIRST, ABS_LOCK_TIME) offer_id = swap_clients[1].postOffer(Coins.NMC, Coins.PART, 10 * COIN, 9.0 * COIN, 10 * COIN, SwapTypes.SELLER_FIRST, ABS_LOCK_TIME)
self.wait_for_offer(swap_clients[0], offer_id) wait_for_offer(delay_event, swap_clients[0], offer_id)
offers = swap_clients[0].listOffers() offers = swap_clients[0].listOffers()
for offer in offers: for offer in offers:
if offer.offer_id == offer_id: if offer.offer_id == offer_id:
bid_id = swap_clients[0].postBid(offer_id, offer.amount_from) bid_id = swap_clients[0].postBid(offer_id, offer.amount_from)
self.wait_for_bid(swap_clients[1], bid_id) wait_for_bid(delay_event, swap_clients[1], bid_id)
swap_clients[1].acceptBid(bid_id) swap_clients[1].acceptBid(bid_id)
self.wait_for_in_progress(swap_clients[0], bid_id, sent=True) wait_for_in_progress(delay_event, swap_clients[0], bid_id, sent=True)
self.wait_for_bid_state(swap_clients[0], bid_id, BidStates.SWAP_COMPLETED, sent=True, seconds_for=60) wait_for_bid(delay_event, swap_clients[0], bid_id, BidStates.SWAP_COMPLETED, sent=True, wait_for=60)
self.wait_for_bid_state(swap_clients[1], bid_id, BidStates.SWAP_COMPLETED, seconds_for=60) wait_for_bid(delay_event, swap_clients[1], bid_id, BidStates.SWAP_COMPLETED, wait_for=60)
js_0 = json.loads(urlopen('http://localhost:1800/json').read()) js_0 = json.loads(urlopen('http://localhost:1800/json').read())
js_1 = json.loads(urlopen('http://localhost:1801/json').read()) js_1 = json.loads(urlopen('http://localhost:1801/json').read())
@ -422,19 +394,19 @@ class Test(unittest.TestCase):
offer_id = swap_clients[0].postOffer(Coins.NMC, Coins.BTC, 10 * COIN, 0.1 * COIN, 10 * COIN, SwapTypes.SELLER_FIRST, ABS_LOCK_TIME) offer_id = swap_clients[0].postOffer(Coins.NMC, Coins.BTC, 10 * COIN, 0.1 * COIN, 10 * COIN, SwapTypes.SELLER_FIRST, ABS_LOCK_TIME)
self.wait_for_offer(swap_clients[1], offer_id) wait_for_offer(delay_event, swap_clients[1], offer_id)
offers = swap_clients[1].listOffers() offers = swap_clients[1].listOffers()
for offer in offers: for offer in offers:
if offer.offer_id == offer_id: if offer.offer_id == offer_id:
bid_id = swap_clients[1].postBid(offer_id, offer.amount_from) bid_id = swap_clients[1].postBid(offer_id, offer.amount_from)
self.wait_for_bid(swap_clients[0], bid_id) wait_for_bid(delay_event, swap_clients[0], bid_id)
swap_clients[0].acceptBid(bid_id) swap_clients[0].acceptBid(bid_id)
self.wait_for_in_progress(swap_clients[1], bid_id, sent=True) wait_for_in_progress(delay_event, swap_clients[1], bid_id, sent=True)
self.wait_for_bid_state(swap_clients[0], bid_id, BidStates.SWAP_COMPLETED, seconds_for=60) wait_for_bid(delay_event, swap_clients[0], bid_id, BidStates.SWAP_COMPLETED, wait_for=60)
self.wait_for_bid_state(swap_clients[1], bid_id, BidStates.SWAP_COMPLETED, sent=True, seconds_for=60) wait_for_bid(delay_event, swap_clients[1], bid_id, BidStates.SWAP_COMPLETED, sent=True, wait_for=60)
js_0bid = json.loads(urlopen('http://localhost:1800/json/bids/{}'.format(bid_id.hex())).read()) js_0bid = json.loads(urlopen('http://localhost:1800/json/bids/{}'.format(bid_id.hex())).read())
@ -452,18 +424,18 @@ class Test(unittest.TestCase):
offer_id = swap_clients[0].postOffer(Coins.NMC, Coins.BTC, 10 * COIN, 0.1 * COIN, 10 * COIN, SwapTypes.SELLER_FIRST, offer_id = swap_clients[0].postOffer(Coins.NMC, Coins.BTC, 10 * COIN, 0.1 * COIN, 10 * COIN, SwapTypes.SELLER_FIRST,
ABS_LOCK_BLOCKS, 10) ABS_LOCK_BLOCKS, 10)
self.wait_for_offer(swap_clients[1], offer_id) wait_for_offer(delay_event, swap_clients[1], offer_id)
offers = swap_clients[1].listOffers() offers = swap_clients[1].listOffers()
for offer in offers: for offer in offers:
if offer.offer_id == offer_id: if offer.offer_id == offer_id:
bid_id = swap_clients[1].postBid(offer_id, offer.amount_from) bid_id = swap_clients[1].postBid(offer_id, offer.amount_from)
self.wait_for_bid(swap_clients[0], bid_id) wait_for_bid(delay_event, swap_clients[0], bid_id)
swap_clients[1].abandonBid(bid_id) swap_clients[1].abandonBid(bid_id)
swap_clients[0].acceptBid(bid_id) swap_clients[0].acceptBid(bid_id)
self.wait_for_bid_state(swap_clients[0], bid_id, BidStates.SWAP_COMPLETED, seconds_for=60) wait_for_bid(delay_event, swap_clients[0], bid_id, BidStates.SWAP_COMPLETED, wait_for=60)
self.wait_for_bid_state(swap_clients[1], bid_id, BidStates.BID_ABANDONED, sent=True, seconds_for=60) wait_for_bid(delay_event, swap_clients[1], bid_id, BidStates.BID_ABANDONED, sent=True, wait_for=60)
js_0 = json.loads(urlopen('http://localhost:1800/json').read()) js_0 = json.loads(urlopen('http://localhost:1800/json').read())
js_1 = json.loads(urlopen('http://localhost:1801/json').read()) js_1 = json.loads(urlopen('http://localhost:1801/json').read())
@ -478,17 +450,17 @@ class Test(unittest.TestCase):
offer_id = swap_clients[0].postOffer(Coins.NMC, Coins.BTC, 10 * COIN, 10 * COIN, 10 * COIN, SwapTypes.SELLER_FIRST, ABS_LOCK_TIME) offer_id = swap_clients[0].postOffer(Coins.NMC, Coins.BTC, 10 * COIN, 10 * COIN, 10 * COIN, SwapTypes.SELLER_FIRST, ABS_LOCK_TIME)
self.wait_for_offer(swap_clients[0], offer_id) wait_for_offer(delay_event, swap_clients[0], offer_id)
offers = swap_clients[0].listOffers() offers = swap_clients[0].listOffers()
for offer in offers: for offer in offers:
if offer.offer_id == offer_id: if offer.offer_id == offer_id:
bid_id = swap_clients[0].postBid(offer_id, offer.amount_from) bid_id = swap_clients[0].postBid(offer_id, offer.amount_from)
self.wait_for_bid(swap_clients[0], bid_id) wait_for_bid(delay_event, swap_clients[0], bid_id)
swap_clients[0].acceptBid(bid_id) swap_clients[0].acceptBid(bid_id)
self.wait_for_bid_tx_state(swap_clients[0], bid_id, TxStates.TX_REDEEMED, TxStates.TX_REDEEMED, seconds_for=60) wait_for_bid_tx_state(delay_event, swap_clients[0], bid_id, TxStates.TX_REDEEMED, TxStates.TX_REDEEMED, wait_for=60)
self.wait_for_bid_state(swap_clients[0], bid_id, BidStates.SWAP_COMPLETED, seconds_for=60) wait_for_bid(delay_event, swap_clients[0], bid_id, BidStates.SWAP_COMPLETED, wait_for=60)
js_0 = json.loads(urlopen('http://localhost:1800/json').read()) js_0 = json.loads(urlopen('http://localhost:1800/json').read())
assert(js_0['num_swapping'] == 0 and js_0['num_watched_outputs'] == 0) assert(js_0['num_swapping'] == 0 and js_0['num_watched_outputs'] == 0)
@ -502,18 +474,18 @@ class Test(unittest.TestCase):
offer_id = swap_clients[0].postOffer(Coins.NMC, Coins.BTC, 0.001 * COIN, 1.0 * COIN, 0.001 * COIN, SwapTypes.SELLER_FIRST, ABS_LOCK_TIME) offer_id = swap_clients[0].postOffer(Coins.NMC, Coins.BTC, 0.001 * COIN, 1.0 * COIN, 0.001 * COIN, SwapTypes.SELLER_FIRST, ABS_LOCK_TIME)
self.wait_for_offer(swap_clients[0], offer_id) wait_for_offer(delay_event, swap_clients[0], offer_id)
offers = swap_clients[0].listOffers() offers = swap_clients[0].listOffers()
for offer in offers: for offer in offers:
if offer.offer_id == offer_id: if offer.offer_id == offer_id:
bid_id = swap_clients[0].postBid(offer_id, offer.amount_from) bid_id = swap_clients[0].postBid(offer_id, offer.amount_from)
self.wait_for_bid(swap_clients[0], bid_id) wait_for_bid(delay_event, swap_clients[0], bid_id)
swap_clients[0].acceptBid(bid_id) swap_clients[0].acceptBid(bid_id)
swap_clients[0].coin_clients[Coins.BTC]['override_feerate'] = 10.0 swap_clients[0].coin_clients[Coins.BTC]['override_feerate'] = 10.0
swap_clients[0].coin_clients[Coins.NMC]['override_feerate'] = 10.0 swap_clients[0].coin_clients[Coins.NMC]['override_feerate'] = 10.0
self.wait_for_bid_state(swap_clients[0], bid_id, BidStates.BID_ERROR, seconds_for=60) wait_for_bid(delay_event, swap_clients[0], bid_id, BidStates.BID_ERROR, wait_for=60)
def pass_99_delay(self): def pass_99_delay(self):
global stop_test global stop_test

@ -15,12 +15,12 @@ $ python setup.py test -s tests.basicswap.test_run.Test.test_04_ltc_btc
import os import os
import sys import sys
import unittest
import json import json
import logging
import shutil
import time import time
import shutil
import signal import signal
import logging
import unittest
import threading import threading
from urllib.request import urlopen from urllib.request import urlopen
@ -50,26 +50,35 @@ from basicswap.http_server import (
) )
from tests.basicswap.common import ( from tests.basicswap.common import (
checkForks, checkForks,
stopDaemons,
wait_for_offer,
wait_for_bid,
wait_for_bid_tx_state,
wait_for_in_progress,
TEST_HTTP_HOST, TEST_HTTP_HOST,
TEST_HTTP_PORT, TEST_HTTP_PORT,
BASE_PORT,
BASE_RPC_PORT,
BASE_ZMQ_PORT,
PREFIX_SECRET_KEY_REGTEST,
) )
from bin.basicswap_run import startDaemon from bin.basicswap_run import startDaemon
logger = logging.getLogger()
logger.level = logging.DEBUG
if not len(logger.handlers):
logger.addHandler(logging.StreamHandler(sys.stdout))
NUM_NODES = 3 NUM_NODES = 3
BASE_PORT = 14792
BASE_RPC_PORT = 19792
BASE_ZMQ_PORT = 20792
PREFIX_SECRET_KEY_REGTEST = 0x2e
LTC_NODE = 3 LTC_NODE = 3
BTC_NODE = 4 BTC_NODE = 4
delay_event = threading.Event()
stop_test = False stop_test = False
logger = logging.getLogger()
logger.level = logging.DEBUG
if not len(logger.handlers):
logger.addHandler(logging.StreamHandler(sys.stdout))
def prepareOtherDir(datadir, nodeId, conf_file='litecoin.conf'): def prepareOtherDir(datadir, nodeId, conf_file='litecoin.conf'):
node_dir = os.path.join(datadir, str(nodeId)) node_dir = os.path.join(datadir, str(nodeId))
if not os.path.exists(node_dir): if not os.path.exists(node_dir):
@ -120,7 +129,8 @@ def prepareDir(datadir, nodeId, network_key, network_pubkey):
fp.write('zmqpubsmsg=tcp://127.0.0.1:' + str(BASE_ZMQ_PORT + nodeId) + '\n') fp.write('zmqpubsmsg=tcp://127.0.0.1:' + str(BASE_ZMQ_PORT + nodeId) + '\n')
fp.write('acceptnonstdtxn=0\n') fp.write('acceptnonstdtxn=0\n')
fp.write('minstakeinterval=5\n') fp.write('minstakeinterval=2\n')
fp.write('stakethreadconddelayms=1000\n')
for i in range(0, NUM_NODES): for i in range(0, NUM_NODES):
if nodeId == i: if nodeId == i:
@ -199,6 +209,7 @@ def signal_handler(sig, frame):
global stop_test global stop_test
print('signal {} detected.'.format(sig)) print('signal {} detected.'.format(sig))
stop_test = True stop_test = True
delay_event.set()
def run_loop(self): def run_loop(self):
@ -210,6 +221,24 @@ def run_loop(self):
btcRpc('generatetoaddress 1 {}'.format(self.btc_addr)) btcRpc('generatetoaddress 1 {}'.format(self.btc_addr))
def make_part_cli_rpc_func(node_id):
node_id = node_id
def rpc_func(method, params=None, wallet=None):
nonlocal node_id
cmd = method
if params:
for p in params:
if isinstance(p, dict) or isinstance(p, list):
cmd += ' "' + dumpje(p) + '"'
elif isinstance(p, int):
cmd += ' ' + str(p)
else:
cmd += ' "' + p + '"'
return partRpc(cmd, node_id)
return rpc_func
class Test(unittest.TestCase): class Test(unittest.TestCase):
@classmethod @classmethod
@ -233,6 +262,7 @@ class Test(unittest.TestCase):
cls.daemons = [] cls.daemons = []
cls.swap_clients = [] cls.swap_clients = []
cls.http_threads = []
cls.daemons.append(startDaemon(os.path.join(cfg.TEST_DATADIRS, str(BTC_NODE)), cfg.BITCOIN_BINDIR, cfg.BITCOIND)) cls.daemons.append(startDaemon(os.path.join(cfg.TEST_DATADIRS, str(BTC_NODE)), cfg.BITCOIN_BINDIR, cfg.BITCOIND))
logging.info('Started %s %d', cfg.BITCOIND, cls.daemons[-1].pid) logging.info('Started %s %d', cfg.BITCOIND, cls.daemons[-1].pid)
@ -242,8 +272,22 @@ class Test(unittest.TestCase):
for i in range(NUM_NODES): for i in range(NUM_NODES):
cls.daemons.append(startDaemon(os.path.join(cfg.TEST_DATADIRS, str(i)), cfg.PARTICL_BINDIR, cfg.PARTICLD)) cls.daemons.append(startDaemon(os.path.join(cfg.TEST_DATADIRS, str(i)), cfg.PARTICL_BINDIR, cfg.PARTICLD))
logging.info('Started %s %d', cfg.PARTICLD, cls.daemons[-1].pid) logging.info('Started %s %d', cfg.PARTICLD, cls.daemons[-1].pid)
time.sleep(1)
for i in range(NUM_NODES): for i in range(NUM_NODES):
# Load mnemonics after all nodes have started to avoid staking getting stuck in TryToSync
rpc = make_part_cli_rpc_func(i)
waitForRPC(rpc)
if i == 0:
rpc('extkeyimportmaster', ['abandon baby cabbage dad eager fabric gadget habit ice kangaroo lab absorb'])
elif i == 1:
rpc('extkeyimportmaster', ['pact mammal barrel matrix local final lecture chunk wasp survey bid various book strong spread fall ozone daring like topple door fatigue limb olympic', '', 'true'])
rpc('getnewextaddress', ['lblExtTest'])
rpc('rescanblockchain')
else:
rpc('extkeyimportmaster', [rpc('mnemonic', ['new'])['master']])
# Lower output split threshold for more stakeable outputs
rpc('walletsettings', ['stakingoptions', {'stakecombinethreshold': 100, 'stakesplitthreshold': 200}])
basicswap_dir = os.path.join(os.path.join(cfg.TEST_DATADIRS, str(i)), 'basicswap') basicswap_dir = os.path.join(os.path.join(cfg.TEST_DATADIRS, str(i)), 'basicswap')
settings_path = os.path.join(basicswap_dir, cfg.CONFIG_FILENAME) settings_path = os.path.join(basicswap_dir, cfg.CONFIG_FILENAME)
with open(settings_path) as fs: with open(settings_path) as fs:
@ -255,10 +299,10 @@ class Test(unittest.TestCase):
sc.setDaemonPID(Coins.PART, cls.daemons[2 + i].pid) sc.setDaemonPID(Coins.PART, cls.daemons[2 + i].pid)
sc.start() sc.start()
cls.swap_clients.append(sc) cls.swap_clients.append(sc)
cls.swap_clients[0].callrpc('extkeyimportmaster', ['abandon baby cabbage dad eager fabric gadget habit ice kangaroo lab absorb'])
cls.swap_clients[1].callrpc('extkeyimportmaster', ['pact mammal barrel matrix local final lecture chunk wasp survey bid various book strong spread fall ozone daring like topple door fatigue limb olympic', '', 'true']) t = HttpThread(cls.swap_clients[i].fp, TEST_HTTP_HOST, TEST_HTTP_PORT + i, False, cls.swap_clients[i])
cls.swap_clients[1].callrpc('getnewextaddress', ['lblExtTest']) cls.http_threads.append(t)
cls.swap_clients[1].callrpc('rescanblockchain') t.start()
waitForRPC(ltcRpc) waitForRPC(ltcRpc)
num_blocks = 500 num_blocks = 500
@ -280,16 +324,21 @@ class Test(unittest.TestCase):
ro = ltcRpc('getwalletinfo') ro = ltcRpc('getwalletinfo')
print('ltcRpc', ro) print('ltcRpc', ro)
cls.http_threads = []
for i in range(3):
t = HttpThread(cls.swap_clients[i].fp, TEST_HTTP_HOST, TEST_HTTP_PORT + i, False, cls.swap_clients[i])
cls.http_threads.append(t)
t.start()
signal.signal(signal.SIGINT, signal_handler) signal.signal(signal.SIGINT, signal_handler)
cls.update_thread = threading.Thread(target=run_loop, args=(cls,)) cls.update_thread = threading.Thread(target=run_loop, args=(cls,))
cls.update_thread.start() cls.update_thread.start()
# Wait for height, or sequencelock is thrown off by genesis blocktime
num_blocks = 3
logging.info('Waiting for Particl chain height %d', num_blocks)
for i in range(60):
particl_blocks = cls.swap_clients[0].callrpc('getblockchaininfo')['blocks']
print('particl_blocks', particl_blocks)
if particl_blocks >= num_blocks:
break
delay_event.wait(1)
assert(particl_blocks >= num_blocks)
@classmethod @classmethod
def tearDownClass(cls): def tearDownClass(cls):
global stop_test global stop_test
@ -300,72 +349,12 @@ class Test(unittest.TestCase):
t.stop() t.stop()
t.join() t.join()
for c in cls.swap_clients: for c in cls.swap_clients:
c.finalise()
c.fp.close() c.fp.close()
for d in cls.daemons:
logging.info('Interrupting %d', d.pid)
try:
d.send_signal(signal.SIGINT)
except Exception as e:
logging.info('Interrupting %d, error %s', d.pid, str(e))
for d in cls.daemons:
d.wait(timeout=10)
if d.stdout:
d.stdout.close()
if d.stderr:
d.stderr.close()
if d.stdin:
d.stdin.close()
super(Test, cls).tearDownClass()
def wait_for_offer(self, swap_client, offer_id): stopDaemons(cls.daemons)
logging.info('wait_for_offer %s', offer_id.hex())
for i in range(20):
time.sleep(1)
offers = swap_client.listOffers()
for offer in offers:
if offer.offer_id == offer_id:
return
raise ValueError('wait_for_offer timed out.')
def wait_for_bid(self, swap_client, bid_id): super(Test, cls).tearDownClass()
logging.info('wait_for_bid %s', bid_id.hex())
for i in range(20):
time.sleep(1)
bids = swap_client.listBids()
for bid in bids:
if bid[1] == bid_id and int(bid[5]) == 1:
return
raise ValueError('wait_for_bid timed out.')
def wait_for_in_progress(self, swap_client, bid_id, sent=False):
logging.info('wait_for_in_progress %s', bid_id.hex())
for i in range(20):
time.sleep(1)
swaps = swap_client.listSwapsInProgress()
for b in swaps:
if b[0] == bid_id:
return
raise ValueError('wait_for_in_progress timed out.')
def wait_for_bid_state(self, swap_client, bid_id, state, sent=False, seconds_for=30):
logging.info('wait_for_bid_state %s %s', bid_id.hex(), str(state))
for i in range(seconds_for):
time.sleep(1)
bid = swap_client.getBid(bid_id)
if bid and bid.state >= state:
return
raise ValueError('wait_for_bid_state timed out.')
def wait_for_bid_tx_state(self, swap_client, bid_id, initiate_state, participate_state, seconds_for=30):
logging.info('wait_for_bid_tx_state %s %s %s', bid_id.hex(), str(initiate_state), str(participate_state))
for i in range(seconds_for):
time.sleep(1)
bid = swap_client.getBid(bid_id)
if (initiate_state is None or bid.getITxState() == initiate_state) \
and (participate_state is None or bid.getPTxState() == participate_state):
return
raise ValueError('wait_for_bid_tx_state timed out.')
def test_01_verifyrawtransaction(self): def test_01_verifyrawtransaction(self):
txn = '0200000001eb6e5c4ebba4efa32f40c7314cad456a64008e91ee30b2dd0235ab9bb67fbdbb01000000ee47304402200956933242dde94f6cf8f195a470f8d02aef21ec5c9b66c5d3871594bdb74c9d02201d7e1b440de8f4da672d689f9e37e98815fb63dbc1706353290887eb6e8f7235012103dc1b24feb32841bc2f4375da91fa97834e5983668c2a39a6b7eadb60e7033f9d205a803b28fe2f86c17db91fa99d7ed2598f79b5677ffe869de2e478c0d1c02cc7514c606382012088a8201fe90717abb84b481c2a59112414ae56ec8acc72273642ca26cc7a5812fdc8f68876a914225fbfa4cb725b75e511810ac4d6f74069bdded26703520140b27576a914207eb66b2fd6ed9924d6217efc7fa7b38dfabe666888acffffffff01e0167118020000001976a9140044e188928710cecba8311f1cf412135b98145c88ac00000000' txn = '0200000001eb6e5c4ebba4efa32f40c7314cad456a64008e91ee30b2dd0235ab9bb67fbdbb01000000ee47304402200956933242dde94f6cf8f195a470f8d02aef21ec5c9b66c5d3871594bdb74c9d02201d7e1b440de8f4da672d689f9e37e98815fb63dbc1706353290887eb6e8f7235012103dc1b24feb32841bc2f4375da91fa97834e5983668c2a39a6b7eadb60e7033f9d205a803b28fe2f86c17db91fa99d7ed2598f79b5677ffe869de2e478c0d1c02cc7514c606382012088a8201fe90717abb84b481c2a59112414ae56ec8acc72273642ca26cc7a5812fdc8f68876a914225fbfa4cb725b75e511810ac4d6f74069bdded26703520140b27576a914207eb66b2fd6ed9924d6217efc7fa7b38dfabe666888acffffffff01e0167118020000001976a9140044e188928710cecba8311f1cf412135b98145c88ac00000000'
@ -406,21 +395,21 @@ class Test(unittest.TestCase):
offer_id = swap_clients[0].postOffer(Coins.PART, Coins.LTC, 100 * COIN, 0.1 * COIN, 100 * COIN, SwapTypes.SELLER_FIRST) offer_id = swap_clients[0].postOffer(Coins.PART, Coins.LTC, 100 * COIN, 0.1 * COIN, 100 * COIN, SwapTypes.SELLER_FIRST)
self.wait_for_offer(swap_clients[1], offer_id) wait_for_offer(delay_event, swap_clients[1], offer_id)
offers = swap_clients[1].listOffers() offers = swap_clients[1].listOffers()
assert(len(offers) == 1) assert(len(offers) == 1)
for offer in offers: for offer in offers:
if offer.offer_id == offer_id: if offer.offer_id == offer_id:
bid_id = swap_clients[1].postBid(offer_id, offer.amount_from) bid_id = swap_clients[1].postBid(offer_id, offer.amount_from)
self.wait_for_bid(swap_clients[0], bid_id) wait_for_bid(delay_event, swap_clients[0], bid_id)
swap_clients[0].acceptBid(bid_id) swap_clients[0].acceptBid(bid_id)
self.wait_for_in_progress(swap_clients[1], bid_id, sent=True) wait_for_in_progress(delay_event, swap_clients[1], bid_id, sent=True)
self.wait_for_bid_state(swap_clients[0], bid_id, BidStates.SWAP_COMPLETED, seconds_for=60) wait_for_bid(delay_event, swap_clients[0], bid_id, BidStates.SWAP_COMPLETED, wait_for=60)
self.wait_for_bid_state(swap_clients[1], bid_id, BidStates.SWAP_COMPLETED, sent=True, seconds_for=60) wait_for_bid(delay_event, swap_clients[1], bid_id, BidStates.SWAP_COMPLETED, sent=True, wait_for=60)
js_0 = json.loads(urlopen('http://localhost:1800/json').read()) js_0 = json.loads(urlopen('http://localhost:1800/json').read())
js_1 = json.loads(urlopen('http://localhost:1801/json').read()) js_1 = json.loads(urlopen('http://localhost:1801/json').read())
@ -433,19 +422,19 @@ class Test(unittest.TestCase):
offer_id = swap_clients[1].postOffer(Coins.LTC, Coins.PART, 10 * COIN, 9.0 * COIN, 10 * COIN, SwapTypes.SELLER_FIRST) offer_id = swap_clients[1].postOffer(Coins.LTC, Coins.PART, 10 * COIN, 9.0 * COIN, 10 * COIN, SwapTypes.SELLER_FIRST)
self.wait_for_offer(swap_clients[0], offer_id) wait_for_offer(delay_event, swap_clients[0], offer_id)
offers = swap_clients[0].listOffers() offers = swap_clients[0].listOffers()
for offer in offers: for offer in offers:
if offer.offer_id == offer_id: if offer.offer_id == offer_id:
bid_id = swap_clients[0].postBid(offer_id, offer.amount_from) bid_id = swap_clients[0].postBid(offer_id, offer.amount_from)
self.wait_for_bid(swap_clients[1], bid_id) wait_for_bid(delay_event, swap_clients[1], bid_id)
swap_clients[1].acceptBid(bid_id) swap_clients[1].acceptBid(bid_id)
self.wait_for_in_progress(swap_clients[0], bid_id, sent=True) wait_for_in_progress(delay_event, swap_clients[0], bid_id, sent=True)
self.wait_for_bid_state(swap_clients[0], bid_id, BidStates.SWAP_COMPLETED, sent=True, seconds_for=60) wait_for_bid(delay_event, swap_clients[0], bid_id, BidStates.SWAP_COMPLETED, sent=True, wait_for=60)
self.wait_for_bid_state(swap_clients[1], bid_id, BidStates.SWAP_COMPLETED, seconds_for=60) wait_for_bid(delay_event, swap_clients[1], bid_id, BidStates.SWAP_COMPLETED, wait_for=60)
js_0 = json.loads(urlopen('http://localhost:1800/json').read()) js_0 = json.loads(urlopen('http://localhost:1800/json').read())
js_1 = json.loads(urlopen('http://localhost:1801/json').read()) js_1 = json.loads(urlopen('http://localhost:1801/json').read())
@ -458,19 +447,19 @@ class Test(unittest.TestCase):
offer_id = swap_clients[0].postOffer(Coins.LTC, Coins.BTC, 10 * COIN, 0.1 * COIN, 10 * COIN, SwapTypes.SELLER_FIRST) offer_id = swap_clients[0].postOffer(Coins.LTC, Coins.BTC, 10 * COIN, 0.1 * COIN, 10 * COIN, SwapTypes.SELLER_FIRST)
self.wait_for_offer(swap_clients[1], offer_id) wait_for_offer(delay_event, swap_clients[1], offer_id)
offers = swap_clients[1].listOffers() offers = swap_clients[1].listOffers()
for offer in offers: for offer in offers:
if offer.offer_id == offer_id: if offer.offer_id == offer_id:
bid_id = swap_clients[1].postBid(offer_id, offer.amount_from) bid_id = swap_clients[1].postBid(offer_id, offer.amount_from)
self.wait_for_bid(swap_clients[0], bid_id) wait_for_bid(delay_event, swap_clients[0], bid_id)
swap_clients[0].acceptBid(bid_id) swap_clients[0].acceptBid(bid_id)
self.wait_for_in_progress(swap_clients[1], bid_id, sent=True) wait_for_in_progress(delay_event, swap_clients[1], bid_id, sent=True)
self.wait_for_bid_state(swap_clients[0], bid_id, BidStates.SWAP_COMPLETED, seconds_for=60) wait_for_bid(delay_event, swap_clients[0], bid_id, BidStates.SWAP_COMPLETED, wait_for=60)
self.wait_for_bid_state(swap_clients[1], bid_id, BidStates.SWAP_COMPLETED, sent=True, seconds_for=60) wait_for_bid(delay_event, swap_clients[1], bid_id, BidStates.SWAP_COMPLETED, sent=True, wait_for=60)
js_0bid = json.loads(urlopen('http://localhost:1800/json/bids/{}'.format(bid_id.hex())).read()) js_0bid = json.loads(urlopen('http://localhost:1800/json/bids/{}'.format(bid_id.hex())).read())
@ -488,18 +477,18 @@ class Test(unittest.TestCase):
offer_id = swap_clients[0].postOffer(Coins.LTC, Coins.BTC, 10 * COIN, 0.1 * COIN, 10 * COIN, SwapTypes.SELLER_FIRST, offer_id = swap_clients[0].postOffer(Coins.LTC, Coins.BTC, 10 * COIN, 0.1 * COIN, 10 * COIN, SwapTypes.SELLER_FIRST,
SEQUENCE_LOCK_BLOCKS, 10) SEQUENCE_LOCK_BLOCKS, 10)
self.wait_for_offer(swap_clients[1], offer_id) wait_for_offer(delay_event, swap_clients[1], offer_id)
offers = swap_clients[1].listOffers() offers = swap_clients[1].listOffers()
for offer in offers: for offer in offers:
if offer.offer_id == offer_id: if offer.offer_id == offer_id:
bid_id = swap_clients[1].postBid(offer_id, offer.amount_from) bid_id = swap_clients[1].postBid(offer_id, offer.amount_from)
self.wait_for_bid(swap_clients[0], bid_id) wait_for_bid(delay_event, swap_clients[0], bid_id)
swap_clients[1].abandonBid(bid_id) swap_clients[1].abandonBid(bid_id)
swap_clients[0].acceptBid(bid_id) swap_clients[0].acceptBid(bid_id)
self.wait_for_bid_state(swap_clients[0], bid_id, BidStates.SWAP_COMPLETED, seconds_for=60) wait_for_bid(delay_event, swap_clients[0], bid_id, BidStates.SWAP_COMPLETED, wait_for=60)
self.wait_for_bid_state(swap_clients[1], bid_id, BidStates.BID_ABANDONED, sent=True, seconds_for=60) wait_for_bid(delay_event, swap_clients[1], bid_id, BidStates.BID_ABANDONED, sent=True, wait_for=60)
js_0 = json.loads(urlopen('http://localhost:1800/json').read()) js_0 = json.loads(urlopen('http://localhost:1800/json').read())
js_1 = json.loads(urlopen('http://localhost:1801/json').read()) js_1 = json.loads(urlopen('http://localhost:1801/json').read())
@ -514,17 +503,17 @@ class Test(unittest.TestCase):
offer_id = swap_clients[0].postOffer(Coins.BTC, Coins.LTC, 10 * COIN, 10 * COIN, 10 * COIN, SwapTypes.SELLER_FIRST) offer_id = swap_clients[0].postOffer(Coins.BTC, Coins.LTC, 10 * COIN, 10 * COIN, 10 * COIN, SwapTypes.SELLER_FIRST)
self.wait_for_offer(swap_clients[0], offer_id) wait_for_offer(delay_event, swap_clients[0], offer_id)
offers = swap_clients[0].listOffers() offers = swap_clients[0].listOffers()
for offer in offers: for offer in offers:
if offer.offer_id == offer_id: if offer.offer_id == offer_id:
bid_id = swap_clients[0].postBid(offer_id, offer.amount_from) bid_id = swap_clients[0].postBid(offer_id, offer.amount_from)
self.wait_for_bid(swap_clients[0], bid_id) wait_for_bid(delay_event, swap_clients[0], bid_id)
swap_clients[0].acceptBid(bid_id) swap_clients[0].acceptBid(bid_id)
self.wait_for_bid_tx_state(swap_clients[0], bid_id, TxStates.TX_REDEEMED, TxStates.TX_REDEEMED, seconds_for=60) wait_for_bid_tx_state(delay_event, swap_clients[0], bid_id, TxStates.TX_REDEEMED, TxStates.TX_REDEEMED, wait_for=60)
self.wait_for_bid_state(swap_clients[0], bid_id, BidStates.SWAP_COMPLETED, seconds_for=60) wait_for_bid(delay_event, swap_clients[0], bid_id, BidStates.SWAP_COMPLETED, wait_for=60)
js_0 = json.loads(urlopen('http://localhost:1800/json').read()) js_0 = json.loads(urlopen('http://localhost:1800/json').read())
assert(js_0['num_swapping'] == 0 and js_0['num_watched_outputs'] == 0) assert(js_0['num_swapping'] == 0 and js_0['num_watched_outputs'] == 0)
@ -538,18 +527,18 @@ class Test(unittest.TestCase):
offer_id = swap_clients[0].postOffer(Coins.BTC, Coins.LTC, 0.001 * COIN, 1.0 * COIN, 0.001 * COIN, SwapTypes.SELLER_FIRST) offer_id = swap_clients[0].postOffer(Coins.BTC, Coins.LTC, 0.001 * COIN, 1.0 * COIN, 0.001 * COIN, SwapTypes.SELLER_FIRST)
self.wait_for_offer(swap_clients[0], offer_id) wait_for_offer(delay_event, swap_clients[0], offer_id)
offers = swap_clients[0].listOffers() offers = swap_clients[0].listOffers()
for offer in offers: for offer in offers:
if offer.offer_id == offer_id: if offer.offer_id == offer_id:
bid_id = swap_clients[0].postBid(offer_id, offer.amount_from) bid_id = swap_clients[0].postBid(offer_id, offer.amount_from)
self.wait_for_bid(swap_clients[0], bid_id) wait_for_bid(delay_event, swap_clients[0], bid_id)
swap_clients[0].acceptBid(bid_id) swap_clients[0].acceptBid(bid_id)
swap_clients[0].coin_clients[Coins.BTC]['override_feerate'] = 10.0 swap_clients[0].coin_clients[Coins.BTC]['override_feerate'] = 10.0
swap_clients[0].coin_clients[Coins.LTC]['override_feerate'] = 10.0 swap_clients[0].coin_clients[Coins.LTC]['override_feerate'] = 10.0
self.wait_for_bid_state(swap_clients[0], bid_id, BidStates.BID_ERROR, seconds_for=60) wait_for_bid(delay_event, swap_clients[0], bid_id, BidStates.BID_ERROR, wait_for=60)
swap_clients[0].abandonBid(bid_id) swap_clients[0].abandonBid(bid_id)
del swap_clients[0].coin_clients[Coins.BTC]['override_feerate'] del swap_clients[0].coin_clients[Coins.BTC]['override_feerate']
@ -563,21 +552,21 @@ class Test(unittest.TestCase):
return # TODO return # TODO
self.wait_for_offer(swap_clients[1], offer_id) wait_for_offer(delay_event, swap_clients[1], offer_id)
offers = swap_clients[1].listOffers() offers = swap_clients[1].listOffers()
assert(len(offers) == 1) assert(len(offers) == 1)
for offer in offers: for offer in offers:
if offer.offer_id == offer_id: if offer.offer_id == offer_id:
bid_id = swap_clients[1].postBid(offer_id, offer.amount_from) bid_id = swap_clients[1].postBid(offer_id, offer.amount_from)
self.wait_for_bid(swap_clients[0], bid_id) wait_for_bid(delay_event, swap_clients[0], bid_id)
swap_clients[0].acceptBid(bid_id) swap_clients[0].acceptBid(bid_id)
self.wait_for_in_progress(swap_clients[1], bid_id, sent=True) wait_for_in_progress(delay_event, swap_clients[1], bid_id, sent=True)
self.wait_for_bid_state(swap_clients[0], bid_id, BidStates.SWAP_COMPLETED, seconds_for=60) wait_for_bid(delay_event, swap_clients[0], bid_id, BidStates.SWAP_COMPLETED, wait_for=60)
self.wait_for_bid_state(swap_clients[1], bid_id, BidStates.SWAP_COMPLETED, sent=True, seconds_for=60) wait_for_bid(delay_event, swap_clients[1], bid_id, BidStates.SWAP_COMPLETED, sent=True, wait_for=60)
js_0 = json.loads(urlopen('http://localhost:1800/json').read()) js_0 = json.loads(urlopen('http://localhost:1800/json').read())
js_1 = json.loads(urlopen('http://localhost:1801/json').read()) js_1 = json.loads(urlopen('http://localhost:1801/json').read())
@ -590,15 +579,15 @@ class Test(unittest.TestCase):
offer_id = swap_clients[0].postOffer(Coins.PART, Coins.LTC, 100 * COIN, 0.1 * COIN, 100 * COIN, SwapTypes.SELLER_FIRST, auto_accept_bids=True) offer_id = swap_clients[0].postOffer(Coins.PART, Coins.LTC, 100 * COIN, 0.1 * COIN, 100 * COIN, SwapTypes.SELLER_FIRST, auto_accept_bids=True)
self.wait_for_offer(swap_clients[1], offer_id) wait_for_offer(delay_event, swap_clients[1], offer_id)
offers = swap_clients[1].listOffers() offers = swap_clients[1].listOffers()
assert(len(offers) >= 1) assert(len(offers) >= 1)
for offer in offers: for offer in offers:
if offer.offer_id == offer_id: if offer.offer_id == offer_id:
bid_id = swap_clients[1].postBid(offer_id, offer.amount_from) bid_id = swap_clients[1].postBid(offer_id, offer.amount_from)
self.wait_for_bid_state(swap_clients[0], bid_id, BidStates.SWAP_COMPLETED, seconds_for=60) wait_for_bid(delay_event, swap_clients[0], bid_id, BidStates.SWAP_COMPLETED, wait_for=60)
self.wait_for_bid_state(swap_clients[1], bid_id, BidStates.SWAP_COMPLETED, sent=True, seconds_for=60) wait_for_bid(delay_event, swap_clients[1], bid_id, BidStates.SWAP_COMPLETED, sent=True, wait_for=60)
def pass_99_delay(self): def pass_99_delay(self):
global stop_test global stop_test

@ -50,11 +50,22 @@ from basicswap.http_server import (
HttpThread, HttpThread,
) )
from tests.basicswap.common import ( from tests.basicswap.common import (
prepareDataDir,
make_rpc_func,
checkForks, checkForks,
stopDaemons,
wait_for_bid,
wait_for_offer,
wait_for_no_offer,
wait_for_none_active,
TEST_HTTP_HOST, TEST_HTTP_HOST,
TEST_HTTP_PORT, TEST_HTTP_PORT,
BASE_RPC_PORT,
BASE_ZMQ_PORT,
BTC_BASE_PORT,
BTC_BASE_RPC_PORT,
PREFIX_SECRET_KEY_REGTEST,
) )
from basicswap.contrib.rpcauth import generate_salt, password_to_hmac
from bin.basicswap_run import startDaemon, startXmrDaemon from bin.basicswap_run import startDaemon, startXmrDaemon
@ -65,21 +76,11 @@ NUM_XMR_NODES = 3
NUM_BTC_NODES = 3 NUM_BTC_NODES = 3
TEST_DIR = cfg.TEST_DATADIRS TEST_DIR = cfg.TEST_DATADIRS
BASE_PORT = 14792
BASE_RPC_PORT = 19792
BASE_ZMQ_PORT = 20792
BTC_BASE_PORT = 31792
BTC_BASE_RPC_PORT = 32792
BTC_BASE_ZMQ_PORT = 33792
XMR_BASE_P2P_PORT = 17792 XMR_BASE_P2P_PORT = 17792
XMR_BASE_RPC_PORT = 21792 XMR_BASE_RPC_PORT = 21792
XMR_BASE_ZMQ_PORT = 22792 XMR_BASE_ZMQ_PORT = 22792
XMR_BASE_WALLET_RPC_PORT = 23792 XMR_BASE_WALLET_RPC_PORT = 23792
PREFIX_SECRET_KEY_REGTEST = 0x2e
delay_event = threading.Event() delay_event = threading.Event()
stop_test = False stop_test = False
@ -111,47 +112,6 @@ def prepareXmrDataDir(datadir, node_id, conf_file):
fp.write('add-exclusive-node=127.0.0.1:{}\n'.format(XMR_BASE_P2P_PORT + i)) fp.write('add-exclusive-node=127.0.0.1:{}\n'.format(XMR_BASE_P2P_PORT + i))
def prepareDataDir(datadir, node_id, conf_file, dir_prefix, base_p2p_port=BASE_PORT, base_rpc_port=BASE_RPC_PORT):
node_dir = os.path.join(datadir, dir_prefix + str(node_id))
if not os.path.exists(node_dir):
os.makedirs(node_dir)
cfg_file_path = os.path.join(node_dir, conf_file)
if os.path.exists(cfg_file_path):
return
with open(cfg_file_path, 'w+') as fp:
fp.write('regtest=1\n')
fp.write('[regtest]\n')
fp.write('port=' + str(base_p2p_port + node_id) + '\n')
fp.write('rpcport=' + str(base_rpc_port + node_id) + '\n')
salt = generate_salt(16)
fp.write('rpcauth={}:{}${}\n'.format('test' + str(node_id), salt, password_to_hmac(salt, 'test_pass' + str(node_id))))
fp.write('daemon=0\n')
fp.write('printtoconsole=0\n')
fp.write('server=1\n')
fp.write('discover=0\n')
fp.write('listenonion=0\n')
fp.write('bind=127.0.0.1\n')
fp.write('debug=1\n')
fp.write('debugexclude=libevent\n')
fp.write('fallbackfee=0.01\n')
fp.write('acceptnonstdtxn=0\n')
fp.write('txindex=1\n')
fp.write('findpeers=0\n')
# minstakeinterval=5 # Using walletsettings stakelimit instead
if base_p2p_port == BASE_PORT: # Particl
fp.write('zmqpubsmsg=tcp://127.0.0.1:{}\n'.format(BASE_ZMQ_PORT + node_id))
for i in range(0, NUM_NODES):
if node_id == i:
continue
fp.write('addnode=127.0.0.1:{}\n'.format(base_p2p_port + i))
def startXmrWalletRPC(node_dir, bin_dir, wallet_bin, node_id, opts=[]): def startXmrWalletRPC(node_dir, bin_dir, wallet_bin, node_id, opts=[]):
daemon_bin = os.path.expanduser(os.path.join(bin_dir, wallet_bin)) daemon_bin = os.path.expanduser(os.path.join(bin_dir, wallet_bin))
@ -236,24 +196,10 @@ def prepare_swapclient_dir(datadir, node_id, network_key, network_pubkey):
json.dump(settings, fp, indent=4) json.dump(settings, fp, indent=4)
def partRpc(cmd, node_id=0):
return callrpc_cli(cfg.PARTICL_BINDIR, os.path.join(TEST_DIR, 'part_' + str(node_id)), 'regtest', cmd, cfg.PARTICL_CLI)
def btcRpc(cmd, node_id=0): def btcRpc(cmd, node_id=0):
return callrpc_cli(cfg.BITCOIN_BINDIR, os.path.join(TEST_DIR, 'btc_' + str(node_id)), 'regtest', cmd, cfg.BITCOIN_CLI) return callrpc_cli(cfg.BITCOIN_BINDIR, os.path.join(TEST_DIR, 'btc_' + str(node_id)), 'regtest', cmd, cfg.BITCOIN_CLI)
def make_rpc_func(node_id, base_rpc_port=BASE_RPC_PORT):
node_id = node_id
auth = 'test{0}:test_pass{0}'.format(node_id)
def rpc_func(method, params=None, wallet=None):
nonlocal node_id, auth
return callrpc(base_rpc_port + node_id, auth, method, params, wallet)
return rpc_func
def signal_handler(sig, frame): def signal_handler(sig, frame):
global stop_test global stop_test
logging.info('signal {} detected.'.format(sig)) logging.info('signal {} detected.'.format(sig))
@ -354,7 +300,20 @@ class Test(unittest.TestCase):
cls.part_daemons.append(startDaemon(os.path.join(TEST_DIR, 'part_' + str(i)), cfg.PARTICL_BINDIR, cfg.PARTICLD)) cls.part_daemons.append(startDaemon(os.path.join(TEST_DIR, 'part_' + str(i)), cfg.PARTICL_BINDIR, cfg.PARTICLD))
logging.info('Started %s %d', cfg.PARTICLD, cls.part_daemons[-1].pid) logging.info('Started %s %d', cfg.PARTICLD, cls.part_daemons[-1].pid)
waitForRPC(make_rpc_func(i)) for i in range(NUM_NODES):
# Load mnemonics after all nodes have started to avoid staking getting stuck in TryToSync
rpc = make_rpc_func(i)
waitForRPC(rpc)
if i == 0:
rpc('extkeyimportmaster', ['abandon baby cabbage dad eager fabric gadget habit ice kangaroo lab absorb'])
elif i == 1:
rpc('extkeyimportmaster', ['pact mammal barrel matrix local final lecture chunk wasp survey bid various book strong spread fall ozone daring like topple door fatigue limb olympic', '', 'true'])
rpc('getnewextaddress', ['lblExtTest'])
rpc('rescanblockchain')
else:
rpc('extkeyimportmaster', [rpc('mnemonic', ['new'])['master']])
# Lower output split threshold for more stakeable outputs
rpc('walletsettings', ['stakingoptions', {'stakecombinethreshold': 100, 'stakesplitthreshold': 200}])
for i in range(NUM_BTC_NODES): for i in range(NUM_BTC_NODES):
prepareDataDir(TEST_DIR, i, 'bitcoin.conf', 'btc_', base_p2p_port=BTC_BASE_PORT, base_rpc_port=BTC_BASE_RPC_PORT) prepareDataDir(TEST_DIR, i, 'bitcoin.conf', 'btc_', base_p2p_port=BTC_BASE_PORT, base_rpc_port=BTC_BASE_RPC_PORT)
@ -401,13 +360,6 @@ class Test(unittest.TestCase):
sc.start() sc.start()
cls.swap_clients.append(sc) cls.swap_clients.append(sc)
logging.info('Initialising coin networks.')
cls.swap_clients[0].callrpc('extkeyimportmaster', ['abandon baby cabbage dad eager fabric gadget habit ice kangaroo lab absorb'])
cls.swap_clients[1].callrpc('extkeyimportmaster', ['pact mammal barrel matrix local final lecture chunk wasp survey bid various book strong spread fall ozone daring like topple door fatigue limb olympic', '', 'true'])
cls.swap_clients[1].callrpc('getnewextaddress', ['lblExtTest'])
cls.swap_clients[1].callrpc('rescanblockchain')
for i in range(3):
t = HttpThread(cls.swap_clients[i].fp, TEST_HTTP_HOST, TEST_HTTP_PORT + i, False, cls.swap_clients[i]) t = HttpThread(cls.swap_clients[i].fp, TEST_HTTP_HOST, TEST_HTTP_PORT + i, False, cls.swap_clients[i])
cls.http_threads.append(t) cls.http_threads.append(t)
t.start() t.start()
@ -459,100 +411,18 @@ class Test(unittest.TestCase):
t.stop() t.stop()
t.join() t.join()
for c in cls.swap_clients: for c in cls.swap_clients:
c.finalise()
c.fp.close() c.fp.close()
for d in cls.xmr_daemons: stopDaemons(cls.xmr_daemons)
logging.info('Interrupting %d', d.pid) stopDaemons(cls.part_daemons)
try: stopDaemons(cls.btc_daemons)
d.send_signal(signal.SIGINT)
except Exception as e:
logging.info('Interrupting %d, error %s', d.pid, str(e))
for d in cls.xmr_daemons:
try:
d.wait(timeout=20)
for fp in (d.stdout, d.stderr, d.stdin):
if fp:
fp.close()
except Exception as e:
logging.info('Closing %d, error %s', d.pid, str(e))
for d in cls.part_daemons + cls.btc_daemons:
logging.info('Interrupting %d', d.pid)
try:
d.send_signal(signal.SIGINT)
except Exception as e:
logging.info('Interrupting %d, error %s', d.pid, str(e))
for d in cls.part_daemons + cls.btc_daemons:
try:
d.wait(timeout=20)
for fp in (d.stdout, d.stderr, d.stdin):
if fp:
fp.close()
except Exception as e:
logging.info('Closing %d, error %s', d.pid, str(e))
super(Test, cls).tearDownClass() super(Test, cls).tearDownClass()
def callxmrnodewallet(self, node_id, method, params=None): def callxmrnodewallet(self, node_id, method, params=None):
return callrpc_xmr(XMR_BASE_WALLET_RPC_PORT + node_id, self.xmr_wallet_auth[node_id], method, params) return callrpc_xmr(XMR_BASE_WALLET_RPC_PORT + node_id, self.xmr_wallet_auth[node_id], method, params)
def wait_for_offer(self, swap_client, offer_id, wait_for=20):
logging.info('wait_for_offer %s', offer_id.hex())
for i in range(wait_for):
if stop_test:
raise ValueError('Test stopped.')
time.sleep(1)
offers = swap_client.listOffers()
for offer in offers:
if offer.offer_id == offer_id:
return
raise ValueError('wait_for_offer timed out.')
def wait_for_no_offer(self, swap_client, offer_id, wait_for=20):
logging.info('wait_for_no_offer %s', offer_id.hex())
for i in range(wait_for):
if stop_test:
raise ValueError('Test stopped.')
time.sleep(1)
offers = swap_client.listOffers()
found_offer = False
for offer in offers:
if offer.offer_id == offer_id:
found_offer = True
break
if not found_offer:
return True
raise ValueError('wait_for_offer timed out.')
def wait_for_bid(self, swap_client, bid_id, state=None, sent=False, wait_for=20):
logging.info('wait_for_bid %s', bid_id.hex())
for i in range(wait_for):
if stop_test:
raise ValueError('Test stopped.')
time.sleep(1)
bids = swap_client.listBids(sent=sent)
for bid in bids:
if bid[1] == bid_id:
if state is not None and state != bid[4]:
continue
return
raise ValueError('wait_for_bid timed out.')
def wait_for_none_active(self, port, wait_for=30):
for i in range(wait_for):
if stop_test:
raise ValueError('Test stopped.')
time.sleep(1)
js = json.loads(urlopen('http://localhost:{}/json'.format(port)).read())
if js['num_swapping'] == 0 and js['num_watched_outputs'] == 0:
return
raise ValueError('wait_for_none_active timed out.')
def delay_for(self, delay_for=60):
logging.info('Delaying for {} seconds.'.format(delay_for))
delay_event.clear()
delay_event.wait(delay_for)
def test_01_part_xmr(self): def test_01_part_xmr(self):
logging.info('---------- Test PART to XMR') logging.info('---------- Test PART to XMR')
swap_clients = self.swap_clients swap_clients = self.swap_clients
@ -562,22 +432,22 @@ class Test(unittest.TestCase):
assert(make_int(js_1[str(int(Coins.XMR))]['unconfirmed'], scale=12) > 0) assert(make_int(js_1[str(int(Coins.XMR))]['unconfirmed'], scale=12) > 0)
offer_id = swap_clients[0].postOffer(Coins.PART, Coins.XMR, 100 * COIN, 0.11 * XMR_COIN, 100 * COIN, SwapTypes.XMR_SWAP) offer_id = swap_clients[0].postOffer(Coins.PART, Coins.XMR, 100 * COIN, 0.11 * XMR_COIN, 100 * COIN, SwapTypes.XMR_SWAP)
self.wait_for_offer(swap_clients[1], offer_id) wait_for_offer(delay_event, swap_clients[1], offer_id)
offers = swap_clients[1].listOffers(filters={'offer_id': offer_id}) offers = swap_clients[1].listOffers(filters={'offer_id': offer_id})
assert(len(offers) == 1) assert(len(offers) == 1)
offer = offers[0] offer = offers[0]
bid_id = swap_clients[1].postXmrBid(offer_id, offer.amount_from) bid_id = swap_clients[1].postXmrBid(offer_id, offer.amount_from)
self.wait_for_bid(swap_clients[0], bid_id, BidStates.BID_RECEIVED) wait_for_bid(delay_event, swap_clients[0], bid_id, BidStates.BID_RECEIVED)
bid, xmr_swap = swap_clients[0].getXmrBid(bid_id) bid, xmr_swap = swap_clients[0].getXmrBid(bid_id)
assert(xmr_swap) assert(xmr_swap)
swap_clients[0].acceptXmrBid(bid_id) swap_clients[0].acceptXmrBid(bid_id)
self.wait_for_bid(swap_clients[0], bid_id, BidStates.SWAP_COMPLETED, wait_for=180) wait_for_bid(delay_event, swap_clients[0], bid_id, BidStates.SWAP_COMPLETED, wait_for=180)
self.wait_for_bid(swap_clients[1], bid_id, BidStates.SWAP_COMPLETED, sent=True) wait_for_bid(delay_event, swap_clients[1], bid_id, BidStates.SWAP_COMPLETED, sent=True)
js_0_end = json.loads(urlopen('http://localhost:1800/json/wallets').read()) js_0_end = json.loads(urlopen('http://localhost:1800/json/wallets').read())
end_xmr = float(js_0_end['6']['balance']) + float(js_0_end['6']['unconfirmed']) end_xmr = float(js_0_end['6']['balance']) + float(js_0_end['6']['unconfirmed'])
@ -592,12 +462,12 @@ class Test(unittest.TestCase):
offer_id = swap_clients[0].postOffer( offer_id = swap_clients[0].postOffer(
Coins.PART, Coins.XMR, 101 * COIN, 0.12 * XMR_COIN, 101 * COIN, SwapTypes.XMR_SWAP, Coins.PART, Coins.XMR, 101 * COIN, 0.12 * XMR_COIN, 101 * COIN, SwapTypes.XMR_SWAP,
lock_type=SEQUENCE_LOCK_BLOCKS, lock_value=12) lock_type=SEQUENCE_LOCK_BLOCKS, lock_value=12)
self.wait_for_offer(swap_clients[1], offer_id) wait_for_offer(delay_event, swap_clients[1], offer_id)
offer = swap_clients[1].getOffer(offer_id) offer = swap_clients[1].getOffer(offer_id)
bid_id = swap_clients[1].postXmrBid(offer_id, offer.amount_from) bid_id = swap_clients[1].postXmrBid(offer_id, offer.amount_from)
self.wait_for_bid(swap_clients[0], bid_id, BidStates.BID_RECEIVED) wait_for_bid(delay_event, swap_clients[0], bid_id, BidStates.BID_RECEIVED)
bid, xmr_swap = swap_clients[0].getXmrBid(bid_id) bid, xmr_swap = swap_clients[0].getXmrBid(bid_id)
assert(xmr_swap) assert(xmr_swap)
@ -606,8 +476,8 @@ class Test(unittest.TestCase):
swap_clients[0].acceptXmrBid(bid_id) swap_clients[0].acceptXmrBid(bid_id)
self.wait_for_bid(swap_clients[0], bid_id, BidStates.XMR_SWAP_FAILED_REFUNDED, wait_for=180) wait_for_bid(delay_event, swap_clients[0], bid_id, BidStates.XMR_SWAP_FAILED_REFUNDED, wait_for=180)
self.wait_for_bid(swap_clients[1], bid_id, BidStates.XMR_SWAP_FAILED_REFUNDED, sent=True) wait_for_bid(delay_event, swap_clients[1], bid_id, BidStates.XMR_SWAP_FAILED_REFUNDED, sent=True)
js_w0_after = json.loads(urlopen('http://localhost:1800/json/wallets').read()) js_w0_after = json.loads(urlopen('http://localhost:1800/json/wallets').read())
print('[rm] js_w0_before', json.dumps(js_w0_before)) print('[rm] js_w0_before', json.dumps(js_w0_before))
@ -622,12 +492,12 @@ class Test(unittest.TestCase):
offer_id = swap_clients[0].postOffer( offer_id = swap_clients[0].postOffer(
Coins.PART, Coins.XMR, 101 * COIN, 0.13 * XMR_COIN, 101 * COIN, SwapTypes.XMR_SWAP, Coins.PART, Coins.XMR, 101 * COIN, 0.13 * XMR_COIN, 101 * COIN, SwapTypes.XMR_SWAP,
lock_type=SEQUENCE_LOCK_BLOCKS, lock_value=12) lock_type=SEQUENCE_LOCK_BLOCKS, lock_value=12)
self.wait_for_offer(swap_clients[1], offer_id) wait_for_offer(delay_event, swap_clients[1], offer_id)
offer = swap_clients[1].getOffer(offer_id) offer = swap_clients[1].getOffer(offer_id)
bid_id = swap_clients[1].postXmrBid(offer_id, offer.amount_from) bid_id = swap_clients[1].postXmrBid(offer_id, offer.amount_from)
self.wait_for_bid(swap_clients[0], bid_id, BidStates.BID_RECEIVED) wait_for_bid(delay_event, swap_clients[0], bid_id, BidStates.BID_RECEIVED)
bid, xmr_swap = swap_clients[0].getXmrBid(bid_id) bid, xmr_swap = swap_clients[0].getXmrBid(bid_id)
assert(xmr_swap) assert(xmr_swap)
@ -637,13 +507,13 @@ class Test(unittest.TestCase):
swap_clients[0].acceptXmrBid(bid_id) swap_clients[0].acceptXmrBid(bid_id)
self.wait_for_bid(swap_clients[0], bid_id, BidStates.BID_ABANDONED, wait_for=180) wait_for_bid(delay_event, swap_clients[0], bid_id, BidStates.BID_ABANDONED, wait_for=180)
self.wait_for_bid(swap_clients[1], bid_id, BidStates.XMR_SWAP_FAILED_SWIPED, wait_for=80, sent=True) wait_for_bid(delay_event, swap_clients[1], bid_id, BidStates.XMR_SWAP_FAILED_SWIPED, wait_for=80, sent=True)
js_w0_after = json.loads(urlopen('http://localhost:1800/json/wallets').read()) js_w0_after = json.loads(urlopen('http://localhost:1800/json/wallets').read())
self.wait_for_none_active(1800) wait_for_none_active(delay_event, 1800)
self.wait_for_none_active(1801) wait_for_none_active(delay_event, 1801)
def test_04_follower_recover_b_lock_tx(self): def test_04_follower_recover_b_lock_tx(self):
logging.info('---------- Test PART to XMR follower recovers coin b lock tx') logging.info('---------- Test PART to XMR follower recovers coin b lock tx')
@ -653,12 +523,12 @@ class Test(unittest.TestCase):
offer_id = swap_clients[0].postOffer( offer_id = swap_clients[0].postOffer(
Coins.PART, Coins.XMR, 101 * COIN, 0.14 * XMR_COIN, 101 * COIN, SwapTypes.XMR_SWAP, Coins.PART, Coins.XMR, 101 * COIN, 0.14 * XMR_COIN, 101 * COIN, SwapTypes.XMR_SWAP,
lock_type=SEQUENCE_LOCK_BLOCKS, lock_value=18) lock_type=SEQUENCE_LOCK_BLOCKS, lock_value=18)
self.wait_for_offer(swap_clients[1], offer_id) wait_for_offer(delay_event, swap_clients[1], offer_id)
offer = swap_clients[1].getOffer(offer_id) offer = swap_clients[1].getOffer(offer_id)
bid_id = swap_clients[1].postXmrBid(offer_id, offer.amount_from) bid_id = swap_clients[1].postXmrBid(offer_id, offer.amount_from)
self.wait_for_bid(swap_clients[0], bid_id, BidStates.BID_RECEIVED) wait_for_bid(delay_event, swap_clients[0], bid_id, BidStates.BID_RECEIVED)
bid, xmr_swap = swap_clients[0].getXmrBid(bid_id) bid, xmr_swap = swap_clients[0].getXmrBid(bid_id)
assert(xmr_swap) assert(xmr_swap)
@ -667,28 +537,28 @@ class Test(unittest.TestCase):
swap_clients[0].acceptXmrBid(bid_id) swap_clients[0].acceptXmrBid(bid_id)
self.wait_for_bid(swap_clients[0], bid_id, BidStates.XMR_SWAP_FAILED_REFUNDED, wait_for=180) wait_for_bid(delay_event, swap_clients[0], bid_id, BidStates.XMR_SWAP_FAILED_REFUNDED, wait_for=180)
self.wait_for_bid(swap_clients[1], bid_id, BidStates.XMR_SWAP_FAILED_REFUNDED, sent=True) wait_for_bid(delay_event, swap_clients[1], bid_id, BidStates.XMR_SWAP_FAILED_REFUNDED, sent=True)
def test_05_btc_xmr(self): def test_05_btc_xmr(self):
logging.info('---------- Test BTC to XMR') logging.info('---------- Test BTC to XMR')
swap_clients = self.swap_clients swap_clients = self.swap_clients
offer_id = swap_clients[0].postOffer(Coins.BTC, Coins.XMR, 10 * COIN, 100 * XMR_COIN, 10 * COIN, SwapTypes.XMR_SWAP) offer_id = swap_clients[0].postOffer(Coins.BTC, Coins.XMR, 10 * COIN, 100 * XMR_COIN, 10 * COIN, SwapTypes.XMR_SWAP)
self.wait_for_offer(swap_clients[1], offer_id) wait_for_offer(delay_event, swap_clients[1], offer_id)
offers = swap_clients[1].listOffers(filters={'offer_id': offer_id}) offers = swap_clients[1].listOffers(filters={'offer_id': offer_id})
offer = offers[0] offer = offers[0]
bid_id = swap_clients[1].postXmrBid(offer_id, offer.amount_from) bid_id = swap_clients[1].postXmrBid(offer_id, offer.amount_from)
self.wait_for_bid(swap_clients[0], bid_id, BidStates.BID_RECEIVED) wait_for_bid(delay_event, swap_clients[0], bid_id, BidStates.BID_RECEIVED)
bid, xmr_swap = swap_clients[0].getXmrBid(bid_id) bid, xmr_swap = swap_clients[0].getXmrBid(bid_id)
assert(xmr_swap) assert(xmr_swap)
swap_clients[0].acceptXmrBid(bid_id) swap_clients[0].acceptXmrBid(bid_id)
self.wait_for_bid(swap_clients[0], bid_id, BidStates.SWAP_COMPLETED, wait_for=180) wait_for_bid(delay_event, swap_clients[0], bid_id, BidStates.SWAP_COMPLETED, wait_for=180)
self.wait_for_bid(swap_clients[1], bid_id, BidStates.SWAP_COMPLETED, sent=True) wait_for_bid(delay_event, swap_clients[1], bid_id, BidStates.SWAP_COMPLETED, sent=True)
def test_06_multiple_swaps(self): def test_06_multiple_swaps(self):
logging.info('---------- Test Multiple concurrent swaps') logging.info('---------- Test Multiple concurrent swaps')
@ -696,9 +566,9 @@ class Test(unittest.TestCase):
offer1_id = swap_clients[0].postOffer(Coins.BTC, Coins.XMR, 10 * COIN, 100 * XMR_COIN, 10 * COIN, SwapTypes.XMR_SWAP) offer1_id = swap_clients[0].postOffer(Coins.BTC, Coins.XMR, 10 * COIN, 100 * XMR_COIN, 10 * COIN, SwapTypes.XMR_SWAP)
offer2_id = swap_clients[0].postOffer(Coins.PART, Coins.XMR, 10 * COIN, 0.14 * XMR_COIN, 10 * COIN, SwapTypes.XMR_SWAP) offer2_id = swap_clients[0].postOffer(Coins.PART, Coins.XMR, 10 * COIN, 0.14 * XMR_COIN, 10 * COIN, SwapTypes.XMR_SWAP)
self.wait_for_offer(swap_clients[1], offer1_id) wait_for_offer(delay_event, swap_clients[1], offer1_id)
offer1 = swap_clients[1].getOffer(offer1_id) offer1 = swap_clients[1].getOffer(offer1_id)
self.wait_for_offer(swap_clients[1], offer2_id) wait_for_offer(delay_event, swap_clients[1], offer2_id)
offer2 = swap_clients[1].getOffer(offer2_id) offer2 = swap_clients[1].getOffer(offer2_id)
bid1_id = swap_clients[1].postXmrBid(offer1_id, offer1.amount_from) bid1_id = swap_clients[1].postXmrBid(offer1_id, offer1.amount_from)
@ -706,40 +576,40 @@ class Test(unittest.TestCase):
offer3_id = swap_clients[0].postOffer(Coins.PART, Coins.XMR, 11 * COIN, 0.15 * XMR_COIN, 11 * COIN, SwapTypes.XMR_SWAP) offer3_id = swap_clients[0].postOffer(Coins.PART, Coins.XMR, 11 * COIN, 0.15 * XMR_COIN, 11 * COIN, SwapTypes.XMR_SWAP)
self.wait_for_bid(swap_clients[0], bid1_id, BidStates.BID_RECEIVED) wait_for_bid(delay_event, swap_clients[0], bid1_id, BidStates.BID_RECEIVED)
swap_clients[0].acceptXmrBid(bid1_id) swap_clients[0].acceptXmrBid(bid1_id)
self.wait_for_offer(swap_clients[1], offer3_id) wait_for_offer(delay_event, swap_clients[1], offer3_id)
offer3 = swap_clients[1].getOffer(offer3_id) offer3 = swap_clients[1].getOffer(offer3_id)
bid3_id = swap_clients[1].postXmrBid(offer3_id, offer3.amount_from) bid3_id = swap_clients[1].postXmrBid(offer3_id, offer3.amount_from)
self.wait_for_bid(swap_clients[0], bid2_id, BidStates.BID_RECEIVED) wait_for_bid(delay_event, swap_clients[0], bid2_id, BidStates.BID_RECEIVED)
swap_clients[0].acceptXmrBid(bid2_id) swap_clients[0].acceptXmrBid(bid2_id)
self.wait_for_bid(swap_clients[0], bid3_id, BidStates.BID_RECEIVED) wait_for_bid(delay_event, swap_clients[0], bid3_id, BidStates.BID_RECEIVED)
swap_clients[0].acceptXmrBid(bid3_id) swap_clients[0].acceptXmrBid(bid3_id)
self.wait_for_bid(swap_clients[0], bid1_id, BidStates.SWAP_COMPLETED, wait_for=180) wait_for_bid(delay_event, swap_clients[0], bid1_id, BidStates.SWAP_COMPLETED, wait_for=180)
self.wait_for_bid(swap_clients[1], bid1_id, BidStates.SWAP_COMPLETED, sent=True) wait_for_bid(delay_event, swap_clients[1], bid1_id, BidStates.SWAP_COMPLETED, sent=True)
self.wait_for_bid(swap_clients[0], bid2_id, BidStates.SWAP_COMPLETED, wait_for=120) wait_for_bid(delay_event, swap_clients[0], bid2_id, BidStates.SWAP_COMPLETED, wait_for=120)
self.wait_for_bid(swap_clients[1], bid2_id, BidStates.SWAP_COMPLETED, sent=True) wait_for_bid(delay_event, swap_clients[1], bid2_id, BidStates.SWAP_COMPLETED, sent=True)
self.wait_for_bid(swap_clients[0], bid3_id, BidStates.SWAP_COMPLETED, wait_for=120) wait_for_bid(delay_event, swap_clients[0], bid3_id, BidStates.SWAP_COMPLETED, wait_for=120)
self.wait_for_bid(swap_clients[1], bid3_id, BidStates.SWAP_COMPLETED, sent=True) wait_for_bid(delay_event, swap_clients[1], bid3_id, BidStates.SWAP_COMPLETED, sent=True)
self.wait_for_none_active(1800) wait_for_none_active(delay_event, 1800)
self.wait_for_none_active(1801) wait_for_none_active(delay_event, 1801)
def test_07_revoke_offer(self): def test_07_revoke_offer(self):
logging.info('---------- Test offer revocaction') logging.info('---------- Test offer revocaction')
swap_clients = self.swap_clients swap_clients = self.swap_clients
offer_id = swap_clients[0].postOffer(Coins.BTC, Coins.XMR, 10 * COIN, 100 * XMR_COIN, 10 * COIN, SwapTypes.XMR_SWAP) offer_id = swap_clients[0].postOffer(Coins.BTC, Coins.XMR, 10 * COIN, 100 * XMR_COIN, 10 * COIN, SwapTypes.XMR_SWAP)
self.wait_for_offer(swap_clients[1], offer_id) wait_for_offer(delay_event, swap_clients[1], offer_id)
swap_clients[0].revokeOffer(offer_id) swap_clients[0].revokeOffer(offer_id)
self.wait_for_no_offer(swap_clients[1], offer_id) wait_for_no_offer(delay_event, swap_clients[1], offer_id)
def test_08_withdraw(self): def test_08_withdraw(self):
logging.info('---------- Test xmr withdrawals') logging.info('---------- Test xmr withdrawals')
@ -753,24 +623,24 @@ class Test(unittest.TestCase):
logging.info('---------- Test BTC to XMR auto accept') logging.info('---------- Test BTC to XMR auto accept')
swap_clients = self.swap_clients swap_clients = self.swap_clients
offer_id = swap_clients[0].postOffer(Coins.BTC, Coins.XMR, 11 * COIN, 101 * XMR_COIN, 10 * COIN, SwapTypes.XMR_SWAP, auto_accept_bids=True) offer_id = swap_clients[0].postOffer(Coins.BTC, Coins.XMR, 11 * COIN, 101 * XMR_COIN, 10 * COIN, SwapTypes.XMR_SWAP, auto_accept_bids=True)
self.wait_for_offer(swap_clients[1], offer_id) wait_for_offer(delay_event, swap_clients[1], offer_id)
offer = swap_clients[1].listOffers(filters={'offer_id': offer_id})[0] offer = swap_clients[1].listOffers(filters={'offer_id': offer_id})[0]
bid_id = swap_clients[1].postXmrBid(offer_id, offer.amount_from) bid_id = swap_clients[1].postXmrBid(offer_id, offer.amount_from)
self.wait_for_bid(swap_clients[0], bid_id, BidStates.SWAP_COMPLETED, wait_for=180) wait_for_bid(delay_event, swap_clients[0], bid_id, BidStates.SWAP_COMPLETED, wait_for=180)
self.wait_for_bid(swap_clients[1], bid_id, BidStates.SWAP_COMPLETED, sent=True) wait_for_bid(delay_event, swap_clients[1], bid_id, BidStates.SWAP_COMPLETED, sent=True)
def test_10_locked_refundtx(self): def test_10_locked_refundtx(self):
logging.info('---------- Test Refund tx is locked') logging.info('---------- Test Refund tx is locked')
swap_clients = self.swap_clients swap_clients = self.swap_clients
offer_id = swap_clients[0].postOffer(Coins.BTC, Coins.XMR, 10 * COIN, 100 * XMR_COIN, 10 * COIN, SwapTypes.XMR_SWAP) offer_id = swap_clients[0].postOffer(Coins.BTC, Coins.XMR, 10 * COIN, 100 * XMR_COIN, 10 * COIN, SwapTypes.XMR_SWAP)
self.wait_for_offer(swap_clients[1], offer_id) wait_for_offer(delay_event, swap_clients[1], offer_id)
offers = swap_clients[1].listOffers(filters={'offer_id': offer_id}) offers = swap_clients[1].listOffers(filters={'offer_id': offer_id})
offer = offers[0] offer = offers[0]
bid_id = swap_clients[1].postXmrBid(offer_id, offer.amount_from) bid_id = swap_clients[1].postXmrBid(offer_id, offer.amount_from)
self.wait_for_bid(swap_clients[0], bid_id, BidStates.BID_RECEIVED) wait_for_bid(delay_event, swap_clients[0], bid_id, BidStates.BID_RECEIVED)
bid, xmr_swap = swap_clients[0].getXmrBid(bid_id) bid, xmr_swap = swap_clients[0].getXmrBid(bid_id)
assert(xmr_swap) assert(xmr_swap)
@ -779,7 +649,7 @@ class Test(unittest.TestCase):
swap_clients[0].acceptXmrBid(bid_id) swap_clients[0].acceptXmrBid(bid_id)
self.wait_for_bid(swap_clients[0], bid_id, BidStates.XMR_SWAP_SCRIPT_COIN_LOCKED, wait_for=180) wait_for_bid(delay_event, swap_clients[0], bid_id, BidStates.XMR_SWAP_SCRIPT_COIN_LOCKED, wait_for=180)
bid, xmr_swap = swap_clients[0].getXmrBid(bid_id) bid, xmr_swap = swap_clients[0].getXmrBid(bid_id)
assert(xmr_swap) assert(xmr_swap)

Loading…
Cancel
Save