Browse Source

setup.py test -> pytest / tox

pivx
tecnovert 3 years ago
parent
commit
a3ba5cf7e6
No known key found for this signature in database GPG Key ID: 8ED6D8750C4E3F93
  1. 50
      .cirrus.yml
  2. 2
      .gitignore
  3. 43
      .travis.yml
  4. 57
      basicswap/http_server.py
  5. 5
      basicswap/interface_btc.py
  6. 5
      basicswap/interface_part.py
  7. 1
      basicswap/interface_xmr.py
  8. 90
      bin/basicswap_prepare.py
  9. 2
      bin/basicswap_run.py
  10. 2
      doc/notes.md
  11. 12
      setup.py
  12. 17
      tests/basicswap/__init__.py
  13. 0
      tests/basicswap/extended/test_network.py
  14. 10
      tests/basicswap/extended/test_nmc.py
  15. 38
      tests/basicswap/extended/test_wallet_init.py
  16. 6
      tests/basicswap/test_reload.py
  17. 173
      tests/basicswap/test_reload_xmr.py
  18. 6
      tests/basicswap/test_run.py
  19. 17
      tests/basicswap/test_xmr.py
  20. 23
      tox.ini

50
.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

2
.gitignore

@ -5,3 +5,5 @@ __pycache__
/*.egg-info
/*.egg
/*.eggs
.tox
.eggs

43
.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

57
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):

5
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']

5
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']

1
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())

90
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:

2
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():

2
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

12
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"
}
)

17
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

0
tests/basicswap/test_network.py → tests/basicswap/extended/test_network.py

10
tests/basicswap/test_nmc.py → 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

38
tests/basicswap/test_wallet_init.py → 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()

6
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):

173
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
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 = []
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'])
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__':

6
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
"""

17
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):

23
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
Loading…
Cancel
Save