diff --git a/bin/basicswap_prepare.py b/bin/basicswap_prepare.py index 78666af..5a7f5e7 100755 --- a/bin/basicswap_prepare.py +++ b/bin/basicswap_prepare.py @@ -78,6 +78,16 @@ logger.level = logging.DEBUG if not len(logger.handlers): logger.addHandler(logging.StreamHandler(sys.stdout)) +UI_HTML_PORT = int(os.getenv('UI_HTML_PORT', 12700)) +COINS_RPCBIND_IP = os.getenv('COINS_RPCBIND_IP', '127.0.0.1') + +PART_ZMQ_PORT = int(os.getenv('PART_ZMQ_PORT', 20792)) +PART_RPC_HOST = os.getenv('PART_RPC_HOST', '127.0.0.1') +PART_RPC_PORT = int(os.getenv('PART_RPC_PORT', 19792)) +PART_ONION_PORT = int(os.getenv('PART_ONION_PORT', 51734)) +PART_RPC_USER = os.getenv('PART_RPC_USER', '') +PART_RPC_PWD = os.getenv('PART_RPC_PWD', '') + XMR_RPC_HOST = os.getenv('XMR_RPC_HOST', '127.0.0.1') BASE_XMR_RPC_PORT = int(os.getenv('BASE_XMR_RPC_PORT', 29798)) BASE_XMR_ZMQ_PORT = int(os.getenv('BASE_XMR_ZMQ_PORT', 30898)) @@ -86,34 +96,22 @@ XMR_WALLET_RPC_HOST = os.getenv('XMR_WALLET_RPC_HOST', '127.0.0.1') XMR_WALLET_RPC_USER = os.getenv('XMR_WALLET_RPC_USER', 'xmr_wallet_user') XMR_WALLET_RPC_PWD = os.getenv('XMR_WALLET_RPC_PWD', 'xmr_wallet_pwd') XMR_SITE_COMMIT = 'abcf12c4ccac3e48bb4ff178f18bb8a95d94b029' # Lock hashes.txt to monero version - DEFAULT_XMR_RESTORE_HEIGHT = int(os.getenv('DEFAULT_XMR_RESTORE_HEIGHT', 2245107)) -UI_HTML_PORT = int(os.getenv('UI_HTML_PORT', 12700)) -PART_ZMQ_PORT = int(os.getenv('PART_ZMQ_PORT', 20792)) - -PART_RPC_HOST = os.getenv('PART_RPC_HOST', '127.0.0.1') LTC_RPC_HOST = os.getenv('LTC_RPC_HOST', '127.0.0.1') -BTC_RPC_HOST = os.getenv('BTC_RPC_HOST', '127.0.0.1') -NMC_RPC_HOST = os.getenv('NMC_RPC_HOST', '127.0.0.1') - -PART_RPC_PORT = int(os.getenv('PART_RPC_PORT', 19792)) LTC_RPC_PORT = int(os.getenv('LTC_RPC_PORT', 19895)) -BTC_RPC_PORT = int(os.getenv('BTC_RPC_PORT', 19996)) -NMC_RPC_PORT = int(os.getenv('NMC_RPC_PORT', 19698)) - -PART_ONION_PORT = int(os.getenv('PART_ONION_PORT', 51734)) LTC_ONION_PORT = int(os.getenv('LTC_ONION_PORT', 9333)) -BTC_ONION_PORT = int(os.getenv('BTC_ONION_PORT', 8334)) - -PART_RPC_USER = os.getenv('PART_RPC_USER', '') -PART_RPC_PWD = os.getenv('PART_RPC_PWD', '') -BTC_RPC_USER = os.getenv('BTC_RPC_USER', '') -BTC_RPC_PWD = os.getenv('BTC_RPC_PWD', '') LTC_RPC_USER = os.getenv('LTC_RPC_USER', '') LTC_RPC_PWD = os.getenv('LTC_RPC_PWD', '') -COINS_RPCBIND_IP = os.getenv('COINS_RPCBIND_IP', '127.0.0.1') +BTC_RPC_HOST = os.getenv('BTC_RPC_HOST', '127.0.0.1') +BTC_RPC_PORT = int(os.getenv('BTC_RPC_PORT', 19996)) +BTC_ONION_PORT = int(os.getenv('BTC_ONION_PORT', 8334)) +BTC_RPC_USER = os.getenv('BTC_RPC_USER', '') +BTC_RPC_PWD = os.getenv('BTC_RPC_PWD', '') + +NMC_RPC_HOST = os.getenv('NMC_RPC_HOST', '127.0.0.1') +NMC_RPC_PORT = int(os.getenv('NMC_RPC_PORT', 19698)) TOR_PROXY_HOST = os.getenv('TOR_PROXY_HOST', '127.0.0.1') TOR_PROXY_PORT = int(os.getenv('TOR_PROXY_PORT', 9050)) @@ -125,7 +123,6 @@ TEST_ONION_LINK = toBool(os.getenv('TEST_ONION_LINK', 'false')) BITCOIN_FASTSYNC_URL = os.getenv('BITCOIN_FASTSYNC_URL', 'http://utxosets.blob.core.windows.net/public/') BITCOIN_FASTSYNC_FILE = os.getenv('BITCOIN_FASTSYNC_FILE', 'utxo-snapshot-bitcoin-mainnet-720179.tar') - use_tor_proxy = False default_socket = socket.socket @@ -207,9 +204,15 @@ def testOnionLink(): logger.info('Onion links work.') -def ensureValidSignatureBy(result, signing_key_name): +def isValidSignature(result): if result.valid is False \ - and not (result.status == 'signature valid' and result.key_status == 'signing key has expired'): + and (result.status == 'signature valid' and result.key_status == 'signing key has expired'): + return True + return result.valid + + +def ensureValidSignatureBy(result, signing_key_name): + if not isValidSignature(result): raise ValueError('Signature verification failed.') if result.key_id not in expected_key_ids[signing_key_name]: @@ -378,17 +381,26 @@ def prepareCore(coin, version_data, settings, data_dir, extra_opts={}): """ gpg = gnupg.GPG() + keysdirpath = extra_opts.get('keysdirpath', None) + if keysdirpath is not None: + logger.info(f'Loading PGP keys from: {keysdirpath}.') + for path in os.scandir(keysdirpath): + if path.is_file(): + with open(path, 'rb') as fp: + rv = gpg.import_keys(fp.read()) + for key in rv.fingerprints: + gpg.trust_keys(rv.fingerprints[0], 'TRUST_FULLY') + if coin == 'monero': with open(assert_path, 'rb') as fp: verified = gpg.verify_file(fp) - if verified.username is None: + if not isValidSignature(verified) and verified.username is None: logger.warning('Signature made by unknown key.') pubkeyurl = 'https://raw.githubusercontent.com/monero-project/monero/master/utils/gpg_keys/binaryfate.asc' logger.info('Importing public key from url: ' + pubkeyurl) rv = gpg.import_keys(downloadBytes(pubkeyurl)) - assert('F0AF4D462A0BDF92' in rv.fingerprints[0]) gpg.trust_keys(rv.fingerprints[0], 'TRUST_FULLY') with open(assert_path, 'rb') as fp: verified = gpg.verify_file(fp) @@ -396,7 +408,7 @@ def prepareCore(coin, version_data, settings, data_dir, extra_opts={}): with open(assert_sig_path, 'rb') as fp: verified = gpg.verify_file(fp, assert_path) - if verified.username is None: + if not isValidSignature(verified) and verified.username is None: logger.warning('Signature made by unknown key.') filename = '{}_{}.pgp'.format(coin, signing_key_name) @@ -745,6 +757,7 @@ def printHelp(): logger.info('--usebtcfastsync Initialise the BTC chain with a snapshot from btcpayserver FastSync.\n' + ' See https://github.com/btcpayserver/btcpayserver-docker/blob/master/contrib/FastSync/README.md') logger.info('--initwalletsonly Setup coin wallets only.') + logger.info('--keysdirpath Speed up tests by preloading all PGP keys in directory.') logger.info('\n' + 'Known coins: %s', ', '.join(known_coins.keys())) @@ -843,13 +856,11 @@ def main(): xmr_restore_height = DEFAULT_XMR_RESTORE_HEIGHT prepare_bin_only = False no_cores = False - use_containers = False enable_tor = False disable_tor = False - tor_control_password = None - use_btc_fastsync = False - extract_core_overwrite = True initwalletsonly = False + tor_control_password = None + extra_opts = {} for v in sys.argv[1:]: if len(v) < 2 or v[0] != '-': @@ -883,10 +894,10 @@ def main(): no_cores = True continue if name == 'usecontainers': - use_containers = True + extra_opts['use_containers'] = True continue if name == 'noextractover': - extract_core_overwrite = False + extra_opts['extract_core_overwrite'] = False continue if name == 'usetorproxy': use_tor_proxy = True @@ -898,7 +909,7 @@ def main(): disable_tor = True continue if name == 'usebtcfastsync': - use_btc_fastsync = True + extra_opts['use_btc_fastsync'] = True continue if name == 'initwalletsonly': initwalletsonly = True @@ -947,6 +958,9 @@ def main(): if name == 'xmrrestoreheight': xmr_restore_height = int(s[1]) continue + if name == 'keysdirpath': + extra_opts['keysdirpath'] = os.path.expanduser(s[1].strip('"')) + continue exitWithError('Unknown argument {}'.format(v)) @@ -1122,13 +1136,8 @@ def main(): logger.info('Done.') return 0 - extra_opts = { - 'use_btc_fastsync': use_btc_fastsync, - 'extract_core_overwrite': extract_core_overwrite, - 'data_dir': data_dir, - 'use_containers': use_containers, - 'tor_control_password': tor_control_password, - } + extra_opts['data_dir'] = data_dir + extra_opts['tor_control_password'] = tor_control_password if add_coin != '': logger.info('Adding coin: %s', add_coin) diff --git a/pgp/keys/monero_binaryfate.asc b/pgp/keys/monero_binaryfate.asc new file mode 100644 index 0000000..55c5b16 --- /dev/null +++ b/pgp/keys/monero_binaryfate.asc @@ -0,0 +1,87 @@ +-----BEGIN PGP PUBLIC KEY BLOCK----- + +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 +lmE0kDaYQqoBKXNXcybElBID8Q== +=tkJZ +-----END PGP PUBLIC KEY BLOCK----- diff --git a/tests/basicswap/common_xmr.py b/tests/basicswap/common_xmr.py index c1f0cad..96aa5ad 100644 --- a/tests/basicswap/common_xmr.py +++ b/tests/basicswap/common_xmr.py @@ -92,6 +92,10 @@ def run_prepare(node_id, datadir_path, bins_path, with_coins, mnemonic_in=None, '-xmrrestoreheight=0'] if mnemonic_in: testargs.append(f'-particl_mnemonic="{mnemonic_in}"') + + keysdirpath = os.getenv('PGP_KEYS_DIR_PATH', None) + if keysdirpath is not None: + testargs.append('-keysdirpath="' + os.path.expanduser(keysdirpath) + '"') with patch.object(sys, 'argv', testargs), patch('sys.stdout', new=StringIO()) as mocked_stdout: prepareSystem.main() lines = mocked_stdout.getvalue().split('\n') diff --git a/tests/basicswap/extended/test_network.py b/tests/basicswap/extended/test_network.py index d442856..53df3de 100644 --- a/tests/basicswap/extended/test_network.py +++ b/tests/basicswap/extended/test_network.py @@ -12,8 +12,8 @@ import shutil import signal import logging import unittest -import traceback import threading +import traceback import basicswap.config as cfg from basicswap.basicswap import ( diff --git a/tests/basicswap/extended/test_wallet_restore.py b/tests/basicswap/extended/test_wallet_restore.py index 5b4926c..25a94ec 100644 --- a/tests/basicswap/extended/test_wallet_restore.py +++ b/tests/basicswap/extended/test_wallet_restore.py @@ -9,6 +9,7 @@ export TEST_PATH=/tmp/test_basicswap_wallet_restore mkdir -p ${TEST_PATH}/bin cp -r ~/tmp/basicswap_bin/* ${TEST_PATH}/bin +export PGP_KEYS_DIR_PATH=$(pwd)/pgp/keys export PYTHONPATH=$(pwd) python tests/basicswap/extended/test_wallet_restore.py @@ -20,19 +21,29 @@ import sys import shutil import logging import unittest +import threading import traceback import multiprocessing from unittest.mock import patch from tests.basicswap.common import ( read_json_api, + post_json_api, waitForServer, + waitForNumOffers, + waitForNumBids, ) from tests.basicswap.common_xmr import ( TestBase, run_prepare, + waitForBidState, ) +from basicswap.rpc import ( + callrpc, +) +from tests.basicswap.mnemonics import mnemonics import bin.basicswap_run as runSystem +from bin.basicswap_prepare import LTC_RPC_PORT, BTC_RPC_PORT TEST_PATH = os.path.expanduser(os.getenv('TEST_PATH', '~/test_basicswap1')) @@ -42,6 +53,23 @@ if not len(logger.handlers): logger.addHandler(logging.StreamHandler(sys.stdout)) +def callbtcnoderpc(node_id, method, params=[], wallet=None, base_rpc_port=BTC_RPC_PORT): + auth = 'test_btc_{0}:test_btc_pwd_{0}'.format(node_id) + return callrpc(base_rpc_port + node_id, auth, method, params, wallet) + + +def callltcnoderpc(node_id, method, params=[], wallet=None, base_rpc_port=LTC_RPC_PORT): + auth = 'test_ltc_{0}:test_ltc_pwd_{0}'.format(node_id) + return callrpc(base_rpc_port + node_id, auth, method, params, wallet) + + +def updateThread(self): + while not self.delay_event.is_set(): + callbtcnoderpc(2, 'generatetoaddress', [1, self.btc_addr]) + callltcnoderpc(1, 'generatetoaddress', [1, self.ltc_addr]) + self.delay_event.wait(2) + + def prepare_node(node_id, mnemonic): logging.info('Preparing node: %d.', node_id) bins_path = os.path.join(TEST_PATH, 'bin') @@ -50,18 +78,18 @@ def prepare_node(node_id, mnemonic): shutil.rmtree(client_path) except Exception as ex: logging.warning('setUpClass %s', str(ex)) - return run_prepare(node_id, client_path, bins_path, 'monero,bitcoin,litecoin', mnemonic) + return run_prepare(node_id, client_path, bins_path, 'monero,bitcoin,litecoin', mnemonic, 3, use_rpcauth=True) class Test(TestBase): @classmethod def setUpClass(cls): super(Test, cls).setUpClass(cls) - + cls.update_thread = None cls.used_mnemonics = [] - # Load wallets from random mnemonics + # Load wallets from random mnemonics, except node0 which needs to import PART from the genesis block for i in range(3): - cls.used_mnemonics.append(prepare_node(i, None)) + cls.used_mnemonics.append(prepare_node(i, mnemonics[0] if i == 0 else None)) def run_thread(self, client_id): client_path = os.path.join(TEST_PATH, 'client{}'.format(client_id)) @@ -70,7 +98,6 @@ class Test(TestBase): runSystem.main() def test_wallet(self): - update_thread = None processes = [] self.wait_seconds(5) @@ -81,24 +108,77 @@ class Test(TestBase): try: waitForServer(self.delay_event, 12700) waitForServer(self.delay_event, 12701) - # TODO: Add swaps + waitForServer(self.delay_event, 12702) - ltc_before = read_json_api(12700, 'wallets/ltc') + num_blocks = 500 # Mine enough to activate segwit + self.btc_addr = callbtcnoderpc(2, 'getnewaddress', ['mining_addr', 'bech32']) + logging.info('Mining %d Bitcoin blocks to %s', num_blocks, self.btc_addr) + callbtcnoderpc(2, 'generatetoaddress', [num_blocks, self.btc_addr]) + + num_blocks = 431 + self.ltc_addr = callltcnoderpc(1, 'getnewaddress', ['mining_addr', 'bech32']) + logging.info('Mining %d Litecoin blocks to %s', num_blocks, self.ltc_addr) + callltcnoderpc(1, 'generatetoaddress', [num_blocks, self.ltc_addr]) + + mweb_addr = callltcnoderpc(1, 'getnewaddress', ['mweb_addr', 'mweb']) + callltcnoderpc(1, 'sendtoaddress', [mweb_addr, 1]) + num_blocks = 69 + callltcnoderpc(1, 'generatetoaddress', [num_blocks, self.ltc_addr]) + + self.update_thread = threading.Thread(target=updateThread, args=(self,)) + self.update_thread.start() + + data = { + 'addr_from': '-1', + 'coin_from': 'part', + 'coin_to': 'ltc', + 'amt_from': '1', + 'amt_to': '1', + 'lockhrs': '24', + 'automation_strat_id': 1} + + offer_id = post_json_api(12700, 'offers/new', data)['offer_id'] + summary = read_json_api(12700) + assert(summary['num_sent_offers'] == 1) + + logger.info('Waiting for offer') + waitForNumOffers(self.delay_event, 12701, 1) + + offers = read_json_api(12701, 'offers') + offer = offers[0] + + data = { + 'offer_id': offer['offer_id'], + 'amount_from': offer['amount_from']} + + bid_id = post_json_api(12701, 'bids/new', data)['bid_id'] + + waitForNumBids(self.delay_event, 12700, 1) + + waitForBidState(self.delay_event, 12700, bid_id, 'Completed') + waitForBidState(self.delay_event, 12701, bid_id, 'Completed') logging.info('Starting a new node on the same mnemonic as the first') prepare_node(3, self.used_mnemonics[0]) processes.append(multiprocessing.Process(target=self.run_thread, args=(3,))) processes[-1].start() waitForServer(self.delay_event, 12703) - ltc_after = read_json_api(12703, 'wallets/ltc') - assert(ltc_before['deposit_address'] == ltc_after['deposit_address']) + # TODO: Try detect past swaps + + ltc_orig = read_json_api(12700, 'wallets/ltc') + ltc_restored = read_json_api(12703, 'wallets/ltc') + assert(float(ltc_orig['balance']) + float(ltc_orig['unconfirmed']) > 0.0) + assert(float(ltc_orig['balance']) + float(ltc_orig['unconfirmed']) == float(ltc_restored['balance']) + float(ltc_restored['unconfirmed'])) + + logging.info('Test passed.') except Exception: traceback.print_exc() - if update_thread: - update_thread.join() + self.delay_event.set() + if self.update_thread: + self.update_thread.join() for p in processes: p.terminate() for p in processes: diff --git a/tests/basicswap/extended/test_xmr_persistent.py b/tests/basicswap/extended/test_xmr_persistent.py index fbf86ae..15f46e6 100644 --- a/tests/basicswap/extended/test_xmr_persistent.py +++ b/tests/basicswap/extended/test_xmr_persistent.py @@ -120,8 +120,8 @@ class Test(unittest.TestCase): random.seed(time.time()) - os.environ['PARTICL_PORT_BASE'] = str(BASE_PART_RPC_PORT) - os.environ['BITCOIN_PORT_BASE'] = str(BASE_BTC_RPC_PORT) + os.environ['PARTICL_RPC_PORT_BASE'] = str(BASE_PART_RPC_PORT) + os.environ['BITCOIN_RPC_PORT_BASE'] = str(BASE_BTC_RPC_PORT) logging.info('Preparing %d nodes.', NUM_NODES) prepare_nodes(NUM_NODES, 'bitcoin,monero', True, {'min_sequence_lock_seconds': 60}, PORT_OFS) diff --git a/tests/basicswap/test_xmr.py b/tests/basicswap/test_xmr.py index 9b17669..52be289 100644 --- a/tests/basicswap/test_xmr.py +++ b/tests/basicswap/test_xmr.py @@ -441,7 +441,7 @@ class BaseTest(unittest.TestCase): cls.http_threads.append(t) t.start() - # Set future block rewards to nowhere (a random address) + # Set future block rewards to nowhere (a random address), so wallet amounts stay constant eckey = ECKey() eckey.generate() void_block_rewards_pubkey = eckey.get_pubkey().get_bytes() @@ -451,6 +451,7 @@ class BaseTest(unittest.TestCase): 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) + # Switch addresses so wallet amounts stay constant num_blocks = 100 cls.btc_addr = cls.swap_clients[0].ci(Coins.BTC).pubkey_to_segwit_address(void_block_rewards_pubkey) logging.info('Mining %d Bitcoin blocks to %s', num_blocks, cls.btc_addr)