|
|
|
#!/usr/bin/env python3
|
|
|
|
# -*- coding: utf-8 -*-
|
|
|
|
|
|
|
|
# Copyright (c) 2019 tecnovert
|
|
|
|
# Distributed under the MIT software license, see the accompanying
|
|
|
|
# file LICENSE.txt or http://www.opensource.org/licenses/mit-license.php.
|
|
|
|
|
|
|
|
"""
|
|
|
|
Atomic Swap Client - Proof of Concept
|
|
|
|
|
|
|
|
sudo pip install python-gnupg
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
import sys
|
|
|
|
import os
|
|
|
|
import json
|
|
|
|
import hashlib
|
|
|
|
import mmap
|
|
|
|
import tarfile
|
|
|
|
import zipfile
|
|
|
|
import stat
|
|
|
|
import time
|
|
|
|
from urllib.request import urlretrieve
|
|
|
|
import urllib.parse
|
|
|
|
import logging
|
|
|
|
import platform
|
|
|
|
|
|
|
|
import gnupg
|
|
|
|
|
|
|
|
import basicswap.config as cfg
|
|
|
|
from basicswap.util import callrpc_cli
|
|
|
|
from bin.basicswap_run import startDaemon
|
|
|
|
|
|
|
|
if platform.system() == 'Darwin':
|
|
|
|
BIN_ARCH = 'osx64.tar.gz'
|
|
|
|
elif platform.system() == 'Windows':
|
|
|
|
BIN_ARCH = 'win64.zip'
|
|
|
|
else:
|
|
|
|
BIN_ARCH = 'x86_64-linux-gnu.tar.gz'
|
|
|
|
|
|
|
|
known_coins = {
|
|
|
|
'particl': '0.18.1.6',
|
|
|
|
'litecoin': '0.17.1',
|
|
|
|
'bitcoin': '0.18.1',
|
|
|
|
'namecoin': '0.18.0',
|
|
|
|
}
|
|
|
|
|
|
|
|
logger = logging.getLogger()
|
|
|
|
logger.level = logging.DEBUG
|
|
|
|
if not len(logger.handlers):
|
|
|
|
logger.addHandler(logging.StreamHandler(sys.stdout))
|
|
|
|
|
|
|
|
|
|
|
|
def make_reporthook():
|
|
|
|
read = 0 # number of bytes read so far
|
|
|
|
last_percent_str = ''
|
|
|
|
|
|
|
|
def reporthook(blocknum, blocksize, totalsize):
|
|
|
|
nonlocal read
|
|
|
|
nonlocal last_percent_str
|
|
|
|
read += blocksize
|
|
|
|
if totalsize > 0:
|
|
|
|
percent_str = '%5.1f%%' % (read * 1e2 / totalsize)
|
|
|
|
if percent_str != last_percent_str:
|
|
|
|
logger.info(percent_str)
|
|
|
|
last_percent_str = percent_str
|
|
|
|
else:
|
|
|
|
logger.info('read %d' % (read,))
|
|
|
|
return reporthook
|
|
|
|
|
|
|
|
|
|
|
|
def downloadFile(url, path):
|
|
|
|
logger.info('Downloading file %s', url)
|
|
|
|
opener = urllib.request.build_opener()
|
|
|
|
opener.addheaders = [('User-agent', 'Mozilla/5.0')]
|
|
|
|
urllib.request.install_opener(opener)
|
|
|
|
urlretrieve(url, path, make_reporthook())
|
|
|
|
|
|
|
|
|
|
|
|
def prepareCore(coin, version, settings, data_dir):
|
|
|
|
logger.info('prepareCore %s v%s', coin, version)
|
|
|
|
|
|
|
|
bin_dir = os.path.expanduser(settings['chainclients'][coin]['bindir'])
|
|
|
|
if not os.path.exists(bin_dir):
|
|
|
|
os.makedirs(bin_dir)
|
|
|
|
|
|
|
|
if 'osx' in BIN_ARCH:
|
|
|
|
os_dir_name = 'osx-unsigned'
|
|
|
|
os_name = 'osx'
|
|
|
|
elif 'win32' in BIN_ARCH or 'win64' in BIN_ARCH:
|
|
|
|
os_dir_name = 'win-unsigned'
|
|
|
|
os_name = 'win'
|
|
|
|
else:
|
|
|
|
os_dir_name = 'linux'
|
|
|
|
os_name = 'linux'
|
|
|
|
|
|
|
|
release_filename = '{}-{}-{}'.format(coin, version, BIN_ARCH)
|
|
|
|
if coin == 'particl':
|
|
|
|
signing_key_name = 'tecnovert'
|
|
|
|
release_url = 'https://github.com/particl/particl-core/releases/download/v{}/{}'.format(version, release_filename)
|
|
|
|
assert_filename = '{}-{}-{}-build.assert'.format(coin, os_name, version)
|
|
|
|
assert_url = 'https://raw.githubusercontent.com/particl/gitian.sigs/master/%s-%s/%s/%s' % (version, os_dir_name, signing_key_name, assert_filename)
|
|
|
|
elif coin == 'litecoin':
|
|
|
|
signing_key_name = 'thrasher'
|
|
|
|
release_url = 'https://download.litecoin.org/litecoin-{}/{}/{}'.format(version, os_name, release_filename)
|
|
|
|
assert_filename = '{}-{}-{}-build.assert'.format(coin, os_name, version.rsplit('.', 1)[0])
|
|
|
|
assert_url = 'https://raw.githubusercontent.com/litecoin-project/gitian.sigs.ltc/master/%s-%s/%s/%s' % (version, os_dir_name, signing_key_name, assert_filename)
|
|
|
|
elif coin == 'bitcoin':
|
|
|
|
signing_key_name = 'laanwj'
|
|
|
|
release_url = 'https://bitcoincore.org/bin/bitcoin-core-{}/{}'.format(version, release_filename)
|
|
|
|
assert_filename = '{}-{}-{}-build.assert'.format(coin, os_name, version.rsplit('.', 1)[0])
|
|
|
|
assert_url = 'https://raw.githubusercontent.com/bitcoin-core/gitian.sigs/master/%s-%s/%s/%s' % (version, os_dir_name, signing_key_name, assert_filename)
|
|
|
|
elif coin == 'namecoin':
|
|
|
|
signing_key_name = 'JeremyRand'
|
|
|
|
release_url = 'https://beta.namecoin.org/files/namecoin-core/namecoin-core-{}/{}'.format(version, release_filename)
|
|
|
|
assert_filename = '{}-{}-{}-build.assert'.format(coin, os_name, version.rsplit('.', 1)[0])
|
|
|
|
assert_url = 'https://raw.githubusercontent.com/namecoin/gitian.sigs/master/%s-%s/%s/%s' % (version, os_dir_name, signing_key_name, assert_filename)
|
|
|
|
else:
|
|
|
|
raise ValueError('Unknown coin')
|
|
|
|
|
|
|
|
assert_sig_filename = assert_filename + '.sig'
|
|
|
|
assert_sig_url = assert_url + '.sig'
|
|
|
|
|
|
|
|
release_path = os.path.join(bin_dir, release_filename)
|
|
|
|
if not os.path.exists(release_path):
|
|
|
|
downloadFile(release_url, release_path)
|
|
|
|
|
|
|
|
# Rename assert files with full version
|
|
|
|
assert_filename = '{}-{}-{}-build.assert'.format(coin, os_name, version)
|
|
|
|
assert_path = os.path.join(bin_dir, assert_filename)
|
|
|
|
if not os.path.exists(assert_path):
|
|
|
|
downloadFile(assert_url, assert_path)
|
|
|
|
|
|
|
|
assert_sig_filename = '{}-{}-{}-build.assert.sig'.format(coin, os_name, version)
|
|
|
|
assert_sig_path = os.path.join(bin_dir, assert_sig_filename)
|
|
|
|
if not os.path.exists(assert_sig_path):
|
|
|
|
downloadFile(assert_sig_url, assert_sig_path)
|
|
|
|
|
|
|
|
hasher = hashlib.sha256()
|
|
|
|
with open(release_path, 'rb') as fp:
|
|
|
|
hasher.update(fp.read())
|
|
|
|
release_hash = hasher.digest()
|
|
|
|
|
|
|
|
logger.info('%s hash: %s', release_filename, release_hash.hex())
|
|
|
|
with open(assert_path, 'rb', 0) as fp, mmap.mmap(fp.fileno(), 0, access=mmap.ACCESS_READ) as s:
|
|
|
|
if s.find(bytes(release_hash.hex(), 'utf-8')) == -1:
|
|
|
|
raise ValueError('Error: release hash %s not found in assert file.' % (release_hash.hex()))
|
|
|
|
else:
|
|
|
|
logger.info('Found release hash in assert file.')
|
|
|
|
|
|
|
|
"""
|
|
|
|
gnupghome = os.path.join(data_dir, 'gpg')
|
|
|
|
if not os.path.exists(gnupghome):
|
|
|
|
os.makedirs(gnupghome)
|
|
|
|
"""
|
|
|
|
gpg = gnupg.GPG()
|
|
|
|
|
|
|
|
with open(assert_sig_path, 'rb') as fp:
|
|
|
|
verified = gpg.verify_file(fp, assert_path)
|
|
|
|
|
|
|
|
if verified.username is None:
|
|
|
|
logger.warning('Signature not verified.')
|
|
|
|
|
|
|
|
pubkeyurl = 'https://raw.githubusercontent.com/tecnovert/basicswap/master/gitianpubkeys/{}_{}.pgp'.format(coin, signing_key_name)
|
|
|
|
logger.info('Importing public key from url: ' + pubkeyurl)
|
|
|
|
gpg.import_keys(urllib.request.urlopen(pubkeyurl).read())
|
|
|
|
|
|
|
|
with open(assert_sig_path, 'rb') as fp:
|
|
|
|
verified = gpg.verify_file(fp, assert_path)
|
|
|
|
|
|
|
|
if verified.username is None:
|
|
|
|
raise ValueError('Signature verification failed.')
|
|
|
|
|
|
|
|
bins = [coin + 'd', coin + '-cli', coin + '-tx']
|
|
|
|
if os_name == 'win':
|
|
|
|
with zipfile.ZipFile(release_path) as fz:
|
|
|
|
for b in bins:
|
|
|
|
b += '.exe'
|
|
|
|
out_path = os.path.join(bin_dir, b)
|
|
|
|
with open(out_path, 'wb') as fout:
|
|
|
|
fout.write(fz.read('{}-{}/bin/{}'.format(coin, version, b)))
|
|
|
|
os.chmod(out_path, stat.S_IRWXU | stat.S_IXGRP | stat.S_IXOTH)
|
|
|
|
else:
|
|
|
|
with tarfile.open(release_path) as ft:
|
|
|
|
for b in bins:
|
|
|
|
out_path = os.path.join(bin_dir, b)
|
|
|
|
fi = ft.extractfile('{}-{}/bin/{}'.format(coin, version, b))
|
|
|
|
with open(out_path, 'wb') as fout:
|
|
|
|
fout.write(fi.read())
|
|
|
|
fi.close()
|
|
|
|
os.chmod(out_path, stat.S_IRWXU | stat.S_IXGRP | stat.S_IXOTH)
|
|
|
|
|
|
|
|
|
|
|
|
def prepareDataDir(coin, settings, data_dir, chain, particl_mnemonic):
|
|
|
|
core_settings = settings['chainclients'][coin]
|
|
|
|
data_dir = core_settings['datadir']
|
|
|
|
|
|
|
|
if not os.path.exists(data_dir):
|
|
|
|
os.makedirs(data_dir)
|
|
|
|
|
|
|
|
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')
|
|
|
|
if chain == 'testnet':
|
|
|
|
fp.write('[test]\n\n')
|
|
|
|
if chain == 'regtest':
|
|
|
|
fp.write('[regtest]\n\n')
|
|
|
|
else:
|
|
|
|
logger.warning('Unknown chain %s', chain)
|
|
|
|
|
|
|
|
fp.write('rpcport={}\n'.format(core_settings['rpcport']))
|
|
|
|
fp.write('printtoconsole=0\n')
|
|
|
|
fp.write('daemon=0\n')
|
|
|
|
|
|
|
|
if coin == 'particl':
|
|
|
|
fp.write('debugexclude=libevent\n')
|
|
|
|
fp.write('zmqpubsmsg=tcp://127.0.0.1:{}\n'.format(settings['zmqport']))
|
|
|
|
fp.write('spentindex=1\n')
|
|
|
|
fp.write('txindex=1\n')
|
|
|
|
fp.write('staking=0\n')
|
|
|
|
|
|
|
|
if particl_mnemonic == 'none':
|
|
|
|
fp.write('createdefaultmasterkey=1')
|
|
|
|
elif coin == 'litecoin':
|
|
|
|
fp.write('prune=1000\n')
|
|
|
|
elif coin == 'bitcoin':
|
|
|
|
fp.write('prune=1000\n')
|
|
|
|
elif coin == 'namecoin':
|
|
|
|
fp.write('prune=1000\n')
|
|
|
|
else:
|
|
|
|
logger.warning('Unknown coin %s', coin)
|
|
|
|
|
|
|
|
|
|
|
|
def extractCore(coin, version, settings):
|
|
|
|
logger.info('extractCore %s v%s', coin, version)
|
|
|
|
|
|
|
|
|
|
|
|
def printVersion():
|
|
|
|
from basicswap import __version__
|
|
|
|
logger.info('Basicswap version:', __version__)
|
|
|
|
|
|
|
|
|
|
|
|
def printHelp():
|
|
|
|
logger.info('Usage: basicswap-prepare ')
|
|
|
|
logger.info('\n--help, -h Print help.')
|
|
|
|
logger.info('--version, -v Print version.')
|
|
|
|
logger.info('--datadir=PATH Path to basicswap data directory, default:~/.basicswap.')
|
|
|
|
logger.info('--bindir=PATH Path to cores directory, default:datadir/bin.')
|
|
|
|
logger.info('--mainnet Run in mainnet mode.')
|
|
|
|
logger.info('--testnet Run in testnet mode.')
|
|
|
|
logger.info('--regtest Run in regtest mode.')
|
|
|
|
logger.info('--particl_mnemonic= Recovery phrase to use for the Particl wallet, default is randomly generated,\n'
|
|
|
|
+ ' "none" to set autogenerate account mode.')
|
|
|
|
logger.info('--withcoin= Prepare system to run daemon for coin.')
|
|
|
|
logger.info('--withoutcoin= Do not prepare system to run daemon for coin.')
|
|
|
|
logger.info('--addcoin= Add coin to existing setup.')
|
|
|
|
logger.info('--disablecoin= Make coin inactive.')
|
|
|
|
logger.info('--preparebinonly Don\'t prepare settings or datadirs.')
|
|
|
|
logger.info('--portoffset=n Raise all ports by n.')
|
|
|
|
|
|
|
|
logger.info('\n' + 'Known coins: %s', ', '.join(known_coins.keys()))
|
|
|
|
|
|
|
|
|
|
|
|
def make_rpc_func(bin_dir, data_dir, chain):
|
|
|
|
bin_dir = bin_dir
|
|
|
|
data_dir = data_dir
|
|
|
|
chain = '' if chain == 'mainnet' else chain
|
|
|
|
|
|
|
|
def rpc_func(cmd):
|
|
|
|
nonlocal bin_dir
|
|
|
|
nonlocal data_dir
|
|
|
|
nonlocal chain
|
|
|
|
|
|
|
|
return callrpc_cli(bin_dir, data_dir, chain, cmd, cfg.PARTICL_CLI)
|
|
|
|
return rpc_func
|
|
|
|
|
|
|
|
|
|
|
|
def waitForRPC(rpc_func, wallet=None):
|
|
|
|
for i in range(10):
|
|
|
|
try:
|
|
|
|
rpc_func('getwalletinfo')
|
|
|
|
return
|
|
|
|
except Exception as ex:
|
|
|
|
logging.warning('Can\'t connect to daemon RPC: %s. Trying again in %d second/s.', str(ex), (1 + i))
|
|
|
|
time.sleep(1 + i)
|
|
|
|
raise ValueError('waitForRPC failed')
|
|
|
|
|
|
|
|
|
|
|
|
def exitWithError(error_msg):
|
|
|
|
sys.stderr.write('Error: {}, exiting.\n'.format(error_msg))
|
|
|
|
sys.exit(1)
|
|
|
|
|
|
|
|
|
|
|
|
def main():
|
|
|
|
data_dir = None
|
|
|
|
bin_dir = None
|
|
|
|
port_offset = None
|
|
|
|
chain = 'mainnet'
|
|
|
|
particl_wallet_mnemonic = None
|
|
|
|
prepare_bin_only = False
|
|
|
|
with_coins = {'particl', 'litecoin'}
|
|
|
|
add_coin = ''
|
|
|
|
disable_coin = ''
|
|
|
|
|
|
|
|
for v in sys.argv[1:]:
|
|
|
|
if len(v) < 2 or v[0] != '-':
|
|
|
|
exitWithError('Unknown argument {}'.format(v))
|
|
|
|
|
|
|
|
s = v.split('=')
|
|
|
|
name = s[0].strip()
|
|
|
|
|
|
|
|
for i in range(2):
|
|
|
|
if name[0] == '-':
|
|
|
|
name = name[1:]
|
|
|
|
|
|
|
|
if name == 'v' or name == 'version':
|
|
|
|
printVersion()
|
|
|
|
return 0
|
|
|
|
if name == 'h' or name == 'help':
|
|
|
|
printHelp()
|
|
|
|
return 0
|
|
|
|
if name == 'mainnet':
|
|
|
|
continue
|
|
|
|
if name == 'testnet':
|
|
|
|
chain = 'testnet'
|
|
|
|
continue
|
|
|
|
if name == 'regtest':
|
|
|
|
chain = 'regtest'
|
|
|
|
continue
|
|
|
|
if name == 'preparebinonly':
|
|
|
|
prepare_bin_only = True
|
|
|
|
continue
|
|
|
|
|
|
|
|
if len(s) == 2:
|
|
|
|
if name == 'datadir':
|
|
|
|
data_dir = os.path.expanduser(s[1].strip('"'))
|
|
|
|
continue
|
|
|
|
if name == 'bindir':
|
|
|
|
bin_dir = os.path.expanduser(s[1].strip('"'))
|
|
|
|
continue
|
|
|
|
if name == 'portoffset':
|
|
|
|
port_offset = int(s[1])
|
|
|
|
continue
|
|
|
|
if name == 'particl_mnemonic':
|
|
|
|
particl_wallet_mnemonic = s[1].strip('"')
|
|
|
|
continue
|
|
|
|
if name == 'withcoin':
|
|
|
|
if s[1] not in known_coins:
|
|
|
|
exitWithError('Unknown coin {}'.format(s[1]))
|
|
|
|
with_coins.add(s[1])
|
|
|
|
continue
|
|
|
|
if name == 'withoutcoin':
|
|
|
|
if s[1] not in known_coins:
|
|
|
|
exitWithError('Unknown coin {}'.format(s[1]))
|
|
|
|
with_coins.discard(s[1])
|
|
|
|
continue
|
|
|
|
if name == 'addcoin':
|
|
|
|
if s[1] not in known_coins:
|
|
|
|
exitWithError('Unknown coin {}'.format(s[1]))
|
|
|
|
add_coin = s[1]
|
|
|
|
with_coins = [add_coin, ]
|
|
|
|
continue
|
|
|
|
if name == 'disablecoin':
|
|
|
|
if s[1] not in known_coins:
|
|
|
|
exitWithError('Unknown coin {}'.format(s[1]))
|
|
|
|
disable_coin = s[1]
|
|
|
|
continue
|
|
|
|
|
|
|
|
exitWithError('Unknown argument {}'.format(v))
|
|
|
|
|
|
|
|
if data_dir is None:
|
|
|
|
default_datadir = '~/.basicswap'
|
|
|
|
data_dir = os.path.join(os.path.expanduser(default_datadir))
|
|
|
|
if bin_dir is None:
|
|
|
|
bin_dir = os.path.join(data_dir, 'bin')
|
|
|
|
|
|
|
|
logger.info('Using datadir: %s', data_dir)
|
|
|
|
logger.info('Chain: %s', chain)
|
|
|
|
|
|
|
|
if port_offset is None:
|
|
|
|
port_offset = 300 if chain == 'testnet' else 0
|
|
|
|
|
|
|
|
if not os.path.exists(data_dir):
|
|
|
|
os.makedirs(data_dir)
|
|
|
|
config_path = os.path.join(data_dir, 'basicswap.json')
|
|
|
|
|
|
|
|
withchainclients = {}
|
|
|
|
chainclients = {
|
|
|
|
'particl': {
|
|
|
|
'connection_type': 'rpc',
|
|
|
|
'manage_daemon': True,
|
|
|
|
'rpcport': 19792 + port_offset,
|
|
|
|
'datadir': os.path.join(data_dir, 'particl'),
|
|
|
|
'bindir': os.path.join(bin_dir, 'particl'),
|
|
|
|
'blocks_confirmed': 2,
|
|
|
|
'override_feerate': 0.002,
|
|
|
|
'conf_target': 2,
|
|
|
|
'core_version_group': 18,
|
|
|
|
'chain_lookups': 'local',
|
|
|
|
},
|
|
|
|
'litecoin': {
|
|
|
|
'connection_type': 'rpc' if 'litecoin' in with_coins else 'none',
|
|
|
|
'manage_daemon': True if 'litecoin' in with_coins else False,
|
|
|
|
'rpcport': 19795 + port_offset,
|
|
|
|
'datadir': os.path.join(data_dir, 'litecoin'),
|
|
|
|
'bindir': os.path.join(bin_dir, 'litecoin'),
|
|
|
|
'use_segwit': True,
|
|
|
|
'blocks_confirmed': 2,
|
|
|
|
'conf_target': 2,
|
|
|
|
'core_version_group': 17,
|
|
|
|
'chain_lookups': 'local',
|
|
|
|
},
|
|
|
|
'bitcoin': {
|
|
|
|
'connection_type': 'rpc' if 'bitcoin' in with_coins else 'none',
|
|
|
|
'manage_daemon': True if 'bitcoin' in with_coins else False,
|
|
|
|
'rpcport': 19796 + port_offset,
|
|
|
|
'datadir': os.path.join(data_dir, 'bitcoin'),
|
|
|
|
'bindir': os.path.join(bin_dir, 'bitcoin'),
|
|
|
|
'use_segwit': True,
|
|
|
|
'blocks_confirmed': 1,
|
|
|
|
'conf_target': 2,
|
|
|
|
'core_version_group': 18,
|
|
|
|
'chain_lookups': 'local',
|
|
|
|
},
|
|
|
|
'namecoin': {
|
|
|
|
'connection_type': 'rpc' if 'namecoin' in with_coins else 'none',
|
|
|
|
'manage_daemon': True if 'namecoin' in with_coins else False,
|
|
|
|
'rpcport': 19798 + port_offset,
|
|
|
|
'datadir': os.path.join(data_dir, 'namecoin'),
|
|
|
|
'bindir': os.path.join(bin_dir, 'namecoin'),
|
|
|
|
'use_segwit': False,
|
|
|
|
'use_csv': False,
|
|
|
|
'blocks_confirmed': 1,
|
|
|
|
'conf_target': 2,
|
|
|
|
'core_version_group': 18,
|
|
|
|
'chain_lookups': 'local',
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if disable_coin != '':
|
|
|
|
logger.info('Disabling coin: %s', disable_coin)
|
|
|
|
if not os.path.exists(config_path):
|
|
|
|
exitWithError('{} does not exist'.format(config_path))
|
|
|
|
with open(config_path) as fs:
|
|
|
|
settings = json.load(fs)
|
|
|
|
|
|
|
|
if disable_coin not in settings['chainclients']:
|
|
|
|
exitWithError('{} has not been prepared'.format(disable_coin))
|
|
|
|
settings['chainclients'][disable_coin]['connection_type'] = 'none'
|
|
|
|
settings['chainclients'][disable_coin]['manage_daemon'] = False
|
|
|
|
|
|
|
|
with open(config_path, 'w') as fp:
|
|
|
|
json.dump(settings, fp, indent=4)
|
|
|
|
|
|
|
|
logger.info('Done.')
|
|
|
|
return 0
|
|
|
|
|
|
|
|
if add_coin != '':
|
|
|
|
logger.info('Adding coin: %s', add_coin)
|
|
|
|
if not os.path.exists(config_path):
|
|
|
|
exitWithError('{} does not exist'.format(config_path))
|
|
|
|
with open(config_path) as fs:
|
|
|
|
settings = json.load(fs)
|
|
|
|
|
|
|
|
if add_coin in settings['chainclients']:
|
|
|
|
coin_settings = settings['chainclients'][add_coin]
|
|
|
|
if coin_settings['connection_type'] == 'none' and coin_settings['manage_daemon'] is False:
|
|
|
|
logger.info('Enabling coin: %s', add_coin)
|
|
|
|
coin_settings['connection_type'] = 'rpc'
|
|
|
|
coin_settings['manage_daemon'] = True
|
|
|
|
with open(config_path, 'w') as fp:
|
|
|
|
json.dump(settings, fp, indent=4)
|
|
|
|
logger.info('Done.')
|
|
|
|
return 0
|
|
|
|
exitWithError('{} is already in the settings file'.format(add_coin))
|
|
|
|
|
|
|
|
settings['chainclients'][add_coin] = chainclients[add_coin]
|
|
|
|
|
|
|
|
prepareCore(add_coin, known_coins[add_coin], settings, data_dir)
|
|
|
|
|
|
|
|
if not prepare_bin_only:
|
|
|
|
prepareDataDir(add_coin, settings, data_dir, chain, particl_wallet_mnemonic)
|
|
|
|
with open(config_path, 'w') as fp:
|
|
|
|
json.dump(settings, fp, indent=4)
|
|
|
|
|
|
|
|
logger.info('Done.')
|
|
|
|
return 0
|
|
|
|
|
|
|
|
logger.info('With coins: %s', ', '.join(with_coins))
|
|
|
|
if os.path.exists(config_path):
|
|
|
|
if not prepare_bin_only:
|
|
|
|
exitWithError('{} exists'.format(config_path))
|
|
|
|
else:
|
|
|
|
with open(config_path) as fs:
|
|
|
|
settings = json.load(fs)
|
|
|
|
else:
|
|
|
|
for c in with_coins:
|
|
|
|
withchainclients[c] = chainclients[c]
|
|
|
|
|
|
|
|
settings = {
|
|
|
|
'debug': True,
|
|
|
|
'zmqhost': 'tcp://127.0.0.1',
|
|
|
|
'zmqport': 20792 + port_offset,
|
|
|
|
'htmlhost': 'localhost',
|
|
|
|
'htmlport': 12700 + port_offset,
|
|
|
|
'network_key': '7sW2UEcHXvuqEjkpE5mD584zRaQYs6WXYohue4jLFZPTvMSxwvgs',
|
|
|
|
'network_pubkey': '035758c4a22d7dd59165db02a56156e790224361eb3191f02197addcb3bde903d2',
|
|
|
|
'chainclients': withchainclients,
|
|
|
|
'auto_reply_delay_min': 5, # Min delay before sending a response message
|
|
|
|
'auto_reply_delay_max': 50, # Max delay before sending a response message
|
|
|
|
'check_progress_seconds': 60,
|
|
|
|
'check_watched_seconds': 60,
|
|
|
|
'check_expired_seconds': 60
|
|
|
|
}
|
|
|
|
|
|
|
|
for c in with_coins:
|
|
|
|
prepareCore(c, known_coins[c], settings, data_dir)
|
|
|
|
|
|
|
|
if prepare_bin_only:
|
|
|
|
logger.info('Done.')
|
|
|
|
return 0
|
|
|
|
|
|
|
|
for c in with_coins:
|
|
|
|
prepareDataDir(c, settings, data_dir, chain, particl_wallet_mnemonic)
|
|
|
|
|
|
|
|
with open(config_path, 'w') as fp:
|
|
|
|
json.dump(settings, fp, indent=4)
|
|
|
|
|
|
|
|
if particl_wallet_mnemonic == 'none':
|
|
|
|
logger.info('Done.')
|
|
|
|
return 0
|
|
|
|
|
|
|
|
logger.info('Loading Particl mnemonic')
|
|
|
|
|
|
|
|
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'])
|
|
|
|
try:
|
|
|
|
waitForRPC(partRpc)
|
|
|
|
|
|
|
|
if particl_wallet_mnemonic is None:
|
|
|
|
particl_wallet_mnemonic = partRpc('mnemonic new')['mnemonic']
|
|
|
|
partRpc('extkeyimportmaster "{}"'.format(particl_wallet_mnemonic))
|
|
|
|
finally:
|
|
|
|
logger.info('Terminating {}'.format(d.pid))
|
|
|
|
d.terminate()
|
|
|
|
d.wait(timeout=120)
|
|
|
|
if d.stdout:
|
|
|
|
d.stdout.close()
|
|
|
|
if d.stderr:
|
|
|
|
d.stderr.close()
|
|
|
|
if d.stdin:
|
|
|
|
d.stdin.close()
|
|
|
|
|
|
|
|
logger.info('IMPORTANT - Save your particl wallet recovery phrase:\n{}\n'.format(particl_wallet_mnemonic))
|
|
|
|
|
|
|
|
logger.info('Done.')
|
|
|
|
|
|
|
|
|
|
|
|
if __name__ == '__main__':
|
|
|
|
main()
|