mirror of
https://github.com/basicswap/basicswap.git
synced 2025-01-03 17:29:26 +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:
|
test_task:
|
||||||
environment:
|
environment:
|
||||||
- PART_VERSION: 0.19.1.1
|
- PART_VERSION: 0.19.1.2
|
||||||
- BTC_VERSION: 0.20.1
|
- BTC_VERSION: 0.20.1
|
||||||
- LTC_VERSION: 0.18.1
|
- LTC_VERSION: 0.18.1
|
||||||
- TEST_RELOAD_PATH: $HOME/test_basicswap1/
|
- TEST_RELOAD_PATH: $HOME/test_basicswap1/
|
||||||
|
|
|
@ -7,7 +7,7 @@ stages:
|
||||||
- test
|
- test
|
||||||
env:
|
env:
|
||||||
global:
|
global:
|
||||||
- PART_VERSION=0.19.1.1
|
- PART_VERSION=0.19.1.2
|
||||||
- BTC_VERSION=0.20.1
|
- BTC_VERSION=0.20.1
|
||||||
- LTC_VERSION=0.18.1
|
- LTC_VERSION=0.18.1
|
||||||
- TEST_DIR=~/test_basicswap2/
|
- TEST_DIR=~/test_basicswap2/
|
||||||
|
|
|
@ -49,6 +49,9 @@ class BaseApp:
|
||||||
self.log = logging.getLogger(self.log_name)
|
self.log = logging.getLogger(self.log_name)
|
||||||
self.log.propagate = False
|
self.log.propagate = False
|
||||||
|
|
||||||
|
# Remove any existing handlers
|
||||||
|
self.log.handlers = []
|
||||||
|
|
||||||
formatter = logging.Formatter('%(asctime)s %(levelname)s : %(message)s')
|
formatter = logging.Formatter('%(asctime)s %(levelname)s : %(message)s')
|
||||||
stream_stdout = logging.StreamHandler()
|
stream_stdout = logging.StreamHandler()
|
||||||
if self.log_name != 'BasicSwap':
|
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)
|
testnet_name = '' if self.chain == 'mainnet' else chainparams[coin][self.chain].get('name', self.chain)
|
||||||
return os.path.join(datadir, testnet_name)
|
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):
|
def getTicker(self, coin_type):
|
||||||
ticker = chainparams[coin_type]['ticker']
|
ticker = chainparams[coin_type]['ticker']
|
||||||
if self.chain == 'testnet':
|
if self.chain == 'testnet':
|
||||||
|
|
|
@ -551,7 +551,6 @@ class BasicSwap(BaseApp):
|
||||||
self.coin_clients[coin]['walletrpcauth'] = (chain_client_settings['walletrpcuser'], chain_client_settings['walletrpcpassword'])
|
self.coin_clients[coin]['walletrpcauth'] = (chain_client_settings['walletrpcuser'], chain_client_settings['walletrpcpassword'])
|
||||||
else:
|
else:
|
||||||
raise ValueError('Missing XMR wallet rpc credentials.')
|
raise ValueError('Missing XMR wallet rpc credentials.')
|
||||||
self.coin_clients[coin]['interface'] = self.createInterface(coin)
|
|
||||||
|
|
||||||
def ci(self, coin): # coin interface
|
def ci(self, coin): # coin interface
|
||||||
return self.coin_clients[coin]['interface']
|
return self.coin_clients[coin]['interface']
|
||||||
|
@ -593,17 +592,17 @@ class BasicSwap(BaseApp):
|
||||||
try:
|
try:
|
||||||
with open(pidfilepath, 'rb') as fp:
|
with open(pidfilepath, 'rb') as fp:
|
||||||
datadir_pid = int(fp.read().decode('utf-8'))
|
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))
|
assert(os.path.exists(authcookiepath))
|
||||||
except Exception:
|
except Exception:
|
||||||
time.sleep(0.5)
|
time.sleep(0.5)
|
||||||
try:
|
try:
|
||||||
if os.name != 'nt' or cc['core_version_group'] > 17: # litecoin on windows doesn't write a pid file
|
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:
|
with open(authcookiepath, 'rb') as fp:
|
||||||
cc['rpcauth'] = fp.read().decode('utf-8')
|
cc['rpcauth'] = fp.read().decode('utf-8')
|
||||||
except Exception:
|
except Exception as e:
|
||||||
self.log.error('Unable to read authcookie for %s, %s, datadir pid %d, daemon pid %s', str(coin), authcookiepath, datadir_pid, cc['pid'])
|
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')
|
raise ValueError('Error, terminating')
|
||||||
|
|
||||||
def createCoinInterface(self, coin):
|
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.log.info('%s Core version %d', chainparams[c]['name'].capitalize(), core_version)
|
||||||
self.coin_clients[c]['core_version'] = core_version
|
self.coin_clients[c]['core_version'] = core_version
|
||||||
|
|
||||||
|
if c == Coins.XMR:
|
||||||
|
self.coin_clients[c]['interface'].ensureWalletExists()
|
||||||
|
|
||||||
if c == Coins.PART:
|
if c == Coins.PART:
|
||||||
self.coin_clients[c]['have_spent_index'] = self.coin_clients[c]['interface'].haveSpentIndex()
|
self.coin_clients[c]['have_spent_index'] = self.coin_clients[c]['interface'].haveSpentIndex()
|
||||||
|
|
||||||
|
@ -636,6 +638,8 @@ class BasicSwap(BaseApp):
|
||||||
self.initialise()
|
self.initialise()
|
||||||
|
|
||||||
def stopDaemon(self, coin):
|
def stopDaemon(self, coin):
|
||||||
|
if coin == Coins.XMR:
|
||||||
|
return
|
||||||
num_tries = 10
|
num_tries = 10
|
||||||
authcookiepath = os.path.join(self.getChainDatadirPath(coin), '.cookie')
|
authcookiepath = os.path.join(self.getChainDatadirPath(coin), '.cookie')
|
||||||
stopping = False
|
stopping = False
|
||||||
|
@ -697,6 +701,19 @@ class BasicSwap(BaseApp):
|
||||||
if synced < 1.0:
|
if synced < 1.0:
|
||||||
raise ValueError('{} chain is still syncing, currently at {}.'.format(self.coin_clients[c]['name'], synced))
|
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):
|
def setIntKV(self, str_key, int_val):
|
||||||
session = scoped_session(self.session_factory)
|
session = scoped_session(self.session_factory)
|
||||||
kv = session.query(DBKVInt).filter_by(key=str_key).first()
|
kv = session.query(DBKVInt).filter_by(key=str_key).first()
|
||||||
|
@ -963,19 +980,8 @@ class BasicSwap(BaseApp):
|
||||||
session.remove()
|
session.remove()
|
||||||
self.mxDB.release()
|
self.mxDB.release()
|
||||||
|
|
||||||
def getPathKey(self, coin_from, coin_to, offer_created_at, contract_count, key_no, for_xmr=False):
|
def grindForEd25519Key(self, coin_type, evkey, key_path_base):
|
||||||
account = self.callcoinrpc(Coins.PART, 'extkey', ['account'])
|
ci = self.ci(coin_type)
|
||||||
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'])
|
|
||||||
|
|
||||||
nonce = 1
|
nonce = 1
|
||||||
while True:
|
while True:
|
||||||
key_path = key_path_base + '/{}'.format(nonce)
|
key_path = key_path_base + '/{}'.format(nonce)
|
||||||
|
@ -986,7 +992,34 @@ class BasicSwap(BaseApp):
|
||||||
return privkey
|
return privkey
|
||||||
nonce += 1
|
nonce += 1
|
||||||
if nonce > 1000:
|
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):
|
def getContractPubkey(self, date, contract_count):
|
||||||
account = self.callcoinrpc(Coins.PART, 'extkey', ['account'])
|
account = self.callcoinrpc(Coins.PART, 'extkey', ['account'])
|
||||||
|
@ -1550,8 +1583,8 @@ class BasicSwap(BaseApp):
|
||||||
xmr_swap.contract_count = self.getNewContractId()
|
xmr_swap.contract_count = self.getNewContractId()
|
||||||
xmr_swap.dest_af = msg_buf.dest_af
|
xmr_swap.dest_af = msg_buf.dest_af
|
||||||
xmr_swap.b_restore_height = self.ci(coin_to).getChainHeight()
|
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)
|
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_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)
|
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)
|
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)
|
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)
|
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_xmr=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)
|
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)
|
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_from = self.ci(coin_from)
|
||||||
ci_to = self.ci(coin_to)
|
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)
|
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)
|
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)
|
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)
|
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)
|
vkbs = ci_to.sumKeys(kbsl, kbsf)
|
||||||
|
|
||||||
address_to = ci_to.getMainWalletAddress()
|
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)
|
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)
|
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)
|
vkbs = ci_to.sumKeys(kbsl, kbsf)
|
||||||
|
|
||||||
address_to = ci_to.getMainWalletAddress()
|
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_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
|
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)
|
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)
|
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 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
# Copyright (c) 2019 tecnovert
|
# Copyright (c) 2019-2020 tecnovert
|
||||||
# Distributed under the MIT software license, see the accompanying
|
# Distributed under the MIT software license, see the accompanying
|
||||||
# file LICENSE or http://www.opensource.org/licenses/mit-license.php.
|
# file LICENSE or http://www.opensource.org/licenses/mit-license.php.
|
||||||
|
|
||||||
|
@ -70,6 +70,7 @@ chainparams = {
|
||||||
'rpcport': 8332,
|
'rpcport': 8332,
|
||||||
'pubkey_address': 0,
|
'pubkey_address': 0,
|
||||||
'script_address': 5,
|
'script_address': 5,
|
||||||
|
'key_prefix': 128,
|
||||||
'hrp': 'bc',
|
'hrp': 'bc',
|
||||||
'bip44': 0,
|
'bip44': 0,
|
||||||
'min_amount': 1000,
|
'min_amount': 1000,
|
||||||
|
@ -79,6 +80,7 @@ chainparams = {
|
||||||
'rpcport': 18332,
|
'rpcport': 18332,
|
||||||
'pubkey_address': 111,
|
'pubkey_address': 111,
|
||||||
'script_address': 196,
|
'script_address': 196,
|
||||||
|
'key_prefix': 239,
|
||||||
'hrp': 'tb',
|
'hrp': 'tb',
|
||||||
'bip44': 1,
|
'bip44': 1,
|
||||||
'min_amount': 1000,
|
'min_amount': 1000,
|
||||||
|
@ -89,6 +91,7 @@ chainparams = {
|
||||||
'rpcport': 18443,
|
'rpcport': 18443,
|
||||||
'pubkey_address': 111,
|
'pubkey_address': 111,
|
||||||
'script_address': 196,
|
'script_address': 196,
|
||||||
|
'key_prefix': 239,
|
||||||
'hrp': 'bcrt',
|
'hrp': 'bcrt',
|
||||||
'bip44': 1,
|
'bip44': 1,
|
||||||
'min_amount': 1000,
|
'min_amount': 1000,
|
||||||
|
@ -105,6 +108,7 @@ chainparams = {
|
||||||
'rpcport': 9332,
|
'rpcport': 9332,
|
||||||
'pubkey_address': 48,
|
'pubkey_address': 48,
|
||||||
'script_address': 50,
|
'script_address': 50,
|
||||||
|
'key_prefix': 176,
|
||||||
'hrp': 'ltc',
|
'hrp': 'ltc',
|
||||||
'bip44': 2,
|
'bip44': 2,
|
||||||
'min_amount': 1000,
|
'min_amount': 1000,
|
||||||
|
@ -114,6 +118,7 @@ chainparams = {
|
||||||
'rpcport': 19332,
|
'rpcport': 19332,
|
||||||
'pubkey_address': 111,
|
'pubkey_address': 111,
|
||||||
'script_address': 58,
|
'script_address': 58,
|
||||||
|
'key_prefix': 239,
|
||||||
'hrp': 'tltc',
|
'hrp': 'tltc',
|
||||||
'bip44': 1,
|
'bip44': 1,
|
||||||
'min_amount': 1000,
|
'min_amount': 1000,
|
||||||
|
@ -124,6 +129,7 @@ chainparams = {
|
||||||
'rpcport': 19443,
|
'rpcport': 19443,
|
||||||
'pubkey_address': 111,
|
'pubkey_address': 111,
|
||||||
'script_address': 58,
|
'script_address': 58,
|
||||||
|
'key_prefix': 239,
|
||||||
'hrp': 'rltc',
|
'hrp': 'rltc',
|
||||||
'bip44': 1,
|
'bip44': 1,
|
||||||
'min_amount': 1000,
|
'min_amount': 1000,
|
||||||
|
|
|
@ -8,6 +8,7 @@ import os
|
||||||
|
|
||||||
CONFIG_FILENAME = 'basicswap.json'
|
CONFIG_FILENAME = 'basicswap.json'
|
||||||
DEFAULT_DATADIR = '~/.basicswap'
|
DEFAULT_DATADIR = '~/.basicswap'
|
||||||
|
DEFAULT_ALLOW_CORS = False
|
||||||
TEST_DATADIRS = os.path.expanduser(os.getenv('DATADIRS', '/tmp/basicswap'))
|
TEST_DATADIRS = os.path.expanduser(os.getenv('DATADIRS', '/tmp/basicswap'))
|
||||||
|
|
||||||
bin_suffix = ('.exe' if os.name == 'nt' else '')
|
bin_suffix = ('.exe' if os.name == 'nt' else '')
|
||||||
|
|
|
@ -17,6 +17,7 @@ from .util import (
|
||||||
dumpj,
|
dumpj,
|
||||||
format_amount,
|
format_amount,
|
||||||
make_int,
|
make_int,
|
||||||
|
toWIF,
|
||||||
decodeAddress)
|
decodeAddress)
|
||||||
from coincurve.keys import (
|
from coincurve.keys import (
|
||||||
PublicKey)
|
PublicKey)
|
||||||
|
@ -131,6 +132,16 @@ class BTCInterface(CoinInterface):
|
||||||
def getBlockchainInfo(self):
|
def getBlockchainInfo(self):
|
||||||
return self.rpc_callback('getblockchaininfo')
|
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):
|
def getWalletInfo(self):
|
||||||
return self.rpc_callback('getwalletinfo')
|
return self.rpc_callback('getwalletinfo')
|
||||||
|
|
||||||
|
|
|
@ -40,3 +40,6 @@ class PARTInterface(BTCInterface):
|
||||||
version = self.getDaemonVersion()
|
version = self.getDaemonVersion()
|
||||||
index_info = self.rpc_callback('getinsightinfo' if int(str(version)[:2]) > 19 else 'getindexinfo')
|
index_info = self.rpc_callback('getinsightinfo' if int(str(version)[:2]) > 19 else 'getindexinfo')
|
||||||
return index_info['spentindex']
|
return index_info['spentindex']
|
||||||
|
|
||||||
|
def initialiseWallet(self, key):
|
||||||
|
raise ValueError('TODO')
|
||||||
|
|
|
@ -65,11 +65,45 @@ class XMRInterface(CoinInterface):
|
||||||
def setWalletFilename(self, wallet_filename):
|
def setWalletFilename(self, wallet_filename):
|
||||||
self._wallet_filename = 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):
|
def testDaemonRPC(self):
|
||||||
self.rpc_wallet_cb('get_languages')
|
self.rpc_wallet_cb('get_languages')
|
||||||
|
|
||||||
def getDaemonVersion(self):
|
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):
|
def getBlockchainInfo(self):
|
||||||
rv = {}
|
rv = {}
|
||||||
|
|
|
@ -15,7 +15,7 @@ class Peer:
|
||||||
|
|
||||||
|
|
||||||
class Network:
|
class Network:
|
||||||
def __init__(self, network_port, network_key):
|
def __init__(self, p2p_port, network_key):
|
||||||
self._network_port = network_port
|
self._p2p_port = p2p_port
|
||||||
self._network_key = network_key
|
self._network_key = network_key
|
||||||
self._peers = []
|
self._peers = []
|
||||||
|
|
|
@ -16,6 +16,7 @@ import json
|
||||||
import mmap
|
import mmap
|
||||||
import stat
|
import stat
|
||||||
import gnupg
|
import gnupg
|
||||||
|
import signal
|
||||||
import hashlib
|
import hashlib
|
||||||
import tarfile
|
import tarfile
|
||||||
import zipfile
|
import zipfile
|
||||||
|
@ -24,13 +25,15 @@ import platform
|
||||||
import urllib.parse
|
import urllib.parse
|
||||||
from urllib.request import urlretrieve
|
from urllib.request import urlretrieve
|
||||||
|
|
||||||
|
|
||||||
import basicswap.config as cfg
|
import basicswap.config as cfg
|
||||||
from basicswap.rpc import (
|
from basicswap.rpc import (
|
||||||
callrpc_cli,
|
callrpc_cli,
|
||||||
waitForRPC,
|
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':
|
if platform.system() == 'Darwin':
|
||||||
BIN_ARCH = 'osx64.tar.gz'
|
BIN_ARCH = 'osx64.tar.gz'
|
||||||
|
@ -40,7 +43,7 @@ else:
|
||||||
BIN_ARCH = 'x86_64-linux-gnu.tar.gz'
|
BIN_ARCH = 'x86_64-linux-gnu.tar.gz'
|
||||||
|
|
||||||
known_coins = {
|
known_coins = {
|
||||||
'particl': '0.19.1.1',
|
'particl': '0.19.1.2',
|
||||||
'litecoin': '0.18.1',
|
'litecoin': '0.18.1',
|
||||||
'bitcoin': '0.20.1',
|
'bitcoin': '0.20.1',
|
||||||
'namecoin': '0.18.0',
|
'namecoin': '0.18.0',
|
||||||
|
@ -52,6 +55,13 @@ logger.level = logging.DEBUG
|
||||||
if not len(logger.handlers):
|
if not len(logger.handlers):
|
||||||
logger.addHandler(logging.StreamHandler(sys.stdout))
|
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():
|
def make_reporthook():
|
||||||
read = 0 # Number of bytes read so far
|
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())
|
fout.write(fi.read())
|
||||||
fi.close()
|
fi.close()
|
||||||
os.chmod(out_path, stat.S_IRWXU | stat.S_IXGRP | stat.S_IXOTH)
|
os.chmod(out_path, stat.S_IRWXU | stat.S_IXGRP | stat.S_IXOTH)
|
||||||
|
|
||||||
print('member', member)
|
|
||||||
return
|
return
|
||||||
|
|
||||||
bins = [coin + 'd', coin + '-cli', coin + '-tx']
|
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):
|
if not os.path.exists(data_dir):
|
||||||
os.makedirs(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')
|
core_conf_path = os.path.join(data_dir, coin + '.conf')
|
||||||
if os.path.exists(core_conf_path):
|
if os.path.exists(core_conf_path):
|
||||||
exitWithError('{} exists'.format(core_conf_path))
|
exitWithError('{} exists'.format(core_conf_path))
|
||||||
|
|
||||||
with open(core_conf_path, 'w') as fp:
|
with open(core_conf_path, 'w') as fp:
|
||||||
if chain != 'mainnet':
|
if chain != 'mainnet':
|
||||||
fp.write(chain + '=1\n')
|
fp.write(chain + '=1\n')
|
||||||
|
@ -490,11 +528,14 @@ def main():
|
||||||
'monero': {
|
'monero': {
|
||||||
'connection_type': 'rpc' if 'monero' in with_coins else 'none',
|
'connection_type': 'rpc' if 'monero' in with_coins else 'none',
|
||||||
'manage_daemon': True if 'monero' in with_coins else False,
|
'manage_daemon': True if 'monero' in with_coins else False,
|
||||||
'rpcport': 29798 + port_offset,
|
'manage_wallet_daemon': True if 'monero' in with_coins else False,
|
||||||
'walletrpcport': 29799 + port_offset,
|
'rpcport': BASE_XMR_RPC_PORT + port_offset,
|
||||||
#'walletrpcuser': 'test' + str(node_id),
|
'zmqport': BASE_XMR_ZMQ_PORT + port_offset,
|
||||||
#'walletrpcpassword': 'test_pass' + str(node_id),
|
'walletrpcport': BASE_XMR_WALLET_PORT + port_offset,
|
||||||
'walletfile': 'basicswap',
|
'rpchost': XMR_RPC_HOST,
|
||||||
|
'walletrpcuser': XMR_WALLET_RPC_USER,
|
||||||
|
'walletrpcpassword': XMR_WALLET_RPC_PWD,
|
||||||
|
'walletfile': 'swap_wallet',
|
||||||
'datadir': os.path.join(data_dir, 'monero'),
|
'datadir': os.path.join(data_dir, 'monero'),
|
||||||
'bindir': os.path.join(bin_dir, 'monero'),
|
'bindir': os.path.join(bin_dir, 'monero'),
|
||||||
}
|
}
|
||||||
|
@ -597,26 +638,57 @@ def main():
|
||||||
|
|
||||||
particl_settings = settings['chainclients']['particl']
|
particl_settings = settings['chainclients']['particl']
|
||||||
partRpc = make_rpc_func(particl_settings['bindir'], particl_settings['datadir'], chain)
|
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:
|
try:
|
||||||
waitForRPC(partRpc)
|
waitForRPC(partRpc)
|
||||||
|
|
||||||
if particl_wallet_mnemonic is None:
|
if particl_wallet_mnemonic is None:
|
||||||
particl_wallet_mnemonic = partRpc('mnemonic new')['mnemonic']
|
particl_wallet_mnemonic = partRpc('mnemonic new')['mnemonic']
|
||||||
partRpc('extkeyimportmaster "{}"'.format(particl_wallet_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:
|
finally:
|
||||||
logger.info('Terminating {}'.format(d.pid))
|
for d in daemons:
|
||||||
d.terminate()
|
logging.info('Interrupting {}'.format(d.pid))
|
||||||
d.wait(timeout=120)
|
d.send_signal(signal.SIGINT)
|
||||||
if d.stdout:
|
d.wait(timeout=120)
|
||||||
d.stdout.close()
|
for fp in (d.stdout, d.stderr, d.stdin):
|
||||||
if d.stderr:
|
if fp:
|
||||||
d.stderr.close()
|
fp.close()
|
||||||
if d.stdin:
|
|
||||||
d.stdin.close()
|
|
||||||
|
|
||||||
logger.info('IMPORTANT - Save your particl wallet recovery phrase:\n{}\n'.format(particl_wallet_mnemonic))
|
logger.info('IMPORTANT - Save your particl wallet recovery phrase:\n{}\n'.format(particl_wallet_mnemonic))
|
||||||
|
|
||||||
logger.info('Done.')
|
logger.info('Done.')
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -19,7 +19,6 @@ import logging
|
||||||
import traceback
|
import traceback
|
||||||
import subprocess
|
import subprocess
|
||||||
|
|
||||||
|
|
||||||
import basicswap.config as cfg
|
import basicswap.config as cfg
|
||||||
from basicswap import __version__
|
from basicswap import __version__
|
||||||
from basicswap.basicswap import BasicSwap
|
from basicswap.basicswap import BasicSwap
|
||||||
|
@ -31,7 +30,6 @@ logger.level = logging.DEBUG
|
||||||
if not len(logger.handlers):
|
if not len(logger.handlers):
|
||||||
logger.addHandler(logging.StreamHandler(sys.stdout))
|
logger.addHandler(logging.StreamHandler(sys.stdout))
|
||||||
|
|
||||||
ALLOW_CORS = False
|
|
||||||
swap_client = None
|
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)
|
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):
|
def runClient(fp, data_dir, chain):
|
||||||
global swap_client
|
global swap_client
|
||||||
settings_path = os.path.join(data_dir, cfg.CONFIG_FILENAME)
|
settings_path = os.path.join(data_dir, cfg.CONFIG_FILENAME)
|
||||||
|
@ -79,6 +100,20 @@ def runClient(fp, data_dir, chain):
|
||||||
try:
|
try:
|
||||||
# Try start daemons
|
# Try start daemons
|
||||||
for c, v in settings['chainclients'].items():
|
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:
|
if v['manage_daemon'] is True:
|
||||||
logger.info('Starting {} daemon'.format(c.capitalize()))
|
logger.info('Starting {} daemon'.format(c.capitalize()))
|
||||||
|
|
||||||
|
@ -99,7 +134,7 @@ def runClient(fp, data_dir, chain):
|
||||||
|
|
||||||
if 'htmlhost' in settings:
|
if 'htmlhost' in settings:
|
||||||
swap_client.log.info('Starting server at %s:%d.' % (settings['htmlhost'], settings['htmlport']))
|
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)
|
tS1 = HttpThread(fp, settings['htmlhost'], settings['htmlport'], allow_cors, swap_client)
|
||||||
threads.append(tS1)
|
threads.append(tS1)
|
||||||
tS1.start()
|
tS1.start()
|
||||||
|
@ -118,8 +153,7 @@ def runClient(fp, data_dir, chain):
|
||||||
|
|
||||||
closed_pids = []
|
closed_pids = []
|
||||||
for d in daemons:
|
for d in daemons:
|
||||||
int_pid = d.pid
|
logging.info('Interrupting {}'.format(d.pid))
|
||||||
logging.info('Interrupting {}'.format(int_pid))
|
|
||||||
try:
|
try:
|
||||||
d.send_signal(signal.SIGINT)
|
d.send_signal(signal.SIGINT)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
@ -127,13 +161,10 @@ def runClient(fp, data_dir, chain):
|
||||||
for d in daemons:
|
for d in daemons:
|
||||||
try:
|
try:
|
||||||
d.wait(timeout=120)
|
d.wait(timeout=120)
|
||||||
if d.stdout:
|
for fp in (d.stdout, d.stderr, d.stdin):
|
||||||
d.stdout.close()
|
if fp:
|
||||||
if d.stderr:
|
fp.close()
|
||||||
d.stderr.close()
|
closed_pids.append(d.pid)
|
||||||
if d.stdin:
|
|
||||||
d.stdin.close()
|
|
||||||
closed_pids.append(int_pid)
|
|
||||||
except Exception as ex:
|
except Exception as ex:
|
||||||
logger.error('Error: {}'.format(ex))
|
logger.error('Error: {}'.format(ex))
|
||||||
|
|
||||||
|
|
|
@ -5,8 +5,8 @@
|
||||||
# Distributed under the MIT software license, see the accompanying
|
# Distributed under the MIT software license, see the accompanying
|
||||||
# file LICENSE or http://www.opensource.org/licenses/mit-license.php.
|
# file LICENSE or http://www.opensource.org/licenses/mit-license.php.
|
||||||
|
|
||||||
import unittest
|
|
||||||
import secrets
|
import secrets
|
||||||
|
import unittest
|
||||||
|
|
||||||
import basicswap.contrib.ed25519_fast as edf
|
import basicswap.contrib.ed25519_fast as edf
|
||||||
import basicswap.ed25519_fast_util as edu
|
import basicswap.ed25519_fast_util as edu
|
||||||
|
|
|
@ -7,12 +7,13 @@
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
import unittest
|
|
||||||
from unittest.mock import patch
|
|
||||||
from io import StringIO
|
|
||||||
import logging
|
|
||||||
import shutil
|
|
||||||
import json
|
import json
|
||||||
|
import shutil
|
||||||
|
import logging
|
||||||
|
import unittest
|
||||||
|
|
||||||
|
from io import StringIO
|
||||||
|
from unittest.mock import patch
|
||||||
|
|
||||||
import basicswap.config as cfg
|
import basicswap.config as cfg
|
||||||
import bin.basicswap_prepare as prepareSystem
|
import bin.basicswap_prepare as prepareSystem
|
||||||
|
|
|
@ -18,17 +18,17 @@ python tests/basicswap/test_reload.py
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
import time
|
|
||||||
import unittest
|
|
||||||
import logging
|
|
||||||
import shutil
|
|
||||||
import json
|
import json
|
||||||
|
import time
|
||||||
|
import shutil
|
||||||
|
import logging
|
||||||
|
import unittest
|
||||||
import traceback
|
import traceback
|
||||||
import multiprocessing
|
|
||||||
import threading
|
import threading
|
||||||
from unittest.mock import patch
|
import multiprocessing
|
||||||
from urllib.request import urlopen
|
|
||||||
from urllib import parse
|
from urllib import parse
|
||||||
|
from urllib.request import urlopen
|
||||||
|
from unittest.mock import patch
|
||||||
|
|
||||||
from basicswap.rpc import (
|
from basicswap.rpc import (
|
||||||
callrpc_cli,
|
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,
|
TEST_HTTP_PORT,
|
||||||
)
|
)
|
||||||
from basicswap.contrib.rpcauth import generate_salt, password_to_hmac
|
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()
|
logger = logging.getLogger()
|
||||||
|
@ -479,12 +479,9 @@ class Test(unittest.TestCase):
|
||||||
for d in cls.xmr_daemons:
|
for d in cls.xmr_daemons:
|
||||||
try:
|
try:
|
||||||
d.wait(timeout=20)
|
d.wait(timeout=20)
|
||||||
if d.stdout:
|
for fp in (d.stdout, d.stderr, d.stdin):
|
||||||
d.stdout.close()
|
if fp:
|
||||||
if d.stderr:
|
fp.close()
|
||||||
d.stderr.close()
|
|
||||||
if d.stdin:
|
|
||||||
d.stdin.close()
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logging.info('Closing %d, error %s', d.pid, str(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:
|
for d in cls.part_daemons + cls.btc_daemons:
|
||||||
try:
|
try:
|
||||||
d.wait(timeout=20)
|
d.wait(timeout=20)
|
||||||
if d.stdout:
|
for fp in (d.stdout, d.stderr, d.stdin):
|
||||||
d.stdout.close()
|
if fp:
|
||||||
if d.stderr:
|
fp.close()
|
||||||
d.stderr.close()
|
|
||||||
if d.stdin:
|
|
||||||
d.stdin.close()
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logging.info('Closing %d, error %s', d.pid, str(e))
|
logging.info('Closing %d, error %s', d.pid, str(e))
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue