mirror of
https://github.com/basicswap/basicswap.git
synced 2025-01-18 16:44:34 +00:00
basicswap-prepare tries to initialise coin wallets from Particl mnemonic
Bitcoin 0.20: 'Cannot set a new HD seed while still in Initial Block Download.' Removed in 0.21
This commit is contained in:
parent
3bbb483a0a
commit
5a163e0f86
18 changed files with 754 additions and 93 deletions
|
@ -11,7 +11,7 @@ lint_task:
|
|||
|
||||
test_task:
|
||||
environment:
|
||||
- PART_VERSION: 0.19.1.1
|
||||
- PART_VERSION: 0.19.1.2
|
||||
- BTC_VERSION: 0.20.1
|
||||
- LTC_VERSION: 0.18.1
|
||||
- TEST_RELOAD_PATH: $HOME/test_basicswap1/
|
||||
|
|
|
@ -7,7 +7,7 @@ stages:
|
|||
- test
|
||||
env:
|
||||
global:
|
||||
- PART_VERSION=0.19.1.1
|
||||
- PART_VERSION=0.19.1.2
|
||||
- BTC_VERSION=0.20.1
|
||||
- LTC_VERSION=0.18.1
|
||||
- TEST_DIR=~/test_basicswap2/
|
||||
|
|
|
@ -49,6 +49,9 @@ class BaseApp:
|
|||
self.log = logging.getLogger(self.log_name)
|
||||
self.log.propagate = False
|
||||
|
||||
# Remove any existing handlers
|
||||
self.log.handlers = []
|
||||
|
||||
formatter = logging.Formatter('%(asctime)s %(levelname)s : %(message)s')
|
||||
stream_stdout = logging.StreamHandler()
|
||||
if self.log_name != 'BasicSwap':
|
||||
|
@ -81,6 +84,12 @@ class BaseApp:
|
|||
testnet_name = '' if self.chain == 'mainnet' else chainparams[coin][self.chain].get('name', self.chain)
|
||||
return os.path.join(datadir, testnet_name)
|
||||
|
||||
def getCoinIdFromName(self, coin_name):
|
||||
for c, params in chainparams.items():
|
||||
if coin_name.lower() == params['name'].lower():
|
||||
return c
|
||||
raise ValueError('Unknown coin: {}'.format(coin_name))
|
||||
|
||||
def getTicker(self, coin_type):
|
||||
ticker = chainparams[coin_type]['ticker']
|
||||
if self.chain == 'testnet':
|
||||
|
|
|
@ -551,7 +551,6 @@ class BasicSwap(BaseApp):
|
|||
self.coin_clients[coin]['walletrpcauth'] = (chain_client_settings['walletrpcuser'], chain_client_settings['walletrpcpassword'])
|
||||
else:
|
||||
raise ValueError('Missing XMR wallet rpc credentials.')
|
||||
self.coin_clients[coin]['interface'] = self.createInterface(coin)
|
||||
|
||||
def ci(self, coin): # coin interface
|
||||
return self.coin_clients[coin]['interface']
|
||||
|
@ -593,17 +592,17 @@ class BasicSwap(BaseApp):
|
|||
try:
|
||||
with open(pidfilepath, 'rb') as fp:
|
||||
datadir_pid = int(fp.read().decode('utf-8'))
|
||||
assert(datadir_pid == cc['pid'])
|
||||
assert(datadir_pid == cc['pid']), 'Mismatched pid'
|
||||
assert(os.path.exists(authcookiepath))
|
||||
except Exception:
|
||||
time.sleep(0.5)
|
||||
try:
|
||||
if os.name != 'nt' or cc['core_version_group'] > 17: # litecoin on windows doesn't write a pid file
|
||||
assert(datadir_pid == cc['pid'])
|
||||
assert(datadir_pid == cc['pid']), 'Mismatched pid'
|
||||
with open(authcookiepath, 'rb') as fp:
|
||||
cc['rpcauth'] = fp.read().decode('utf-8')
|
||||
except Exception:
|
||||
self.log.error('Unable to read authcookie for %s, %s, datadir pid %d, daemon pid %s', str(coin), authcookiepath, datadir_pid, cc['pid'])
|
||||
except Exception as e:
|
||||
self.log.error('Unable to read authcookie for %s, %s, datadir pid %d, daemon pid %s. Error: %s', str(coin), authcookiepath, datadir_pid, cc['pid'], str(e))
|
||||
raise ValueError('Error, terminating')
|
||||
|
||||
def createCoinInterface(self, coin):
|
||||
|
@ -626,6 +625,9 @@ class BasicSwap(BaseApp):
|
|||
self.log.info('%s Core version %d', chainparams[c]['name'].capitalize(), core_version)
|
||||
self.coin_clients[c]['core_version'] = core_version
|
||||
|
||||
if c == Coins.XMR:
|
||||
self.coin_clients[c]['interface'].ensureWalletExists()
|
||||
|
||||
if c == Coins.PART:
|
||||
self.coin_clients[c]['have_spent_index'] = self.coin_clients[c]['interface'].haveSpentIndex()
|
||||
|
||||
|
@ -636,6 +638,8 @@ class BasicSwap(BaseApp):
|
|||
self.initialise()
|
||||
|
||||
def stopDaemon(self, coin):
|
||||
if coin == Coins.XMR:
|
||||
return
|
||||
num_tries = 10
|
||||
authcookiepath = os.path.join(self.getChainDatadirPath(coin), '.cookie')
|
||||
stopping = False
|
||||
|
@ -697,6 +701,19 @@ class BasicSwap(BaseApp):
|
|||
if synced < 1.0:
|
||||
raise ValueError('{} chain is still syncing, currently at {}.'.format(self.coin_clients[c]['name'], synced))
|
||||
|
||||
def initialiseWallet(self, coin_type):
|
||||
ci = self.ci(coin_type)
|
||||
self.log.info('Initialising {} wallet.'.format(ci.coin_name()))
|
||||
|
||||
if coin_type == Coins.XMR:
|
||||
key_view = self.getWalletKey(coin_type, 1, for_ed25519=True)
|
||||
key_spend = self.getWalletKey(coin_type, 2, for_ed25519=True)
|
||||
ci.initialiseWallet(key_view, key_spend)
|
||||
return
|
||||
|
||||
root_key = self.getWalletKey(coin_type, 1)
|
||||
ci.initialiseWallet(root_key)
|
||||
|
||||
def setIntKV(self, str_key, int_val):
|
||||
session = scoped_session(self.session_factory)
|
||||
kv = session.query(DBKVInt).filter_by(key=str_key).first()
|
||||
|
@ -963,19 +980,8 @@ class BasicSwap(BaseApp):
|
|||
session.remove()
|
||||
self.mxDB.release()
|
||||
|
||||
def getPathKey(self, coin_from, coin_to, offer_created_at, contract_count, key_no, for_xmr=False):
|
||||
account = self.callcoinrpc(Coins.PART, 'extkey', ['account'])
|
||||
evkey = self.callcoinrpc(Coins.PART, 'extkey', ['account', 'default', 'true'])['evkey']
|
||||
ci = self.ci(coin_to)
|
||||
|
||||
days = offer_created_at // 86400
|
||||
secs = offer_created_at - days * 86400
|
||||
key_path_base = '44445555h/999999/{}/{}/{}/{}/{}/{}'.format(int(coin_from), int(coin_to), days, secs, contract_count, key_no)
|
||||
|
||||
if not for_xmr:
|
||||
extkey = self.callcoinrpc(Coins.PART, 'extkey', ['info', evkey, key_path_base])['key_info']['result']
|
||||
return decodeWif(self.callcoinrpc(Coins.PART, 'extkey', ['info', extkey])['key_info']['privkey'])
|
||||
|
||||
def grindForEd25519Key(self, coin_type, evkey, key_path_base):
|
||||
ci = self.ci(coin_type)
|
||||
nonce = 1
|
||||
while True:
|
||||
key_path = key_path_base + '/{}'.format(nonce)
|
||||
|
@ -986,7 +992,34 @@ class BasicSwap(BaseApp):
|
|||
return privkey
|
||||
nonce += 1
|
||||
if nonce > 1000:
|
||||
raise ValueError('getKeyForXMR failed')
|
||||
raise ValueError('grindForEd25519Key failed')
|
||||
|
||||
def getWalletKey(self, coin_type, key_num, for_ed25519=False):
|
||||
account = self.callcoinrpc(Coins.PART, 'extkey', ['account'])
|
||||
evkey = self.callcoinrpc(Coins.PART, 'extkey', ['account', 'default', 'true'])['evkey']
|
||||
|
||||
key_path_base = '44445555h/1h/{}/{}'.format(int(coin_type), key_num)
|
||||
|
||||
if not for_ed25519:
|
||||
extkey = self.callcoinrpc(Coins.PART, 'extkey', ['info', evkey, key_path_base])['key_info']['result']
|
||||
return decodeWif(self.callcoinrpc(Coins.PART, 'extkey', ['info', extkey])['key_info']['privkey'])
|
||||
|
||||
return self.grindForEd25519Key(coin_type, evkey, key_path_base)
|
||||
|
||||
def getPathKey(self, coin_from, coin_to, offer_created_at, contract_count, key_no, for_ed25519=False):
|
||||
account = self.callcoinrpc(Coins.PART, 'extkey', ['account'])
|
||||
evkey = self.callcoinrpc(Coins.PART, 'extkey', ['account', 'default', 'true'])['evkey']
|
||||
ci = self.ci(coin_to)
|
||||
|
||||
days = offer_created_at // 86400
|
||||
secs = offer_created_at - days * 86400
|
||||
key_path_base = '44445555h/999999/{}/{}/{}/{}/{}/{}'.format(int(coin_from), int(coin_to), days, secs, contract_count, key_no)
|
||||
|
||||
if not for_ed25519:
|
||||
extkey = self.callcoinrpc(Coins.PART, 'extkey', ['info', evkey, key_path_base])['key_info']['result']
|
||||
return decodeWif(self.callcoinrpc(Coins.PART, 'extkey', ['info', extkey])['key_info']['privkey'])
|
||||
|
||||
return self.grindForEd25519Key(coin_to, evkey, key_path_base)
|
||||
|
||||
def getContractPubkey(self, date, contract_count):
|
||||
account = self.callcoinrpc(Coins.PART, 'extkey', ['account'])
|
||||
|
@ -1550,8 +1583,8 @@ class BasicSwap(BaseApp):
|
|||
xmr_swap.contract_count = self.getNewContractId()
|
||||
xmr_swap.dest_af = msg_buf.dest_af
|
||||
xmr_swap.b_restore_height = self.ci(coin_to).getChainHeight()
|
||||
kbvf = self.getPathKey(coin_from, coin_to, bid_created_at, xmr_swap.contract_count, 1, for_xmr=True)
|
||||
kbsf = self.getPathKey(coin_from, coin_to, bid_created_at, xmr_swap.contract_count, 2, for_xmr=True)
|
||||
kbvf = self.getPathKey(coin_from, coin_to, bid_created_at, xmr_swap.contract_count, 1, for_ed25519=True)
|
||||
kbsf = self.getPathKey(coin_from, coin_to, bid_created_at, xmr_swap.contract_count, 2, for_ed25519=True)
|
||||
|
||||
kaf = self.getPathKey(coin_from, coin_to, bid_created_at, xmr_swap.contract_count, 3)
|
||||
karf = self.getPathKey(coin_from, coin_to, bid_created_at, xmr_swap.contract_count, 4)
|
||||
|
@ -1660,8 +1693,8 @@ class BasicSwap(BaseApp):
|
|||
|
||||
contract_secret = self.getPathKey(coin_from, coin_to, bid.created_at, xmr_swap.contract_count, 1)
|
||||
|
||||
kbvl = self.getPathKey(coin_from, coin_to, bid.created_at, xmr_swap.contract_count, 2, for_xmr=True)
|
||||
kbsl = self.getPathKey(coin_from, coin_to, bid.created_at, xmr_swap.contract_count, 3, for_xmr=True)
|
||||
kbvl = self.getPathKey(coin_from, coin_to, bid.created_at, xmr_swap.contract_count, 2, for_ed25519=True)
|
||||
kbsl = self.getPathKey(coin_from, coin_to, bid.created_at, xmr_swap.contract_count, 3, for_ed25519=True)
|
||||
|
||||
kal = self.getPathKey(coin_from, coin_to, bid.created_at, xmr_swap.contract_count, 4)
|
||||
karl = self.getPathKey(coin_from, coin_to, bid.created_at, xmr_swap.contract_count, 5)
|
||||
|
@ -3746,7 +3779,7 @@ class BasicSwap(BaseApp):
|
|||
ci_from = self.ci(coin_from)
|
||||
ci_to = self.ci(coin_to)
|
||||
|
||||
kbsf = self.getPathKey(coin_from, coin_to, bid.created_at, xmr_swap.contract_count, 2, for_xmr=True)
|
||||
kbsf = self.getPathKey(coin_from, coin_to, bid.created_at, xmr_swap.contract_count, 2, for_ed25519=True)
|
||||
kaf = self.getPathKey(coin_from, coin_to, bid.created_at, xmr_swap.contract_count, 3)
|
||||
|
||||
al_lock_spend_sig = ci_from.decryptOtVES(kbsf, xmr_swap.al_lock_spend_tx_esig)
|
||||
|
@ -3801,7 +3834,7 @@ class BasicSwap(BaseApp):
|
|||
kbsf = ci_from.recoverEncKey(xmr_swap.al_lock_spend_tx_esig, xmr_swap.al_lock_spend_tx_sig, xmr_swap.pkasf)
|
||||
assert(kbsf is not None)
|
||||
|
||||
kbsl = self.getPathKey(coin_from, coin_to, bid.created_at, xmr_swap.contract_count, 3, for_xmr=True)
|
||||
kbsl = self.getPathKey(coin_from, coin_to, bid.created_at, xmr_swap.contract_count, 3, for_ed25519=True)
|
||||
vkbs = ci_to.sumKeys(kbsl, kbsf)
|
||||
|
||||
address_to = ci_to.getMainWalletAddress()
|
||||
|
@ -3835,7 +3868,7 @@ class BasicSwap(BaseApp):
|
|||
kbsl = ci_from.recoverEncKey(xmr_swap.af_lock_refund_spend_tx_esig, af_lock_refund_spend_tx_sig, xmr_swap.pkasl)
|
||||
assert(kbsl is not None)
|
||||
|
||||
kbsf = self.getPathKey(coin_from, coin_to, bid.created_at, xmr_swap.contract_count, 2, for_xmr=True)
|
||||
kbsf = self.getPathKey(coin_from, coin_to, bid.created_at, xmr_swap.contract_count, 2, for_ed25519=True)
|
||||
vkbs = ci_to.sumKeys(kbsl, kbsf)
|
||||
|
||||
address_to = ci_to.getMainWalletAddress()
|
||||
|
@ -3874,7 +3907,7 @@ class BasicSwap(BaseApp):
|
|||
xmr_swap.af_lock_refund_spend_tx_esig = msg_data.af_lock_refund_spend_tx_esig
|
||||
xmr_swap.af_lock_refund_tx_sig = msg_data.af_lock_refund_tx_sig
|
||||
|
||||
kbsl = self.getPathKey(coin_from, coin_to, bid.created_at, xmr_swap.contract_count, 3, for_xmr=True)
|
||||
kbsl = self.getPathKey(coin_from, coin_to, bid.created_at, xmr_swap.contract_count, 3, for_ed25519=True)
|
||||
karl = self.getPathKey(coin_from, coin_to, bid.created_at, xmr_swap.contract_count, 5)
|
||||
|
||||
xmr_swap.af_lock_refund_spend_tx_sig = ci_from.decryptOtVES(kbsl, xmr_swap.af_lock_refund_spend_tx_esig)
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright (c) 2019 tecnovert
|
||||
# Copyright (c) 2019-2020 tecnovert
|
||||
# Distributed under the MIT software license, see the accompanying
|
||||
# file LICENSE or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
|
@ -70,6 +70,7 @@ chainparams = {
|
|||
'rpcport': 8332,
|
||||
'pubkey_address': 0,
|
||||
'script_address': 5,
|
||||
'key_prefix': 128,
|
||||
'hrp': 'bc',
|
||||
'bip44': 0,
|
||||
'min_amount': 1000,
|
||||
|
@ -79,6 +80,7 @@ chainparams = {
|
|||
'rpcport': 18332,
|
||||
'pubkey_address': 111,
|
||||
'script_address': 196,
|
||||
'key_prefix': 239,
|
||||
'hrp': 'tb',
|
||||
'bip44': 1,
|
||||
'min_amount': 1000,
|
||||
|
@ -89,6 +91,7 @@ chainparams = {
|
|||
'rpcport': 18443,
|
||||
'pubkey_address': 111,
|
||||
'script_address': 196,
|
||||
'key_prefix': 239,
|
||||
'hrp': 'bcrt',
|
||||
'bip44': 1,
|
||||
'min_amount': 1000,
|
||||
|
@ -105,6 +108,7 @@ chainparams = {
|
|||
'rpcport': 9332,
|
||||
'pubkey_address': 48,
|
||||
'script_address': 50,
|
||||
'key_prefix': 176,
|
||||
'hrp': 'ltc',
|
||||
'bip44': 2,
|
||||
'min_amount': 1000,
|
||||
|
@ -114,6 +118,7 @@ chainparams = {
|
|||
'rpcport': 19332,
|
||||
'pubkey_address': 111,
|
||||
'script_address': 58,
|
||||
'key_prefix': 239,
|
||||
'hrp': 'tltc',
|
||||
'bip44': 1,
|
||||
'min_amount': 1000,
|
||||
|
@ -124,6 +129,7 @@ chainparams = {
|
|||
'rpcport': 19443,
|
||||
'pubkey_address': 111,
|
||||
'script_address': 58,
|
||||
'key_prefix': 239,
|
||||
'hrp': 'rltc',
|
||||
'bip44': 1,
|
||||
'min_amount': 1000,
|
||||
|
|
|
@ -8,6 +8,7 @@ import os
|
|||
|
||||
CONFIG_FILENAME = 'basicswap.json'
|
||||
DEFAULT_DATADIR = '~/.basicswap'
|
||||
DEFAULT_ALLOW_CORS = False
|
||||
TEST_DATADIRS = os.path.expanduser(os.getenv('DATADIRS', '/tmp/basicswap'))
|
||||
|
||||
bin_suffix = ('.exe' if os.name == 'nt' else '')
|
||||
|
|
|
@ -17,6 +17,7 @@ from .util import (
|
|||
dumpj,
|
||||
format_amount,
|
||||
make_int,
|
||||
toWIF,
|
||||
decodeAddress)
|
||||
from coincurve.keys import (
|
||||
PublicKey)
|
||||
|
@ -131,6 +132,16 @@ class BTCInterface(CoinInterface):
|
|||
def getBlockchainInfo(self):
|
||||
return self.rpc_callback('getblockchaininfo')
|
||||
|
||||
def initialiseWallet(self, key_bytes):
|
||||
wif_prefix = chainparams[self.coin_type()][self._network]['key_prefix']
|
||||
key_wif = toWIF(wif_prefix, key_bytes)
|
||||
|
||||
try:
|
||||
self.rpc_callback('sethdseed', [True, key_wif])
|
||||
except Exception as e:
|
||||
# < 0.21: Cannot set a new HD seed while still in Initial Block Download.
|
||||
logging.error('sethdseed failed: {}'.format(str(e)))
|
||||
|
||||
def getWalletInfo(self):
|
||||
return self.rpc_callback('getwalletinfo')
|
||||
|
||||
|
|
|
@ -40,3 +40,6 @@ class PARTInterface(BTCInterface):
|
|||
version = self.getDaemonVersion()
|
||||
index_info = self.rpc_callback('getinsightinfo' if int(str(version)[:2]) > 19 else 'getindexinfo')
|
||||
return index_info['spentindex']
|
||||
|
||||
def initialiseWallet(self, key):
|
||||
raise ValueError('TODO')
|
||||
|
|
|
@ -65,11 +65,45 @@ class XMRInterface(CoinInterface):
|
|||
def setWalletFilename(self, wallet_filename):
|
||||
self._wallet_filename = wallet_filename
|
||||
|
||||
def initialiseWallet(self, key_view, key_spend, restore_height=None):
|
||||
try:
|
||||
self.rpc_wallet_cb('open_wallet', {'filename': self._wallet_filename})
|
||||
# TODO: Check address
|
||||
return # Wallet exists
|
||||
except Exception as e:
|
||||
pass
|
||||
|
||||
try:
|
||||
if restore_height is None:
|
||||
restore_height = self.getChainHeight()
|
||||
except Exception as e:
|
||||
logging.warning('Unable to get restore_height, set to zero. Error: {}'.format(str(e)))
|
||||
restore_height = 0
|
||||
|
||||
Kbv = self.getPubkey(key_view)
|
||||
Kbs = self.getPubkey(key_spend)
|
||||
address_b58 = xmr_util.encode_address(Kbv, Kbs)
|
||||
|
||||
params = {
|
||||
'filename': self._wallet_filename,
|
||||
'address': address_b58,
|
||||
'viewkey': b2h(key_view[::-1]),
|
||||
'spendkey': b2h(key_spend[::-1]),
|
||||
'restore_height': restore_height,
|
||||
}
|
||||
rv = self.rpc_wallet_cb('generate_from_keys', params)
|
||||
logging.info('generate_from_keys %s', dumpj(rv))
|
||||
self.rpc_wallet_cb('open_wallet', {'filename': self._wallet_filename})
|
||||
|
||||
def ensureWalletExists(self):
|
||||
self.rpc_wallet_cb('open_wallet', {'filename': self._wallet_filename})
|
||||
|
||||
def testDaemonRPC(self):
|
||||
self.rpc_wallet_cb('get_languages')
|
||||
|
||||
def getDaemonVersion(self):
|
||||
return self.rpc_cb('get_version')['version']
|
||||
return self.rpc_wallet_cb('get_version')['version']
|
||||
#return self.rpc_cb('get_version')['version']
|
||||
|
||||
def getBlockchainInfo(self):
|
||||
rv = {}
|
||||
|
|
|
@ -15,7 +15,7 @@ class Peer:
|
|||
|
||||
|
||||
class Network:
|
||||
def __init__(self, network_port, network_key):
|
||||
self._network_port = network_port
|
||||
def __init__(self, p2p_port, network_key):
|
||||
self._p2p_port = p2p_port
|
||||
self._network_key = network_key
|
||||
self._peers = []
|
||||
|
|
|
@ -16,6 +16,7 @@ import json
|
|||
import mmap
|
||||
import stat
|
||||
import gnupg
|
||||
import signal
|
||||
import hashlib
|
||||
import tarfile
|
||||
import zipfile
|
||||
|
@ -24,13 +25,15 @@ import platform
|
|||
import urllib.parse
|
||||
from urllib.request import urlretrieve
|
||||
|
||||
|
||||
import basicswap.config as cfg
|
||||
from basicswap.rpc import (
|
||||
callrpc_cli,
|
||||
waitForRPC,
|
||||
)
|
||||
from bin.basicswap_run import startDaemon
|
||||
from basicswap.basicswap import BasicSwap
|
||||
from basicswap.chainparams import Coins
|
||||
from bin.basicswap_run import startDaemon, startXmrWalletDaemon
|
||||
|
||||
|
||||
if platform.system() == 'Darwin':
|
||||
BIN_ARCH = 'osx64.tar.gz'
|
||||
|
@ -40,7 +43,7 @@ else:
|
|||
BIN_ARCH = 'x86_64-linux-gnu.tar.gz'
|
||||
|
||||
known_coins = {
|
||||
'particl': '0.19.1.1',
|
||||
'particl': '0.19.1.2',
|
||||
'litecoin': '0.18.1',
|
||||
'bitcoin': '0.20.1',
|
||||
'namecoin': '0.18.0',
|
||||
|
@ -52,6 +55,13 @@ logger.level = logging.DEBUG
|
|||
if not len(logger.handlers):
|
||||
logger.addHandler(logging.StreamHandler(sys.stdout))
|
||||
|
||||
XMR_RPC_HOST = os.getenv('XMR_RPC_HOST', 'localhost')
|
||||
BASE_XMR_RPC_PORT = os.getenv('BASE_XMR_RPC_PORT', 29798)
|
||||
BASE_XMR_ZMQ_PORT = os.getenv('BASE_XMR_ZMQ_PORT', 29898)
|
||||
BASE_XMR_WALLET_PORT = os.getenv('BASE_XMR_WALLET_PORT', 29998)
|
||||
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')
|
||||
|
||||
|
||||
def make_reporthook():
|
||||
read = 0 # Number of bytes read so far
|
||||
|
@ -95,8 +105,6 @@ def extractCore(coin, version, settings, bin_dir, release_path):
|
|||
fout.write(fi.read())
|
||||
fi.close()
|
||||
os.chmod(out_path, stat.S_IRWXU | stat.S_IXGRP | stat.S_IXOTH)
|
||||
|
||||
print('member', member)
|
||||
return
|
||||
|
||||
bins = [coin + 'd', coin + '-cli', coin + '-tx']
|
||||
|
@ -257,10 +265,40 @@ def prepareDataDir(coin, settings, data_dir, chain, particl_mnemonic):
|
|||
if not os.path.exists(data_dir):
|
||||
os.makedirs(data_dir)
|
||||
|
||||
if coin == 'monero':
|
||||
core_conf_path = os.path.join(data_dir, coin + 'd.conf')
|
||||
if os.path.exists(core_conf_path):
|
||||
exitWithError('{} exists'.format(core_conf_path))
|
||||
with open(core_conf_path, 'w') as fp:
|
||||
if chain == 'regtest':
|
||||
fp.write('regtest=1\n')
|
||||
fp.write('keep-fakechain=1\n')
|
||||
fp.write('fixed-difficulty=1\n')
|
||||
elif 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('zmq-rpc-bind-port={}\n'.format(core_settings['zmqport']))
|
||||
#fp.write('zmq-rpc-bind-ip=127.0.0.1\n')
|
||||
wallet_conf_path = os.path.join(data_dir, coin + '_wallet.conf')
|
||||
if os.path.exists(wallet_conf_path):
|
||||
exitWithError('{} exists'.format(wallet_conf_path))
|
||||
with open(wallet_conf_path, 'w') as fp:
|
||||
fp.write('daemon-address={}:{}\n'.format(core_settings['rpchost'], core_settings['rpcport']))
|
||||
fp.write('no-dns=1\n')
|
||||
fp.write('rpc-bind-port={}\n'.format(core_settings['walletrpcport']))
|
||||
fp.write('wallet-dir={}\n'.format(os.path.join(data_dir, 'wallets')))
|
||||
fp.write('log-file={}\n'.format(os.path.join(data_dir, 'wallet.log')))
|
||||
fp.write('shared-ringdb-dir={}\n'.format(os.path.join(data_dir, 'shared-ringdb')))
|
||||
fp.write('rpc-login={}:{}\n'.format(core_settings['walletrpcuser'], core_settings['walletrpcpassword']))
|
||||
return
|
||||
core_conf_path = os.path.join(data_dir, coin + '.conf')
|
||||
if os.path.exists(core_conf_path):
|
||||
exitWithError('{} exists'.format(core_conf_path))
|
||||
|
||||
with open(core_conf_path, 'w') as fp:
|
||||
if chain != 'mainnet':
|
||||
fp.write(chain + '=1\n')
|
||||
|
@ -490,11 +528,14 @@ def main():
|
|||
'monero': {
|
||||
'connection_type': 'rpc' if 'monero' in with_coins else 'none',
|
||||
'manage_daemon': True if 'monero' in with_coins else False,
|
||||
'rpcport': 29798 + port_offset,
|
||||
'walletrpcport': 29799 + port_offset,
|
||||
#'walletrpcuser': 'test' + str(node_id),
|
||||
#'walletrpcpassword': 'test_pass' + str(node_id),
|
||||
'walletfile': 'basicswap',
|
||||
'manage_wallet_daemon': True if 'monero' in with_coins else False,
|
||||
'rpcport': BASE_XMR_RPC_PORT + port_offset,
|
||||
'zmqport': BASE_XMR_ZMQ_PORT + port_offset,
|
||||
'walletrpcport': BASE_XMR_WALLET_PORT + port_offset,
|
||||
'rpchost': XMR_RPC_HOST,
|
||||
'walletrpcuser': XMR_WALLET_RPC_USER,
|
||||
'walletrpcpassword': XMR_WALLET_RPC_PWD,
|
||||
'walletfile': 'swap_wallet',
|
||||
'datadir': os.path.join(data_dir, 'monero'),
|
||||
'bindir': os.path.join(bin_dir, 'monero'),
|
||||
}
|
||||
|
@ -597,26 +638,57 @@ def main():
|
|||
|
||||
particl_settings = settings['chainclients']['particl']
|
||||
partRpc = make_rpc_func(particl_settings['bindir'], particl_settings['datadir'], chain)
|
||||
d = startDaemon(particl_settings['datadir'], particl_settings['bindir'], cfg.PARTICLD, ['-noconnect', '-nofindpeers', '-nostaking', '-nodnsseed', '-nolisten'])
|
||||
|
||||
daemons = []
|
||||
daemons.append(startDaemon(particl_settings['datadir'], particl_settings['bindir'], cfg.PARTICLD, ['-noconnect', '-nofindpeers', '-nostaking', '-nodnsseed', '-nolisten']))
|
||||
try:
|
||||
waitForRPC(partRpc)
|
||||
|
||||
if particl_wallet_mnemonic is None:
|
||||
particl_wallet_mnemonic = partRpc('mnemonic new')['mnemonic']
|
||||
partRpc('extkeyimportmaster "{}"'.format(particl_wallet_mnemonic))
|
||||
|
||||
# Initialise wallets
|
||||
with open(os.path.join(data_dir, 'basicswap.log'), 'a') as fp:
|
||||
swap_client = BasicSwap(fp, data_dir, settings, chain)
|
||||
|
||||
swap_client.setCoinConnectParams(Coins.PART)
|
||||
swap_client.setDaemonPID(Coins.PART, daemons[-1].pid)
|
||||
swap_client.setCoinRunParams(Coins.PART)
|
||||
swap_client.createCoinInterface(Coins.PART)
|
||||
|
||||
for coin_name in with_coins:
|
||||
coin_settings = settings['chainclients'][coin_name]
|
||||
c = swap_client.getCoinIdFromName(coin_name)
|
||||
if c == Coins.PART:
|
||||
continue
|
||||
|
||||
swap_client.setCoinConnectParams(c)
|
||||
|
||||
if c == Coins.XMR:
|
||||
if not coin_settings['manage_wallet_daemon']:
|
||||
continue
|
||||
daemons.append(startXmrWalletDaemon(coin_settings['datadir'], coin_settings['bindir'], 'monero-wallet-rpc'))
|
||||
else:
|
||||
if not coin_settings['manage_daemon']:
|
||||
continue
|
||||
filename = coin_name + 'd' + ('.exe' if os.name == 'nt' else '')
|
||||
daemons.append(startDaemon(coin_settings['datadir'], coin_settings['bindir'], filename, ['-noconnect', '-nodnsseed', '-nolisten']))
|
||||
swap_client.setDaemonPID(c, daemons[-1].pid)
|
||||
swap_client.setCoinRunParams(c)
|
||||
swap_client.createCoinInterface(c)
|
||||
swap_client.waitForDaemonRPC(c)
|
||||
swap_client.initialiseWallet(c)
|
||||
finally:
|
||||
logger.info('Terminating {}'.format(d.pid))
|
||||
d.terminate()
|
||||
for d in daemons:
|
||||
logging.info('Interrupting {}'.format(d.pid))
|
||||
d.send_signal(signal.SIGINT)
|
||||
d.wait(timeout=120)
|
||||
if d.stdout:
|
||||
d.stdout.close()
|
||||
if d.stderr:
|
||||
d.stderr.close()
|
||||
if d.stdin:
|
||||
d.stdin.close()
|
||||
for fp in (d.stdout, d.stderr, d.stdin):
|
||||
if fp:
|
||||
fp.close()
|
||||
|
||||
logger.info('IMPORTANT - Save your particl wallet recovery phrase:\n{}\n'.format(particl_wallet_mnemonic))
|
||||
|
||||
logger.info('Done.')
|
||||
|
||||
|
||||
|
|
|
@ -19,7 +19,6 @@ import logging
|
|||
import traceback
|
||||
import subprocess
|
||||
|
||||
|
||||
import basicswap.config as cfg
|
||||
from basicswap import __version__
|
||||
from basicswap.basicswap import BasicSwap
|
||||
|
@ -31,7 +30,6 @@ logger.level = logging.DEBUG
|
|||
if not len(logger.handlers):
|
||||
logger.addHandler(logging.StreamHandler(sys.stdout))
|
||||
|
||||
ALLOW_CORS = False
|
||||
swap_client = None
|
||||
|
||||
|
||||
|
@ -50,6 +48,29 @@ def startDaemon(node_dir, bin_dir, daemon_bin, opts=[]):
|
|||
return subprocess.Popen(args, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||
|
||||
|
||||
def startXmrDaemon(node_dir, bin_dir, daemon_bin, opts=[]):
|
||||
daemon_bin = os.path.expanduser(os.path.join(bin_dir, daemon_bin))
|
||||
|
||||
args = [daemon_bin, '--config-file=' + os.path.join(os.path.expanduser(node_dir), 'monerod.conf')] + opts
|
||||
logging.info('Starting node {} --data-dir={}'.format(daemon_bin, node_dir))
|
||||
|
||||
return subprocess.Popen(args, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||
|
||||
|
||||
def startXmrWalletDaemon(node_dir, bin_dir, wallet_bin, opts=[]):
|
||||
daemon_bin = os.path.expanduser(os.path.join(bin_dir, wallet_bin))
|
||||
|
||||
data_dir = os.path.expanduser(node_dir)
|
||||
args = [daemon_bin, '--config-file=' + os.path.join(os.path.expanduser(node_dir), 'monero_wallet.conf')] + opts
|
||||
|
||||
args += opts
|
||||
logging.info('Starting wallet daemon {} --wallet-dir={}'.format(daemon_bin, node_dir))
|
||||
|
||||
#return subprocess.Popen(args, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, cwd=data_dir)
|
||||
wallet_stdout = open(os.path.join(data_dir, 'wallet_stdout.log'), 'w')
|
||||
wallet_stderr = open(os.path.join(data_dir, 'wallet_stderr.log'), 'w')
|
||||
return subprocess.Popen(args, stdin=subprocess.PIPE, stdout=wallet_stdout, stderr=wallet_stderr, cwd=data_dir)
|
||||
|
||||
def runClient(fp, data_dir, chain):
|
||||
global swap_client
|
||||
settings_path = os.path.join(data_dir, cfg.CONFIG_FILENAME)
|
||||
|
@ -79,6 +100,20 @@ def runClient(fp, data_dir, chain):
|
|||
try:
|
||||
# Try start daemons
|
||||
for c, v in settings['chainclients'].items():
|
||||
if c == 'monero':
|
||||
if v['manage_daemon'] is True:
|
||||
logger.info('Starting {} daemon'.format(c.capitalize()))
|
||||
daemons.append(startXmrDaemon(v['datadir'], v['bindir'], 'monerod'))
|
||||
pid = daemons[-1].pid
|
||||
logger.info('Started {} {}'.format('monerod', pid))
|
||||
|
||||
if v['manage_wallet_daemon'] is True:
|
||||
logger.info('Starting {} wallet daemon'.format(c.capitalize()))
|
||||
daemons.append(startXmrWalletDaemon(v['datadir'], v['bindir'], 'monero-wallet-rpc'))
|
||||
pid = daemons[-1].pid
|
||||
logger.info('Started {} {}'.format('monero-wallet-rpc', pid))
|
||||
|
||||
continue
|
||||
if v['manage_daemon'] is True:
|
||||
logger.info('Starting {} daemon'.format(c.capitalize()))
|
||||
|
||||
|
@ -99,7 +134,7 @@ def runClient(fp, data_dir, chain):
|
|||
|
||||
if 'htmlhost' in settings:
|
||||
swap_client.log.info('Starting server at %s:%d.' % (settings['htmlhost'], settings['htmlport']))
|
||||
allow_cors = settings['allowcors'] if 'allowcors' in settings else ALLOW_CORS
|
||||
allow_cors = settings['allowcors'] if 'allowcors' in settings else cfg.DEFAULT_ALLOW_CORS
|
||||
tS1 = HttpThread(fp, settings['htmlhost'], settings['htmlport'], allow_cors, swap_client)
|
||||
threads.append(tS1)
|
||||
tS1.start()
|
||||
|
@ -118,8 +153,7 @@ def runClient(fp, data_dir, chain):
|
|||
|
||||
closed_pids = []
|
||||
for d in daemons:
|
||||
int_pid = d.pid
|
||||
logging.info('Interrupting {}'.format(int_pid))
|
||||
logging.info('Interrupting {}'.format(d.pid))
|
||||
try:
|
||||
d.send_signal(signal.SIGINT)
|
||||
except Exception as e:
|
||||
|
@ -127,13 +161,10 @@ def runClient(fp, data_dir, chain):
|
|||
for d in daemons:
|
||||
try:
|
||||
d.wait(timeout=120)
|
||||
if d.stdout:
|
||||
d.stdout.close()
|
||||
if d.stderr:
|
||||
d.stderr.close()
|
||||
if d.stdin:
|
||||
d.stdin.close()
|
||||
closed_pids.append(int_pid)
|
||||
for fp in (d.stdout, d.stderr, d.stdin):
|
||||
if fp:
|
||||
fp.close()
|
||||
closed_pids.append(d.pid)
|
||||
except Exception as ex:
|
||||
logger.error('Error: {}'.format(ex))
|
||||
|
||||
|
|
|
@ -5,8 +5,8 @@
|
|||
# Distributed under the MIT software license, see the accompanying
|
||||
# file LICENSE or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
import unittest
|
||||
import secrets
|
||||
import unittest
|
||||
|
||||
import basicswap.contrib.ed25519_fast as edf
|
||||
import basicswap.ed25519_fast_util as edu
|
||||
|
|
|
@ -7,12 +7,13 @@
|
|||
|
||||
import os
|
||||
import sys
|
||||
import unittest
|
||||
from unittest.mock import patch
|
||||
from io import StringIO
|
||||
import logging
|
||||
import shutil
|
||||
import json
|
||||
import shutil
|
||||
import logging
|
||||
import unittest
|
||||
|
||||
from io import StringIO
|
||||
from unittest.mock import patch
|
||||
|
||||
import basicswap.config as cfg
|
||||
import bin.basicswap_prepare as prepareSystem
|
||||
|
|
|
@ -18,17 +18,17 @@ python tests/basicswap/test_reload.py
|
|||
|
||||
import os
|
||||
import sys
|
||||
import time
|
||||
import unittest
|
||||
import logging
|
||||
import shutil
|
||||
import json
|
||||
import time
|
||||
import shutil
|
||||
import logging
|
||||
import unittest
|
||||
import traceback
|
||||
import multiprocessing
|
||||
import threading
|
||||
from unittest.mock import patch
|
||||
from urllib.request import urlopen
|
||||
import multiprocessing
|
||||
from urllib import parse
|
||||
from urllib.request import urlopen
|
||||
from unittest.mock import patch
|
||||
|
||||
from basicswap.rpc import (
|
||||
callrpc_cli,
|
||||
|
|
264
tests/basicswap/test_reload_xmr.py
Normal file
264
tests/basicswap/test_reload_xmr.py
Normal file
|
@ -0,0 +1,264 @@
|
|||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright (c) 2020 tecnovert
|
||||
# Distributed under the MIT software license, see the accompanying
|
||||
# file LICENSE or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
"""
|
||||
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.5-x86_64-linux-gnu.tar.gz ${TEST_RELOAD_PATH}/bin/monero
|
||||
export PYTHONPATH=$(pwd)
|
||||
python tests/basicswap/test_reload_xmr.py
|
||||
|
||||
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
import json
|
||||
import time
|
||||
import shutil
|
||||
import logging
|
||||
import unittest
|
||||
import traceback
|
||||
import threading
|
||||
import multiprocessing
|
||||
from urllib import parse
|
||||
from urllib.request import urlopen
|
||||
from unittest.mock import patch
|
||||
|
||||
|
||||
from basicswap.rpc import (
|
||||
callrpc_cli,
|
||||
)
|
||||
from basicswap.util import (
|
||||
dumpj
|
||||
)
|
||||
from tests.basicswap.mnemonics import mnemonics
|
||||
|
||||
import basicswap.config as cfg
|
||||
import bin.basicswap_prepare as prepareSystem
|
||||
import bin.basicswap_run as runSystem
|
||||
|
||||
test_path = os.path.expanduser(os.getenv('TEST_RELOAD_PATH', '~/test_basicswap1'))
|
||||
PARTICL_PORT_BASE = int(os.getenv('PARTICL_PORT_BASE', '11938'))
|
||||
|
||||
XMR_BASE_P2P_PORT = 17792
|
||||
XMR_BASE_RPC_PORT = 21792
|
||||
XMR_BASE_ZMQ_PORT = 22792
|
||||
XMR_BASE_WALLET_RPC_PORT = 23792
|
||||
|
||||
stop_test = False
|
||||
|
||||
logger = logging.getLogger()
|
||||
logger.level = logging.DEBUG
|
||||
if not len(logger.handlers):
|
||||
logger.addHandler(logging.StreamHandler(sys.stdout))
|
||||
|
||||
|
||||
def waitForServer(port):
|
||||
for i in range(20):
|
||||
try:
|
||||
time.sleep(1)
|
||||
summary = json.loads(urlopen('http://localhost:{}/json'.format(port)).read())
|
||||
break
|
||||
except Exception:
|
||||
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')
|
||||
|
||||
|
||||
def updateThread(xmr_addr):
|
||||
#btc_addr = btcRpc(0, 'getnewaddress mining_addr bech32')
|
||||
|
||||
while not stop_test:
|
||||
#btcRpc(0, 'generatetoaddress {} {}'.format(1, btc_addr))
|
||||
time.sleep(5)
|
||||
|
||||
|
||||
class Test(unittest.TestCase):
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
super(Test, cls).setUpClass()
|
||||
|
||||
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)
|
||||
try:
|
||||
shutil.rmtree(client_path)
|
||||
except Exception as ex:
|
||||
logger.warning('setUpClass %s', str(ex))
|
||||
testargs = [
|
||||
'basicswap-prepare',
|
||||
'-datadir="{}"'.format(client_path),
|
||||
'-bindir="{}"'.format(os.path.join(test_path, 'bin')),
|
||||
'-portoffset={}'.format(i),
|
||||
'-particl_mnemonic="{}"'.format(mnemonics[i]),
|
||||
'-regtest', '-withoutcoin=litecoin', '-withcoin=monero']
|
||||
with patch.object(sys, 'argv', testargs):
|
||||
prepareSystem.main()
|
||||
|
||||
with open(os.path.join(client_path, 'particl', 'particl.conf'), 'r') as fp:
|
||||
lines = fp.readlines()
|
||||
with open(os.path.join(client_path, 'particl', 'particl.conf'), 'w') as fp:
|
||||
for line in lines:
|
||||
if not line.startswith('staking'):
|
||||
fp.write(line)
|
||||
fp.write('port={}\n'.format(PARTICL_PORT_BASE + i))
|
||||
fp.write('bind=127.0.0.1\n')
|
||||
fp.write('dnsseed=0\n')
|
||||
fp.write('minstakeinterval=5\n')
|
||||
for ip in range(3):
|
||||
if ip != i:
|
||||
fp.write('connect=localhost:{}\n'.format(PARTICL_PORT_BASE + ip))
|
||||
|
||||
with open(os.path.join(client_path, 'monero', 'monerod.conf'), 'a') as fp:
|
||||
fp.write('p2p-bind-ip=127.0.0.1\n')
|
||||
fp.write('p2p-bind-port={}\n'.format(XMR_BASE_P2P_PORT + i))
|
||||
for ip in range(3):
|
||||
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))
|
||||
|
||||
def run_thread(self, client_id):
|
||||
client_path = os.path.join(test_path, 'client{}'.format(client_id))
|
||||
testargs = ['basicswap-run', '-datadir=' + client_path, '-regtest']
|
||||
with patch.object(sys, 'argv', testargs):
|
||||
runSystem.main()
|
||||
|
||||
def test_reload(self):
|
||||
global stop_test
|
||||
update_thread = None
|
||||
processes = []
|
||||
|
||||
for i in range(3):
|
||||
processes.append(multiprocessing.Process(target=self.run_thread, args=(i,)))
|
||||
processes[-1].start()
|
||||
|
||||
try:
|
||||
waitForServer(12700)
|
||||
|
||||
wallets = json.loads(urlopen('http://localhost:12701/json/wallets').read())
|
||||
print('[rm] wallets', dumpj(wallets))
|
||||
|
||||
xmr_addr1 = wallets['6']['deposit_address']
|
||||
num_blocks = 500
|
||||
|
||||
raise ValueError('TODO')
|
||||
'''
|
||||
|
||||
btc_addr = btcRpc(1, 'getnewaddress mining_addr bech32')
|
||||
logging.info('Mining %d Bitcoin blocks to %s', num_blocks, btc_addr)
|
||||
btcRpc(1, 'generatetoaddress {} {}'.format(num_blocks, btc_addr))
|
||||
|
||||
for i in range(20):
|
||||
blocks = btcRpc(0, 'getblockchaininfo')['blocks']
|
||||
if blocks >= 500:
|
||||
break
|
||||
assert(blocks >= 500)
|
||||
'''
|
||||
|
||||
data = parse.urlencode({
|
||||
'addr_from': '-1',
|
||||
'coin_from': '1',
|
||||
'coin_to': '6',
|
||||
'amt_from': '1',
|
||||
'amt_to': '1',
|
||||
'lockhrs': '24'}).encode()
|
||||
|
||||
offer_id = json.loads(urlopen('http://localhost:12700/json/offers/new', data=data).read())
|
||||
summary = json.loads(urlopen('http://localhost:12700/json').read())
|
||||
assert(summary['num_sent_offers'] == 1)
|
||||
|
||||
|
||||
logger.info('Waiting for offer:')
|
||||
waitForNumOffers(12701, 1)
|
||||
|
||||
offers = json.loads(urlopen('http://localhost:12701/json/offers').read())
|
||||
offer = offers[0]
|
||||
|
||||
data = parse.urlencode({
|
||||
'offer_id': offer['offer_id'],
|
||||
'amount_from': offer['amount_from']}).encode()
|
||||
|
||||
bid_id = json.loads(urlopen('http://localhost:12701/json/bids/new', data=data).read())
|
||||
|
||||
waitForNumBids(12700, 1)
|
||||
|
||||
bids = json.loads(urlopen('http://localhost:12700/json/bids').read())
|
||||
bid = bids[0]
|
||||
|
||||
data = parse.urlencode({
|
||||
'accept': True
|
||||
}).encode()
|
||||
rv = json.loads(urlopen('http://localhost:12700/json/bids/{}'.format(bid['bid_id']), data=data).read())
|
||||
assert(rv['bid_state'] == 'Accepted')
|
||||
|
||||
waitForNumSwapping(12701, 1)
|
||||
|
||||
logger.info('Restarting client:')
|
||||
c1 = processes[1]
|
||||
c1.terminate()
|
||||
c1.join()
|
||||
processes[1] = multiprocessing.Process(target=self.run_thread, args=(1,))
|
||||
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_addr,))
|
||||
update_thread.start()
|
||||
|
||||
logger.info('Completing swap:')
|
||||
for i in range(240):
|
||||
time.sleep(5)
|
||||
|
||||
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:
|
||||
traceback.print_exc()
|
||||
|
||||
stop_test = True
|
||||
if update_thread:
|
||||
update_thread.join()
|
||||
for p in processes:
|
||||
p.terminate()
|
||||
for p in processes:
|
||||
p.join()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
202
tests/basicswap/test_wallet_init.py
Normal file
202
tests/basicswap/test_wallet_init.py
Normal file
|
@ -0,0 +1,202 @@
|
|||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright (c) 2020 tecnovert
|
||||
# Distributed under the MIT software license, see the accompanying
|
||||
# file LICENSE or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
"""
|
||||
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.5-x86_64-linux-gnu.tar.gz ${TEST_PATH}/bin/monero
|
||||
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
|
||||
|
||||
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
import json
|
||||
import time
|
||||
import shutil
|
||||
import logging
|
||||
import unittest
|
||||
import traceback
|
||||
import threading
|
||||
import multiprocessing
|
||||
from urllib import parse
|
||||
from urllib.request import urlopen
|
||||
from unittest.mock import patch
|
||||
|
||||
|
||||
from basicswap.rpc import (
|
||||
callrpc_cli,
|
||||
)
|
||||
from basicswap.util import (
|
||||
dumpj
|
||||
)
|
||||
from tests.basicswap.mnemonics import mnemonics
|
||||
|
||||
import basicswap.config as cfg
|
||||
import bin.basicswap_prepare as prepareSystem
|
||||
import bin.basicswap_run as runSystem
|
||||
|
||||
test_path = os.path.expanduser(os.getenv('TEST_PATH', '~/test_basicswap1'))
|
||||
PARTICL_PORT_BASE = int(os.getenv('PARTICL_PORT_BASE', '11938'))
|
||||
BITCOIN_PORT_BASE = int(os.getenv('BITCOIN_PORT_BASE', '10938'))
|
||||
XMR_BASE_P2P_PORT = 17792
|
||||
XMR_BASE_RPC_PORT = 21792
|
||||
XMR_BASE_ZMQ_PORT = 22792
|
||||
XMR_BASE_WALLET_RPC_PORT = 23792
|
||||
|
||||
stop_test = False
|
||||
|
||||
logger = logging.getLogger()
|
||||
logger.level = logging.DEBUG
|
||||
if not len(logger.handlers):
|
||||
logger.addHandler(logging.StreamHandler(sys.stdout))
|
||||
|
||||
|
||||
def waitForServer(port):
|
||||
for i in range(20):
|
||||
try:
|
||||
time.sleep(1)
|
||||
summary = json.loads(urlopen('http://localhost:{}/json'.format(port)).read())
|
||||
break
|
||||
except Exception:
|
||||
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):
|
||||
super(Test, cls).setUpClass()
|
||||
|
||||
for i in range(2):
|
||||
client_path = os.path.join(test_path, 'client{}'.format(i))
|
||||
config_path = os.path.join(client_path, cfg.CONFIG_FILENAME)
|
||||
try:
|
||||
shutil.rmtree(client_path)
|
||||
except Exception as ex:
|
||||
logger.warning('setUpClass %s', str(ex))
|
||||
testargs = [
|
||||
'basicswap-prepare',
|
||||
'-datadir="{}"'.format(client_path),
|
||||
'-bindir="{}"'.format(os.path.join(test_path, 'bin')),
|
||||
'-portoffset={}'.format(i),
|
||||
'-particl_mnemonic="{}"'.format(mnemonics[0]),
|
||||
'-regtest', '-withoutcoin=litecoin', '-withcoin=monero,bitcoin']
|
||||
with patch.object(sys, 'argv', testargs):
|
||||
prepareSystem.main()
|
||||
|
||||
with open(os.path.join(client_path, 'particl', 'particl.conf'), 'r') as fp:
|
||||
lines = fp.readlines()
|
||||
with open(os.path.join(client_path, 'particl', 'particl.conf'), 'w') as fp:
|
||||
for line in lines:
|
||||
if not line.startswith('staking'):
|
||||
fp.write(line)
|
||||
fp.write('port={}\n'.format(PARTICL_PORT_BASE + i))
|
||||
fp.write('bind=127.0.0.1\n')
|
||||
fp.write('dnsseed=0\n')
|
||||
fp.write('minstakeinterval=5\n')
|
||||
for ip in range(3):
|
||||
if ip != i:
|
||||
fp.write('connect=localhost:{}\n'.format(PARTICL_PORT_BASE + ip))
|
||||
|
||||
# Pruned nodes don't provide blocks
|
||||
with open(os.path.join(client_path, 'bitcoin', 'bitcoin.conf'), 'r') as fp:
|
||||
lines = fp.readlines()
|
||||
with open(os.path.join(client_path, 'bitcoin', 'bitcoin.conf'), 'w') as fp:
|
||||
for line in lines:
|
||||
if not line.startswith('prune'):
|
||||
fp.write(line)
|
||||
fp.write('port={}\n'.format(BITCOIN_PORT_BASE + i))
|
||||
fp.write('discover=0\n')
|
||||
fp.write('dnsseed=0\n')
|
||||
fp.write('listenonion=0\n')
|
||||
fp.write('upnp=0\n')
|
||||
fp.write('bind=127.0.0.1\n')
|
||||
for ip in range(3):
|
||||
if ip != i:
|
||||
fp.write('connect=localhost:{}\n'.format(BITCOIN_PORT_BASE + ip))
|
||||
|
||||
with open(os.path.join(client_path, 'monero', 'monerod.conf'), 'a') as fp:
|
||||
fp.write('p2p-bind-ip=127.0.0.1\n')
|
||||
fp.write('p2p-bind-port={}\n'.format(XMR_BASE_P2P_PORT + i))
|
||||
for ip in range(3):
|
||||
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))
|
||||
|
||||
def run_thread(self, client_id):
|
||||
client_path = os.path.join(test_path, 'client{}'.format(client_id))
|
||||
testargs = ['basicswap-run', '-datadir=' + client_path, '-regtest']
|
||||
with patch.object(sys, 'argv', testargs):
|
||||
runSystem.main()
|
||||
|
||||
def test_wallet(self):
|
||||
global stop_test
|
||||
update_thread = None
|
||||
processes = []
|
||||
|
||||
time.sleep(5)
|
||||
for i in range(2):
|
||||
processes.append(multiprocessing.Process(target=self.run_thread, args=(i,)))
|
||||
processes[-1].start()
|
||||
|
||||
try:
|
||||
waitForServer(12700)
|
||||
|
||||
wallets = json.loads(urlopen('http://localhost:12700/json/wallets').read())
|
||||
print('[rm] wallets', dumpj(wallets))
|
||||
|
||||
waitForServer(12701)
|
||||
wallets = json.loads(urlopen('http://localhost:12701/json/wallets').read())
|
||||
print('[rm] wallets', dumpj(wallets))
|
||||
|
||||
raise ValueError('TODO')
|
||||
except Exception:
|
||||
traceback.print_exc()
|
||||
|
||||
stop_test = True
|
||||
if update_thread:
|
||||
update_thread.join()
|
||||
for p in processes:
|
||||
p.terminate()
|
||||
for p in processes:
|
||||
p.join()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
|
@ -55,7 +55,7 @@ from tests.basicswap.common import (
|
|||
TEST_HTTP_PORT,
|
||||
)
|
||||
from basicswap.contrib.rpcauth import generate_salt, password_to_hmac
|
||||
from bin.basicswap_run import startDaemon
|
||||
from bin.basicswap_run import startDaemon, startXmrDaemon
|
||||
|
||||
|
||||
logger = logging.getLogger()
|
||||
|
@ -479,12 +479,9 @@ class Test(unittest.TestCase):
|
|||
for d in cls.xmr_daemons:
|
||||
try:
|
||||
d.wait(timeout=20)
|
||||
if d.stdout:
|
||||
d.stdout.close()
|
||||
if d.stderr:
|
||||
d.stderr.close()
|
||||
if d.stdin:
|
||||
d.stdin.close()
|
||||
for fp in (d.stdout, d.stderr, d.stdin):
|
||||
if fp:
|
||||
fp.close()
|
||||
except Exception as e:
|
||||
logging.info('Closing %d, error %s', d.pid, str(e))
|
||||
|
||||
|
@ -497,12 +494,9 @@ class Test(unittest.TestCase):
|
|||
for d in cls.part_daemons + cls.btc_daemons:
|
||||
try:
|
||||
d.wait(timeout=20)
|
||||
if d.stdout:
|
||||
d.stdout.close()
|
||||
if d.stderr:
|
||||
d.stderr.close()
|
||||
if d.stdin:
|
||||
d.stdin.close()
|
||||
for fp in (d.stdout, d.stderr, d.stdin):
|
||||
if fp:
|
||||
fp.close()
|
||||
except Exception as e:
|
||||
logging.info('Closing %d, error %s', d.pid, str(e))
|
||||
|
||||
|
|
Loading…
Reference in a new issue