diff --git a/.cirrus.yml b/.cirrus.yml index 155dac3..a46228f 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -7,40 +7,42 @@ lint_task: - pip install codespell script: - flake8 --version - - PYTHONWARNINGS="ignore" flake8 --ignore=E501,F841,W503 --exclude=basicswap/contrib,messages_pb2.py,.eggs - - codespell --check-filenames --disable-colors --quiet-level=7 --ignore-words=tests/lint/spelling.ignore-words.txt -S .git,.eggs,gitianpubkeys,*.pyc,*basicswap/contrib,*mnemonics.py + - PYTHONWARNINGS="ignore" flake8 --ignore=E501,F841,W503 --exclude=basicswap/contrib,messages_pb2.py,.eggs,.tox + - codespell --check-filenames --disable-colors --quiet-level=7 --ignore-words=tests/lint/spelling.ignore-words.txt -S .git,.eggs,.tox,gitianpubkeys,*.pyc,*basicswap/contrib,*mnemonics.py test_task: environment: - - PART_VERSION: 0.19.1.2 - - BTC_VERSION: 0.20.1 - - LTC_VERSION: 0.18.1 - - XMR_VERSION: 0.17.1.9 - - TEST_RELOAD_PATH: $HOME/test_basicswap1/ - - TEST_DIR: $HOME/test_basicswap2/ - - BIN_DIRS: $HOME/binaries - - PARTICL_BINDIR: ${BIN_DIRS}/particl-${PART_VERSION}/bin - - BITCOIN_BINDIR: ${BIN_DIRS}/bitcoin-${BTC_VERSION}/bin - - LITECOIN_BINDIR: ${BIN_DIRS}/litecoin-${LTC_VERSION}/bin - - MONERO_BINDIR: ${BIN_DIRS}/monero-${XMR_VERSION}/bin + - TEST_PREPARE_PATH: $HOME/test_basicswap-prepare + - TEST_RELOAD_PATH: $HOME/test_basicswap1 + - TEST_DIR: $HOME/test_basicswap2 + - BIN_DIR: /tmp/cached_bin + - PARTICL_BINDIR: ${BIN_DIR}/particl + - BITCOIN_BINDIR: ${BIN_DIR}/bitcoin + - LITECOIN_BINDIR: ${BIN_DIR}/litecoin + - XMR_BINDIR: ${BIN_DIR}/monero setup_script: - apt-get update - apt-get install -y wget python3-pip gnupg unzip protobuf-compiler automake libtool pkg-config - - if [ ! -d "$BIN_DIRS" ]; then mkdir -p "$BIN_DIRS" ; fi - - if [ ! -d "$PARTICL_BINDIR" ]; then cd "$BIN_DIRS" && wget https://github.com/tecnovert/particl-core/releases/download/v${PART_VERSION}/particl-${PART_VERSION}-x86_64-linux-gnu.tar.gz && tar xvf particl-${PART_VERSION}-x86_64-linux-gnu.tar.gz; fi - - if [ ! -d "$BITCOIN_BINDIR" ]; then cd "$BIN_DIRS" && wget https://bitcoincore.org/bin/bitcoin-core-${BTC_VERSION}/bitcoin-${BTC_VERSION}-x86_64-linux-gnu.tar.gz && tar xvf bitcoin-${BTC_VERSION}-x86_64-linux-gnu.tar.gz; fi - - if [ ! -d "$LITECOIN_BINDIR" ]; then cd "$BIN_DIRS" && wget https://download.litecoin.org/litecoin-${LTC_VERSION}/linux/litecoin-${LTC_VERSION}-x86_64-linux-gnu.tar.gz && tar xvf litecoin-${LTC_VERSION}-x86_64-linux-gnu.tar.gz ; fi + - pip install tox + - python3 setup.py install - wget -O coincurve-anonswap.zip https://github.com/tecnovert/coincurve/archive/anonswap.zip - unzip coincurve-anonswap.zip - cd coincurve-anonswap - python3 setup.py install --force + bins_cache: + folder: /tmp/cached_bin + reupload_on_changes: false + fingerprint_script: + - basicswap-prepare -v + populate_script: + - basicswap-prepare --bindir=/tmp/cached_bin --preparebinonly --withcoins=particl,bitcoin,litecoin,monero script: - cd "${CIRRUS_WORKING_DIR}" - export DATADIRS="${TEST_DIR}" - - mkdir -p ${DATADIRS}/bin/{particl,bitcoin,monero} - - cp "${BIN_DIRS}/bitcoin-${BTC_VERSION}-x86_64-linux-gnu.tar.gz" "${DATADIRS}/bin/bitcoin" - - cp "${BIN_DIRS}/particl-${PART_VERSION}-x86_64-linux-gnu.tar.gz" "${DATADIRS}/bin/particl" - - mkdir -p ${TEST_RELOAD_PATH}/bin/{particl,bitcoin,monero} - - cp "${BIN_DIRS}/particl-${PART_VERSION}-x86_64-linux-gnu.tar.gz" "${TEST_RELOAD_PATH}/bin/particl" - - cp "${BIN_DIRS}/bitcoin-${BTC_VERSION}-x86_64-linux-gnu.tar.gz" "${TEST_RELOAD_PATH}/bin/bitcoin" - - python setup.py test + - mkdir -p "${DATADIRS}/bin" + - cp -r ${BIN_DIR} "${DATADIRS}/bin" + - mkdir -p "${TEST_RELOAD_PATH}/bin" + - cp -r ${BIN_DIR} "${TEST_RELOAD_PATH}/bin" + - mkdir -p "${TEST_PREPARE_PATH}/bin" + - cp -r ${BIN_DIR} "${TEST_PREPARE_PATH}/bin" + - tox diff --git a/.gitignore b/.gitignore index 74746e8..987e284 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,5 @@ __pycache__ /*.egg-info /*.egg /*.eggs +.tox +.eggs diff --git a/.travis.yml b/.travis.yml index c431ca1..bada43a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,40 +7,37 @@ stages: - test env: global: - - PART_VERSION=0.19.1.2 - - BTC_VERSION=0.20.1 - - LTC_VERSION=0.18.1 - - XMR_VERSION=0.17.1.9 - - TEST_DIR=~/test_basicswap2/ - - TEST_RELOAD_PATH=~/test_basicswap1/ - - BIN_DIRS=~/binaries - - PARTICL_BINDIR=${BIN_DIRS}/particl-${PART_VERSION}/bin/ - - BITCOIN_BINDIR=${BIN_DIRS}/bitcoin-${BTC_VERSION}/bin/ - - LITECOIN_BINDIR=${BIN_DIRS}/litecoin-${LTC_VERSION}/bin/ - - MONERO_BINDIR=${BIN_DIRS}/monero-${XMR_VERSION}/bin/ + - TEST_PREPARE_PATH: ~/test_basicswap-prepare + - TEST_DIR=~/test_basicswap2 + - TEST_RELOAD_PATH=~/test_basicswap1 + - BIN_DIRS=~/cached_bin + - PARTICL_BINDIR=${BIN_DIRS}/particl + - BITCOIN_BINDIR=${BIN_DIRS}/bitcoin + - LITECOIN_BINDIR=${BIN_DIRS}/litecoin + - XMR_BINDIR=${BIN_DIRS}/monero cache: directories: - "$BIN_DIRS" before_install: - sudo apt-get install -y wget python3-pip gnupg unzip protobuf-compiler automake libtool pkg-config +install: + - travis_retry pip install tox before_script: - - if [ ! -d "$BIN_DIRS" ]; then mkdir -p "$BIN_DIRS" ; fi - - if [ ! -d "$PARTICL_BINDIR" ]; then cd "$BIN_DIRS" && wget https://github.com/tecnovert/particl-core/releases/download/v${PART_VERSION}/particl-${PART_VERSION}-x86_64-linux-gnu.tar.gz && tar xvf particl-${PART_VERSION}-x86_64-linux-gnu.tar.gz ; fi - - if [ ! -d "$BITCOIN_BINDIR" ]; then cd "$BIN_DIRS" && wget https://bitcoincore.org/bin/bitcoin-core-${BTC_VERSION}/bitcoin-${BTC_VERSION}-x86_64-linux-gnu.tar.gz && tar xvf bitcoin-${BTC_VERSION}-x86_64-linux-gnu.tar.gz ; fi - - if [ ! -d "$LITECOIN_BINDIR" ]; then cd "$BIN_DIRS" && wget https://download.litecoin.org/litecoin-${LTC_VERSION}/linux/litecoin-${LTC_VERSION}-x86_64-linux-gnu.tar.gz && tar xvf litecoin-${LTC_VERSION}-x86_64-linux-gnu.tar.gz ; fi - wget -O coincurve-anonswap.zip https://github.com/tecnovert/coincurve/archive/anonswap.zip - unzip coincurve-anonswap.zip - cd coincurve-anonswap - python3 setup.py install --force script: - cd $TRAVIS_BUILD_DIR + - basicswap-prepare --bindir=${BIN_DIRS} --preparebinonly --withcoins=particl,bitcoin,litecoin,monero - export DATADIRS="${TEST_DIR}" - - mkdir -p ${DATADIRS}/bin/{particl,bitcoin,monero} - - cp "${BIN_DIRS}/bitcoin-${BTC_VERSION}-x86_64-linux-gnu.tar.gz" "${DATADIRS}/bin/bitcoin" - - mkdir -p ${TEST_RELOAD_PATH}/bin/{particl,bitcoin,monero} - - cp "${BIN_DIRS}/particl-${PART_VERSION}-x86_64-linux-gnu.tar.gz" "${TEST_RELOAD_PATH}/bin/particl" - - cp "${BIN_DIRS}/bitcoin-${BTC_VERSION}-x86_64-linux-gnu.tar.gz" "${TEST_RELOAD_PATH}/bin/bitcoin" - - python setup.py test + - mkdir -p "${DATADIRS}/bin" + - cp -r ${BIN_DIR} "${DATADIRS}/bin" + - mkdir -p "${TEST_RELOAD_PATH}/bin" + - cp -r ${BIN_DIR} "${TEST_RELOAD_PATH}/bin" + - mkdir -p "${TEST_PREPARE_PATH}/bin" + - cp -r ${BIN_DIR} "${TEST_PREPARE_PATH}/bin" + - tox after_success: - echo "End test" jobs: @@ -53,8 +50,8 @@ jobs: - travis_retry pip install codespell==1.15.0 before_script: script: - - PYTHONWARNINGS="ignore" flake8 --ignore=E501,F841,W503 --exclude=basicswap/contrib,messages_pb2.py,.eggs - - codespell --check-filenames --disable-colors --quiet-level=7 --ignore-words=tests/lint/spelling.ignore-words.txt -S .git,.eggs,gitianpubkeys,*.pyc,*basicswap/contrib,*mnemonics.py + - PYTHONWARNINGS="ignore" flake8 --ignore=E501,F841,W503 --exclude=basicswap/contrib,messages_pb2.py,.eggs,.tox + - codespell --check-filenames --disable-colors --quiet-level=7 --ignore-words=tests/lint/spelling.ignore-words.txt -S .git,.eggs,.tox,gitianpubkeys,*.pyc,*basicswap/contrib,*mnemonics.py after_success: - echo "End lint" - stage: test diff --git a/basicswap/http_server.py b/basicswap/http_server.py index deb4d40..7e80de7 100644 --- a/basicswap/http_server.py +++ b/basicswap/http_server.py @@ -383,32 +383,35 @@ class HttpHandler(BaseHTTPRequestHandler): page_data['autoaccept'] = True if b'autoaccept' in form_data else False parsed_data['autoaccept'] = page_data['autoaccept'] - if len(errors) == 0 and page_data['swap_style'] == 'xmr': - if b'fee_rate_from' in form_data: - page_data['from_fee_override'] = form_data[b'fee_rate_from'][0].decode('utf-8') - parsed_data['from_fee_override'] = page_data['from_fee_override'] - else: - from_fee_override, page_data['from_fee_src'] = swap_client.getFeeRateForCoin(parsed_data['coin_from'], page_data['fee_from_conf']) - if page_data['fee_from_extra'] > 0: - from_fee_override += from_fee_override * (float(page_data['fee_from_extra']) / 100.0) - page_data['from_fee_override'] = ci_from.format_amount(ci_from.make_int(from_fee_override, r=1)) - parsed_data['from_fee_override'] = page_data['from_fee_override'] - - lock_spend_tx_vsize = ci_from.xmr_swap_alock_spend_tx_vsize() - lock_spend_tx_fee = ci_from.make_int(ci_from.make_int(from_fee_override, r=1) * lock_spend_tx_vsize / 1000, r=1) - page_data['amt_from_lock_spend_tx_fee'] = ci_from.format_amount(lock_spend_tx_fee // ci_from.COIN()) - page_data['tla_from'] = ci_from.ticker() - - if coin_to == Coins.XMR: - if b'fee_rate_to' in form_data: - page_data['to_fee_override'] = form_data[b'fee_rate_to'][0].decode('utf-8') - parsed_data['to_fee_override'] = page_data['to_fee_override'] + try: + if len(errors) == 0 and page_data['swap_style'] == 'xmr': + if b'fee_rate_from' in form_data: + page_data['from_fee_override'] = form_data[b'fee_rate_from'][0].decode('utf-8') + parsed_data['from_fee_override'] = page_data['from_fee_override'] else: - to_fee_override, page_data['to_fee_src'] = swap_client.getFeeRateForCoin(parsed_data['coin_to'], page_data['fee_to_conf']) - if page_data['fee_to_extra'] > 0: - to_fee_override += to_fee_override * (float(page_data['fee_to_extra']) / 100.0) - page_data['to_fee_override'] = ci_to.format_amount(ci_to.make_int(to_fee_override, r=1)) - parsed_data['to_fee_override'] = page_data['to_fee_override'] + from_fee_override, page_data['from_fee_src'] = swap_client.getFeeRateForCoin(parsed_data['coin_from'], page_data['fee_from_conf']) + if page_data['fee_from_extra'] > 0: + from_fee_override += from_fee_override * (float(page_data['fee_from_extra']) / 100.0) + page_data['from_fee_override'] = ci_from.format_amount(ci_from.make_int(from_fee_override, r=1)) + parsed_data['from_fee_override'] = page_data['from_fee_override'] + + lock_spend_tx_vsize = ci_from.xmr_swap_alock_spend_tx_vsize() + lock_spend_tx_fee = ci_from.make_int(ci_from.make_int(from_fee_override, r=1) * lock_spend_tx_vsize / 1000, r=1) + page_data['amt_from_lock_spend_tx_fee'] = ci_from.format_amount(lock_spend_tx_fee // ci_from.COIN()) + page_data['tla_from'] = ci_from.ticker() + + if coin_to == Coins.XMR: + if b'fee_rate_to' in form_data: + page_data['to_fee_override'] = form_data[b'fee_rate_to'][0].decode('utf-8') + parsed_data['to_fee_override'] = page_data['to_fee_override'] + else: + to_fee_override, page_data['to_fee_src'] = swap_client.getFeeRateForCoin(parsed_data['coin_to'], page_data['fee_to_conf']) + if page_data['fee_to_extra'] > 0: + to_fee_override += to_fee_override * (float(page_data['fee_to_extra']) / 100.0) + page_data['to_fee_override'] = ci_to.format_amount(ci_to.make_int(to_fee_override, r=1)) + parsed_data['to_fee_override'] = page_data['to_fee_override'] + except Exception as e: + print('Error setting fee', str(e)) # Expected if missing fields return parsed_data, errors @@ -456,7 +459,9 @@ class HttpHandler(BaseHTTPRequestHandler): def postNewOffer(self, form_data): page_data = {} - parsed_data = self.parseOfferFormData(form_data, page_data) + parsed_data, errors = self.parseOfferFormData(form_data, page_data) + if len(errors) > 0: + raise ValueError('Parse errors: ' + ' '.join(errors)) return self.postNewOfferFromParsed(parsed_data) def page_newoffer(self, url_split, post_string): diff --git a/basicswap/interface_btc.py b/basicswap/interface_btc.py index 640df0a..033868e 100644 --- a/basicswap/interface_btc.py +++ b/basicswap/interface_btc.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- -# Copyright (c) 2020 tecnovert +# Copyright (c) 2020-2021 tecnovert # Distributed under the MIT software license, see the accompanying # file LICENSE or http://www.opensource.org/licenses/mit-license.php. @@ -117,7 +117,8 @@ class BTCInterface(CoinInterface): def __init__(self, coin_settings, network): super().__init__() - self.rpc_callback = make_rpc_func(coin_settings['rpcport'], coin_settings['rpcauth'], host=coin_settings['rpchost']) + rpc_host = coin_settings.get('rpchost', 'localhost') + self.rpc_callback = make_rpc_func(coin_settings['rpcport'], coin_settings['rpcauth'], host=rpc_host) self.txoType = CTxOut self._network = network self.blocks_confirmed = coin_settings['blocks_confirmed'] diff --git a/basicswap/interface_part.py b/basicswap/interface_part.py index cce82c1..9f375b3 100644 --- a/basicswap/interface_part.py +++ b/basicswap/interface_part.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- -# Copyright (c) 2020 tecnovert +# Copyright (c) 2020-2021 tecnovert # Distributed under the MIT software license, see the accompanying # file LICENSE or http://www.opensource.org/licenses/mit-license.php. @@ -36,7 +36,8 @@ class PARTInterface(BTCInterface): return 213 def __init__(self, coin_settings, network): - self.rpc_callback = make_rpc_func(coin_settings['rpcport'], coin_settings['rpcauth'], host=coin_settings['rpchost']) + rpc_host = coin_settings.get('rpchost', 'localhost') + self.rpc_callback = make_rpc_func(coin_settings['rpcport'], coin_settings['rpcauth'], host=rpc_host) self.txoType = CTxOutPart self._network = network self.blocks_confirmed = coin_settings['blocks_confirmed'] diff --git a/basicswap/interface_xmr.py b/basicswap/interface_xmr.py index fbf6974..be1e4fb 100644 --- a/basicswap/interface_xmr.py +++ b/basicswap/interface_xmr.py @@ -123,6 +123,7 @@ class XMRInterface(CoinInterface): def getWalletInfo(self): self.rpc_wallet_cb('open_wallet', {'filename': self._wallet_filename}) rv = {} + self.rpc_wallet_cb('refresh') balance_info = self.rpc_wallet_cb('get_balance') rv['balance'] = format_amount(balance_info['unlocked_balance'], XMRInterface.exp()) rv['unconfirmed_balance'] = format_amount(balance_info['balance'] - balance_info['unlocked_balance'], XMRInterface.exp()) diff --git a/bin/basicswap_prepare.py b/bin/basicswap_prepare.py index eb4b62c..ea2c4be 100755 --- a/bin/basicswap_prepare.py +++ b/bin/basicswap_prepare.py @@ -1,7 +1,7 @@ #!/usr/bin/env python3 # -*- coding: utf-8 -*- -# Copyright (c) 2019-2020 tecnovert +# Copyright (c) 2019-2021 tecnovert # Distributed under the MIT software license, see the accompanying # file LICENSE or http://www.opensource.org/licenses/mit-license.php. @@ -31,11 +31,14 @@ from bin.basicswap_run import startDaemon, startXmrWalletDaemon if platform.system() == 'Darwin': - BIN_ARCH = 'osx64.tar.gz' + BIN_ARCH = 'osx64' + FILE_EXT = 'tar.gz' elif platform.system() == 'Windows': - BIN_ARCH = 'win64.zip' + BIN_ARCH = 'win64' + FILE_EXT = 'zip' else: - BIN_ARCH = 'x86_64-linux-gnu.tar.gz' + BIN_ARCH = 'x86_64-linux-gnu' + FILE_EXT = 'tar.gz' known_coins = { 'particl': '0.19.1.2', @@ -67,6 +70,8 @@ LTC_RPC_HOST = os.getenv('LTC_RPC_HOST', 'localhost') BTC_RPC_HOST = os.getenv('BTC_RPC_HOST', 'localhost') NMC_RPC_HOST = os.getenv('NMC_RPC_HOST', 'localhost') +extract_core_overwrite = True + def make_reporthook(): read = 0 # Number of bytes read so far @@ -88,6 +93,7 @@ def make_reporthook(): def downloadFile(url, path): logger.info('Downloading file %s', url) + logger.info('To %s', path) opener = urllib.request.build_opener() opener.addheaders = [('User-agent', 'Mozilla/5.0')] urllib.request.install_opener(opener) @@ -97,19 +103,31 @@ def downloadFile(url, path): def extractCore(coin, version, settings, bin_dir, release_path): logger.info('extractCore %s v%s', coin, version) - bins = [coin + 'd', coin + '-cli', coin + '-tx'] - if coin == 'monero': + bins = ['monerod', 'monero-wallet-rpc'] + num_exist = 0 + for b in bins: + out_path = os.path.join(bin_dir, b) + if os.path.exists(out_path): + num_exist += 1 + if not extract_core_overwrite and num_exist == len(bins): + logger.info('Skipping extract, files exist.') + return + with tarfile.open(release_path) as ft: for member in ft.getmembers(): if member.isdir(): continue - out_path = os.path.join(bin_dir, os.path.basename(member.name)) - fi = ft.extractfile(member) - with open(out_path, 'wb') as fout: - fout.write(fi.read()) - fi.close() - os.chmod(out_path, stat.S_IRWXU | stat.S_IXGRP | stat.S_IXOTH) + bin_name = os.path.basename(member.name) + if bin_name not in bins: + continue + out_path = os.path.join(bin_dir, bin_name) + if (not os.path.exists(out_path)) or extract_core_overwrite: + fi = ft.extractfile(member) + with open(out_path, 'wb') as fout: + fout.write(fi.read()) + fi.close() + os.chmod(out_path, stat.S_IRWXU | stat.S_IXGRP | stat.S_IXOTH) return bins = [coin + 'd', coin + '-cli', coin + '-tx'] @@ -121,18 +139,20 @@ def extractCore(coin, version, settings, bin_dir, release_path): for b in bins: b += '.exe' out_path = os.path.join(bin_dir, b) - with open(out_path, 'wb') as fout: - fout.write(fz.read('{}-{}/bin/{}'.format(coin, version, b))) - os.chmod(out_path, stat.S_IRWXU | stat.S_IXGRP | stat.S_IXOTH) + if (not os.path.exists(out_path)) or extract_core_overwrite: + with open(out_path, 'wb') as fout: + fout.write(fz.read('{}-{}/bin/{}'.format(coin, version, b))) + os.chmod(out_path, stat.S_IRWXU | stat.S_IXGRP | stat.S_IXOTH) else: with tarfile.open(release_path) as ft: for b in bins: out_path = os.path.join(bin_dir, b) - fi = ft.extractfile('{}-{}/bin/{}'.format(coin, version, b)) - with open(out_path, 'wb') as fout: - fout.write(fi.read()) - fi.close() - os.chmod(out_path, stat.S_IRWXU | stat.S_IXGRP | stat.S_IXOTH) + if not os.path.exists(out_path) or extract_core_overwrite: + fi = ft.extractfile('{}-{}/bin/{}'.format(coin, version, b)) + with open(out_path, 'wb') as fout: + fout.write(fi.read()) + fi.close() + os.chmod(out_path, stat.S_IRWXU | stat.S_IXGRP | stat.S_IXOTH) def prepareCore(coin, version, settings, data_dir): @@ -152,11 +172,12 @@ def prepareCore(coin, version, settings, data_dir): os_dir_name = 'linux' os_name = 'linux' - release_filename = '{}-{}-{}'.format(coin, version, BIN_ARCH) if coin == 'monero': + use_file_ext = 'tar.bz2' if FILE_EXT == 'tar.gz' else FILE_EXT + release_filename = '{}-{}-{}.{}'.format(coin, version, BIN_ARCH, use_file_ext) if os_name == 'osx': os_name = 'mac' - release_url = 'https://downloads.getmonero.org/cli/monero-{}-x64-v{}.tar.bz2'.format(os_name, version) + release_url = 'https://downloads.getmonero.org/cli/monero-{}-x64-v{}.{}'.format(os_name, version, use_file_ext) release_path = os.path.join(bin_dir, release_filename) if not os.path.exists(release_path): downloadFile(release_url, release_path) @@ -168,7 +189,7 @@ def prepareCore(coin, version, settings, data_dir): if not os.path.exists(assert_path): downloadFile(assert_url, assert_path) else: - release_filename = '{}-{}-{}'.format(coin, version, BIN_ARCH) + release_filename = '{}-{}-{}.{}'.format(coin, version, BIN_ARCH, FILE_EXT) if coin == 'particl': signing_key_name = 'tecnovert' release_url = 'https://github.com/tecnovert/particl-core/releases/download/v{}/{}'.format(version, release_filename) @@ -284,16 +305,17 @@ def prepareDataDir(coin, settings, chain, particl_mnemonic): fp.write('regtest=1\n') fp.write('keep-fakechain=1\n') fp.write('fixed-difficulty=1\n') - elif chain == 'testnet': + else: + fp.write('bootstrap-daemon-address=auto\n') + fp.write('restricted-rpc=1\n') + if chain == 'testnet': fp.write('testnet=1\n') fp.write('data-dir={}\n'.format(data_dir)) fp.write('rpc-bind-port={}\n'.format(core_settings['rpcport'])) fp.write('rpc-bind-ip=127.0.0.1\n') fp.write('zmq-rpc-bind-port={}\n'.format(core_settings['zmqport'])) fp.write('zmq-rpc-bind-ip=127.0.0.1\n') - fp.write('prune-blockchain=1') - fp.write('restricted-rpc=1') - fp.write('bootstrap-daemon-address=auto') + fp.write('prune-blockchain=1\n') wallet_conf_path = os.path.join(data_dir, coin + '_wallet.conf') if os.path.exists(wallet_conf_path): @@ -346,7 +368,11 @@ def prepareDataDir(coin, settings, chain, particl_mnemonic): def printVersion(): from basicswap import __version__ - logger.info('Basicswap version:', __version__) + logger.info('Basicswap version: %s', __version__) + + logger.info('Core versions:') + for coin, version in known_coins.items(): + logger.info('\t%s: %s', coin, version) def printHelp(): @@ -369,6 +395,7 @@ def printHelp(): logger.info('--portoffset=n Raise all ports by n.') logger.info('--htmlhost= Interface to host on, default:localhost.') logger.info('--xmrrestoreheight=n Block height to restore Monero wallet from, default:{}.'.format(DEFAULT_XMR_RESTORE_HEIGHT)) + logger.info('--noextractover Prevent extracting cores if files exist. Speeds up tests') logger.info('\n' + 'Known coins: %s', ', '.join(known_coins.keys())) @@ -393,6 +420,7 @@ def exitWithError(error_msg): def main(): + global extract_core_overwrite data_dir = None bin_dir = None port_offset = None @@ -437,6 +465,9 @@ def main(): if name == 'nocores': no_cores = True continue + if name == 'noextractover': + extract_core_overwrite = False + continue if len(s) == 2: if name == 'datadir': data_dir = os.path.expanduser(s[1].strip('"')) @@ -489,7 +520,8 @@ def main(): if bin_dir is None: bin_dir = os.path.join(data_dir, 'bin') - logger.info('Using datadir: %s', data_dir) + logger.info('datadir: %s', data_dir) + logger.info('bindir: %s', bin_dir) logger.info('Chain: %s', chain) if port_offset is None: diff --git a/bin/basicswap_run.py b/bin/basicswap_run.py index ff95136..6d346c6 100755 --- a/bin/basicswap_run.py +++ b/bin/basicswap_run.py @@ -184,7 +184,7 @@ def runClient(fp, data_dir, chain): def printVersion(): - logger.info('Basicswap version:', __version__) + logger.info('Basicswap version: %s', __version__) def printHelp(): diff --git a/doc/notes.md b/doc/notes.md index ff0ab1c..d226a07 100644 --- a/doc/notes.md +++ b/doc/notes.md @@ -2,7 +2,7 @@ ## Run One Test ``` -python setup.py test -s tests.basicswap.test_xmr.Test.test_02_leader_recover_a_lock_tx +pytest -v -s tests/basicswap/test_xmr.py::Test::test_02_leader_recover_a_lock_tx ``` ## TODO diff --git a/setup.py b/setup.py index 9bf5417..4912009 100644 --- a/setup.py +++ b/setup.py @@ -12,7 +12,7 @@ setuptools.setup( version=__version__, author="tecnovert", author_email="tecnovert@tecnovert.net", - description="Simple atomic swap demo", + description="Simple atomic swap system", long_description=open("README.md").read(), long_description_content_type="text/markdown", url="https://github.com/tecnovert/basicswap", @@ -23,6 +23,13 @@ setuptools.setup( "License :: OSI Approved :: MIT License", "Operating System :: Linux", ], + keywords=[ + "crypto", + "cryptocurrency", + "particl", + "bitcoin", + "monero", + ], install_requires=[ "wheel", "pyzmq", @@ -38,6 +45,5 @@ setuptools.setup( "basicswap-run=bin.basicswap_run:main", "basicswap-prepare=bin.basicswap_prepare:main", ] - }, - test_suite="tests.basicswap.test_suite" + } ) diff --git a/tests/basicswap/__init__.py b/tests/basicswap/__init__.py index 128b685..e69de29 100644 --- a/tests/basicswap/__init__.py +++ b/tests/basicswap/__init__.py @@ -1,17 +0,0 @@ -import unittest - -import tests.basicswap.test_other as test_other -import tests.basicswap.test_prepare as test_prepare -import tests.basicswap.test_run as test_run -import tests.basicswap.test_reload as test_reload - - -def test_suite(): - loader = unittest.TestLoader() - suite = loader.loadTestsFromModule(test_other) - suite.addTests(loader.loadTestsFromModule(test_prepare)) - suite.addTests(loader.loadTestsFromModule(test_run)) - suite.addTests(loader.loadTestsFromModule(test_reload)) - # TODO: Add to ci scripts suite.addTests(loader.loadTestsFromModule(test_xmr)) - - return suite diff --git a/tests/basicswap/test_network.py b/tests/basicswap/extended/test_network.py similarity index 100% rename from tests/basicswap/test_network.py rename to tests/basicswap/extended/test_network.py diff --git a/tests/basicswap/test_nmc.py b/tests/basicswap/extended/test_nmc.py similarity index 99% rename from tests/basicswap/test_nmc.py rename to tests/basicswap/extended/test_nmc.py index e5c3394..f4a5b8f 100644 --- a/tests/basicswap/test_nmc.py +++ b/tests/basicswap/extended/test_nmc.py @@ -1,23 +1,23 @@ #!/usr/bin/env python3 # -*- coding: utf-8 -*- -# Copyright (c) 2019-2020 tecnovert +# Copyright (c) 2019-2021 tecnovert # Distributed under the MIT software license, see the accompanying # file LICENSE or http://www.opensource.org/licenses/mit-license.php. """ -basicswap]$ python tests/test_nmc.py +basicswap]$ python tests/basicswap/extended/test_nmc.py """ import os import sys -import unittest import json -import logging -import shutil import time +import shutil import signal +import logging +import unittest import threading from urllib.request import urlopen diff --git a/tests/basicswap/test_wallet_init.py b/tests/basicswap/extended/test_wallet_init.py similarity index 84% rename from tests/basicswap/test_wallet_init.py rename to tests/basicswap/extended/test_wallet_init.py index c978837..1414c2a 100644 --- a/tests/basicswap/test_wallet_init.py +++ b/tests/basicswap/extended/test_wallet_init.py @@ -1,7 +1,7 @@ #!/usr/bin/env python3 # -*- coding: utf-8 -*- -# Copyright (c) 2020 tecnovert +# Copyright (c) 2020-2021 tecnovert # Distributed under the MIT software license, see the accompanying # file LICENSE or http://www.opensource.org/licenses/mit-license.php. @@ -9,10 +9,10 @@ export TEST_PATH=/tmp/test_basicswap_wallet_init mkdir -p ${TEST_PATH}/bin/{particl,monero,bitcoin} cp ~/tmp/particl-0.19.1.2-x86_64-linux-gnu.tar.gz ${TEST_PATH}/bin/particl -cp ~/tmp/monero-0.17.1.9-x86_64-linux-gnu.tar.gz ${TEST_PATH}/bin/monero +cp ~/tmp/monero-linux-x64-v0.17.1.9.tar.bz2 ${TEST_PATH}/bin/monero/monero-0.17.1.9-x86_64-linux-gnu.tar.bz2 cp ~/tmp/bitcoin-0.20.1-x86_64-linux-gnu.tar.gz ${TEST_PATH}/bin/bitcoin export PYTHONPATH=$(pwd) -python tests/basicswap/test_wallet_init.py +python tests/basicswap/extended/test_wallet_init.py """ @@ -61,33 +61,6 @@ def waitForServer(port): traceback.print_exc() -def waitForNumOffers(port, offers): - for i in range(20): - summary = json.loads(urlopen('http://localhost:{}/json'.format(port)).read()) - if summary['num_network_offers'] >= offers: - return - time.sleep(1) - raise ValueError('waitForNumOffers failed') - - -def waitForNumBids(port, bids): - for i in range(20): - summary = json.loads(urlopen('http://localhost:{}/json'.format(port)).read()) - if summary['num_recv_bids'] >= bids: - return - time.sleep(1) - raise ValueError('waitForNumBids failed') - - -def waitForNumSwapping(port, bids): - for i in range(20): - summary = json.loads(urlopen('http://localhost:{}/json'.format(port)).read()) - if summary['num_swapping'] >= bids: - return - time.sleep(1) - raise ValueError('waitForNumSwapping failed') - - class Test(unittest.TestCase): @classmethod def setUpClass(cls): @@ -106,7 +79,10 @@ class Test(unittest.TestCase): '-bindir="{}"'.format(os.path.join(test_path, 'bin')), '-portoffset={}'.format(i), '-particl_mnemonic="{}"'.format(mnemonics[0]), - '-regtest', '-withcoin=monero,bitcoin'] + '-regtest', + '-withcoin=monero,bitcoin', + '-noextractover', + '-xmrrestoreheight=0'] with patch.object(sys, 'argv', testargs): prepareSystem.main() diff --git a/tests/basicswap/test_reload.py b/tests/basicswap/test_reload.py index 520158e..4e391b1 100644 --- a/tests/basicswap/test_reload.py +++ b/tests/basicswap/test_reload.py @@ -1,7 +1,7 @@ #!/usr/bin/env python3 # -*- coding: utf-8 -*- -# Copyright (c) 2019 tecnovert +# Copyright (c) 2019-2021 tecnovert # Distributed under the MIT software license, see the accompanying # file LICENSE or http://www.opensource.org/licenses/mit-license.php. @@ -13,7 +13,6 @@ cp ~/tmp/bitcoin-0.20.1-x86_64-linux-gnu.tar.gz ${TEST_RELOAD_PATH}/bin/bitcoin export PYTHONPATH=$(pwd) python tests/basicswap/test_reload.py - """ import os @@ -61,9 +60,10 @@ def waitForServer(port): try: time.sleep(1) summary = json.loads(urlopen('http://localhost:{}/json'.format(port)).read()) - break + return except Exception: traceback.print_exc() + raise ValueError('waitForServer failed') def waitForNumOffers(port, offers): diff --git a/tests/basicswap/test_reload_xmr.py b/tests/basicswap/test_reload_xmr.py index d0e9aee..bd3329e 100644 --- a/tests/basicswap/test_reload_xmr.py +++ b/tests/basicswap/test_reload_xmr.py @@ -1,7 +1,7 @@ #!/usr/bin/env python3 # -*- coding: utf-8 -*- -# Copyright (c) 2020 tecnovert +# Copyright (c) 2020-2021 tecnovert # Distributed under the MIT software license, see the accompanying # file LICENSE or http://www.opensource.org/licenses/mit-license.php. @@ -9,7 +9,7 @@ export TEST_RELOAD_PATH=/tmp/test_basicswap mkdir -p ${TEST_RELOAD_PATH}/bin/{particl,monero} cp ~/tmp/particl-0.19.1.2-x86_64-linux-gnu.tar.gz ${TEST_RELOAD_PATH}/bin/particl -cp ~/tmp/monero-0.17.1.9-x86_64-linux-gnu.tar.gz ${TEST_RELOAD_PATH}/bin/monero +cp ~/tmp/monero-linux-x64-v0.17.1.9.tar.bz2 ${TEST_RELOAD_PATH}/bin/monero/monero-0.17.1.9-x86_64-linux-gnu.tar.bz2 export PYTHONPATH=$(pwd) python tests/basicswap/test_reload_xmr.py @@ -19,8 +19,8 @@ python tests/basicswap/test_reload_xmr.py import os import sys import json -import time import shutil +import signal import logging import unittest import traceback @@ -46,7 +46,7 @@ XMR_BASE_P2P_PORT = 17792 XMR_BASE_RPC_PORT = 29798 XMR_BASE_WALLET_RPC_PORT = 29998 -stop_test = False +delay_event = threading.Event() logger = logging.getLogger() logger.level = logging.DEBUG @@ -54,47 +54,64 @@ if not len(logger.handlers): logger.addHandler(logging.StreamHandler(sys.stdout)) -def waitForServer(port): - for i in range(20): +def waitForServer(port, wait_for=20): + for i in range(wait_for): + if delay_event.is_set(): + raise ValueError('Test stopped.') try: - time.sleep(1) + delay_event.wait(1) summary = json.loads(urlopen('http://localhost:{}/json'.format(port)).read()) - break + return except Exception: traceback.print_exc() + raise ValueError('waitForServer failed') -def waitForNumOffers(port, offers): - for i in range(20): +def waitForNumOffers(port, offers, wait_for=20): + for i in range(wait_for): + if delay_event.is_set(): + raise ValueError('Test stopped.') summary = json.loads(urlopen('http://localhost:{}/json'.format(port)).read()) if summary['num_network_offers'] >= offers: return - time.sleep(1) + delay_event.wait(1) raise ValueError('waitForNumOffers failed') -def waitForNumBids(port, bids): - for i in range(20): +def waitForNumBids(port, bids, wait_for=20): + for i in range(wait_for): + if delay_event.is_set(): + raise ValueError('Test stopped.') summary = json.loads(urlopen('http://localhost:{}/json'.format(port)).read()) if summary['num_recv_bids'] >= bids: return - time.sleep(1) + delay_event.wait(1) raise ValueError('waitForNumBids failed') -def waitForNumSwapping(port, bids): - for i in range(20): +def waitForNumSwapping(port, bids, wait_for=60): + for i in range(wait_for): + if delay_event.is_set(): + raise ValueError('Test stopped.') summary = json.loads(urlopen('http://localhost:{}/json'.format(port)).read()) if summary['num_swapping'] >= bids: return - time.sleep(1) + delay_event.wait(1) raise ValueError('waitForNumSwapping failed') def updateThread(xmr_addr): - while not stop_test: - callrpc_xmr_na(XMR_BASE_RPC_PORT + 1, 'generateblocks', {'wallet_address': xmr_addr, 'amount_of_blocks': 1}) - time.sleep(5) + while not delay_event.is_set(): + try: + callrpc_xmr_na(XMR_BASE_RPC_PORT + 1, 'generateblocks', {'wallet_address': xmr_addr, 'amount_of_blocks': 1}) + except Exception as e: + print('updateThread error', str(e)) + delay_event.wait(2) + + +def signal_handler(sig, frame): + logging.info('signal {} detected.'.format(sig)) + delay_event.set() class Test(unittest.TestCase): @@ -102,6 +119,9 @@ class Test(unittest.TestCase): def setUpClass(cls): super(Test, cls).setUpClass() + cls.update_thread = None + cls.processes = [] + for i in range(3): client_path = os.path.join(test_path, 'client{}'.format(i)) config_path = os.path.join(client_path, cfg.CONFIG_FILENAME) @@ -115,7 +135,10 @@ class Test(unittest.TestCase): '-bindir="{}"'.format(os.path.join(test_path, 'bin')), '-portoffset={}'.format(i), '-particl_mnemonic="{}"'.format(mnemonics[i]), - '-regtest', '-withcoin=monero'] + '-regtest', + '-withcoin=monero', + '-noextractover', + '-xmrrestoreheight=0'] with patch.object(sys, 'argv', testargs): prepareSystem.main() @@ -140,7 +163,22 @@ class Test(unittest.TestCase): if ip != i: fp.write('add-exclusive-node=127.0.0.1:{}\n'.format(XMR_BASE_P2P_PORT + ip)) - assert(os.path.exists(config_path)) + with open(config_path) as fs: + settings = json.load(fs) + + settings['min_delay_event'] = 1 + settings['max_delay_event'] = 4 + + settings['check_progress_seconds'] = 5 + settings['check_watched_seconds'] = 5 + settings['check_expired_seconds'] = 60 + settings['check_events_seconds'] = 5 + settings['check_xmr_swaps_seconds'] = 5 + + with open(config_path, 'w') as fp: + json.dump(settings, fp, indent=4) + + signal.signal(signal.SIGINT, signal_handler) def run_thread(self, client_id): client_path = os.path.join(test_path, 'client{}'.format(client_id)) @@ -148,14 +186,12 @@ class Test(unittest.TestCase): with patch.object(sys, 'argv', testargs): runSystem.main() - def test_reload(self): - global stop_test - update_thread = None - processes = [] + def start_processes(self): + delay_event.clear() for i in range(3): - processes.append(multiprocessing.Process(target=self.run_thread, args=(i,))) - processes[-1].start() + self.processes.append(multiprocessing.Process(target=self.run_thread, args=(i,))) + self.processes[-1].start() try: waitForServer(12701) @@ -163,12 +199,38 @@ class Test(unittest.TestCase): wallets = json.loads(urlopen('http://localhost:12701/json/wallets').read()) xmr_addr1 = wallets['6']['deposit_address'] - num_blocks = 500 + num_blocks = 100 - logging.info('Mining %d Monero blocks.', num_blocks) - callrpc_xmr_na(XMR_BASE_RPC_PORT + 1, 'generateblocks', {'wallet_address': xmr_addr1, 'amount_of_blocks': num_blocks}) - rv = callrpc_xmr_na(XMR_BASE_RPC_PORT + 1, 'get_block_count') - logging.info('XMR blocks: %d', rv['count']) + if callrpc_xmr_na(XMR_BASE_RPC_PORT + 1, 'get_block_count')['count'] < num_blocks: + logging.info('Mining {} Monero blocks to {}.'.format(num_blocks, xmr_addr1)) + callrpc_xmr_na(XMR_BASE_RPC_PORT + 1, 'generateblocks', {'wallet_address': xmr_addr1, 'amount_of_blocks': num_blocks}) + logging.info('XMR blocks: %d', callrpc_xmr_na(XMR_BASE_RPC_PORT + 1, 'get_block_count')['count']) + + self.update_thread = threading.Thread(target=updateThread, args=(xmr_addr1,)) + self.update_thread.start() + except Exception: + traceback.print_exc() + + def stop_processes(self): + logger.info('Stopping test') + delay_event.set() + if self.update_thread: + self.update_thread.join() + for p in self.processes: + p.terminate() + for p in self.processes: + p.join() + self.update_thread = None + self.processes = [] + + def test_01_reload(self): + self.start_processes() + + try: + waitForServer(12700) + waitForServer(12701) + wallets1 = json.loads(urlopen('http://localhost:12701/json/wallets').read()) + assert(float(wallets1['6']['balance']) > 0.0) data = parse.urlencode({ 'addr_from': '-1', @@ -201,7 +263,7 @@ class Test(unittest.TestCase): bid = bids[0] if bid['bid_state'] == 'Received': break - time.sleep(1) + delay_event.wait(1) data = parse.urlencode({ 'accept': True @@ -212,39 +274,48 @@ class Test(unittest.TestCase): waitForNumSwapping(12701, 1) logger.info('Restarting client') - c1 = processes[1] + c1 = self.processes[1] c1.terminate() c1.join() - processes[1] = multiprocessing.Process(target=self.run_thread, args=(1,)) - processes[1].start() + self.processes[1] = multiprocessing.Process(target=self.run_thread, args=(1,)) + self.processes[1].start() waitForServer(12701) rv = json.loads(urlopen('http://localhost:12701/json').read()) assert(rv['num_swapping'] == 1) - update_thread = threading.Thread(target=updateThread, args=(xmr_addr1,)) - update_thread.start() - logger.info('Completing swap') for i in range(240): - time.sleep(5) + if delay_event.is_set(): + raise ValueError('Test stopped.') + delay_event.wait(4) rv = json.loads(urlopen('http://localhost:12700/json/bids/{}'.format(bid['bid_id'])).read()) - print(rv) if rv['bid_state'] == 'Completed': break assert(rv['bid_state'] == 'Completed') - except Exception: + except Exception as e: traceback.print_exc() + raise(e) + finally: + self.stop_processes() - logger.info('Stopping test') - stop_test = True - if update_thread: - update_thread.join() - for p in processes: - p.terminate() - for p in processes: - p.join() + def test_02_bids_offline(self): + # Start multiple bids while offering node is offline + self.start_processes() + + try: + waitForServer(12700) + waitForServer(12701) + wallets1 = json.loads(urlopen('http://localhost:12701/json/wallets').read()) + print('wallets 1', json.dumps(wallets1, indent=4)) + assert(float(wallets1['6']['balance']) > 0.0) + + except Exception as e: + traceback.print_exc() + raise(e) + finally: + self.stop_processes() if __name__ == '__main__': diff --git a/tests/basicswap/test_run.py b/tests/basicswap/test_run.py index f202e9f..01e80a9 100644 --- a/tests/basicswap/test_run.py +++ b/tests/basicswap/test_run.py @@ -1,15 +1,15 @@ #!/usr/bin/env python3 # -*- coding: utf-8 -*- -# Copyright (c) 2019 tecnovert +# Copyright (c) 2019-2021 tecnovert # Distributed under the MIT software license, see the accompanying # file LICENSE or http://www.opensource.org/licenses/mit-license.php. """ -basicswap]$ python setup.py test +basicswap]$ pytest Run one test: -$ python setup.py test -s tests.basicswap.test_run.Test.test_04_ltc_btc +$ pytest -v -s tests/basicswap/test_run.py::Test::test_04_ltc_btc """ diff --git a/tests/basicswap/test_xmr.py b/tests/basicswap/test_xmr.py index cc01b9b..ddd67d8 100644 --- a/tests/basicswap/test_xmr.py +++ b/tests/basicswap/test_xmr.py @@ -1,7 +1,7 @@ #!/usr/bin/env python3 # -*- coding: utf-8 -*- -# Copyright (c) 2020 tecnovert +# Copyright (c) 2020-2021 tecnovert # Distributed under the MIT software license, see the accompanying # file LICENSE or http://www.opensource.org/licenses/mit-license.php. @@ -103,7 +103,7 @@ def prepareXmrDataDir(datadir, node_id, conf_file): fp.write('rpc-bind-port={}\n'.format(XMR_BASE_RPC_PORT + node_id)) fp.write('p2p-bind-ip=127.0.0.1\n') fp.write('rpc-bind-ip=127.0.0.1\n') - + fp.write('prune-blockchain=1\n') fp.write('zmq-rpc-bind-port={}\n'.format(XMR_BASE_ZMQ_PORT + node_id)) fp.write('zmq-rpc-bind-ip=127.0.0.1\n') @@ -118,6 +118,7 @@ def startXmrWalletRPC(node_dir, bin_dir, wallet_bin, node_id, opts=[]): data_dir = os.path.expanduser(node_dir) args = [daemon_bin] + args += ['--non-interactive'] args += ['--daemon-address=localhost:{}'.format(XMR_BASE_RPC_PORT + node_id)] args += ['--no-dns'] args += ['--rpc-bind-port={}'.format(XMR_BASE_WALLET_RPC_PORT + node_id)] @@ -370,17 +371,17 @@ class Test(unittest.TestCase): cls.btc_addr = callnoderpc(0, 'getnewaddress', ['mining_addr', 'bech32'], base_rpc_port=BTC_BASE_RPC_PORT) cls.xmr_addr = cls.callxmrnodewallet(cls, 1, 'get_address')['address'] - num_blocks = 500 + num_blocks = 500 # Mine enough to activate segwit 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)) + num_blocks = 100 if callrpc_xmr_na(XMR_BASE_RPC_PORT + 1, 'get_block_count')['count'] < num_blocks: - logging.info('Mining %d Monero blocks.', num_blocks) + logging.info('Mining %d Monero blocks to %s.', num_blocks, cls.xmr_addr) callrpc_xmr_na(XMR_BASE_RPC_PORT + 1, 'generateblocks', {'wallet_address': cls.xmr_addr, 'amount_of_blocks': num_blocks}) - rv = callrpc_xmr_na(XMR_BASE_RPC_PORT + 1, 'get_block_count') - logging.info('XMR blocks: %d', rv['count']) + logging.info('XMR blocks: %d', callrpc_xmr_na(XMR_BASE_RPC_PORT + 1, 'get_block_count')['count']) logging.info('Starting update thread.') signal.signal(signal.SIGINT, signal_handler) @@ -629,8 +630,12 @@ class Test(unittest.TestCase): logging.info('---------- Test xmr withdrawals') swap_clients = self.swap_clients js_0 = json.loads(urlopen('http://localhost:1800/json/wallets').read()) + print('js_0 debug', js_0) address_to = js_0[str(int(Coins.XMR))]['deposit_address'] + js_1 = json.loads(urlopen('http://localhost:1801/json/wallets').read()) + assert(float(js_1[str(int(Coins.XMR))]['balance']) > 0.0) + swap_clients[1].withdrawCoin(Coins.XMR, 1.1, address_to, False) def test_09_auto_accept(self): diff --git a/tox.ini b/tox.ini new file mode 100644 index 0000000..1d73a60 --- /dev/null +++ b/tox.ini @@ -0,0 +1,23 @@ +[tox] +envlist = py3 + +[testenv] +setenv = + COINCURVE_IGNORE_SYSTEM_LIB = 1 +passenv = + PARTICL_BINDIR + BITCOIN_BINDIR + LITECOIN_BINDIR + XMR_BINDIR +deps = + pytest + -rrequirements.txt + git+https://github.com/tecnovert/coincurve.git@anonswap#egg=coincurve +commands = + pytest + +[pytest] +addopts = -v -s +norecursedirs = tests/basicswap/extended +testpaths = + tests