parent
f1efb0a317
commit
76af4a941e
12 changed files with 378 additions and 201 deletions
@ -0,0 +1,117 @@ |
||||
#!/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. |
||||
|
||||
""" |
||||
Particl Atomic Swap - Proof of Concept |
||||
|
||||
sudo pip install python-gnupg |
||||
|
||||
""" |
||||
|
||||
import sys |
||||
import os |
||||
import subprocess |
||||
import time |
||||
import json |
||||
import hashlib |
||||
import mmap |
||||
import tarfile |
||||
import urllib.request |
||||
import urllib.parse |
||||
import logging |
||||
|
||||
import gnupg |
||||
|
||||
|
||||
logger = logging.getLogger() |
||||
logger.level = logging.DEBUG |
||||
|
||||
|
||||
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('\n--version, -v Print version.') |
||||
logger.info('\n--datadir=PATH Path to basicswap data directory, default:~/.basicswap.') |
||||
logger.info('\n--mainnet Run in mainnet mode.') |
||||
logger.info('\n--testnet Run in testnet mode.') |
||||
logger.info('\n--regtest Run in regtest mode.') |
||||
logger.info('\n--particl_mnemonic= Recovery phrase to use for the Particl wallet, default is randomly generated.') |
||||
|
||||
|
||||
def main(): |
||||
print('main') |
||||
data_dir = None |
||||
chain = 'mainnet' |
||||
particl_wallet_mnemonic = None |
||||
|
||||
for v in sys.argv[1:]: |
||||
if len(v) < 2 or v[0] != '-': |
||||
logger.warning('Unknown argument', v) |
||||
continue |
||||
|
||||
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 len(s) == 2: |
||||
if name == 'datadir': |
||||
data_dir = os.path.expanduser(s[1]) |
||||
continue |
||||
if name == 'particl_mnemonic': |
||||
particl_wallet_mnemonic = s[1] |
||||
continue |
||||
|
||||
logger.warning('Unknown argument', v) |
||||
|
||||
if data_dir is None: |
||||
default_datadir = '~/.basicswap' |
||||
data_dir = os.path.join(os.path.expanduser(default_datadir)) |
||||
logger.info('Using datadir: %s', data_dir) |
||||
logger.info('Chain: %s', chain) |
||||
|
||||
if not os.path.exists(data_dir): |
||||
os.makedirs(data_dir) |
||||
|
||||
config_path = os.path.join(data_dir, 'basicswap.json') |
||||
if os.path.exists(config_path): |
||||
sys.stderr.write('Error: {} exists, exiting.'.format(config_path)) |
||||
exit(1) |
||||
|
||||
settings = { |
||||
'debug': True, |
||||
} |
||||
|
||||
with open(config_path, 'w') as fp: |
||||
json.dump(settings, fp, indent=4) |
||||
|
||||
logger.info('Done.') |
||||
|
||||
if __name__ == '__main__': |
||||
main() |
@ -1 +0,0 @@ |
||||
basicswap_run.py |
@ -0,0 +1,181 @@ |
||||
#!/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. |
||||
|
||||
""" |
||||
Particl Atomic Swap - Proof of Concept |
||||
|
||||
Dependencies: |
||||
$ pacman -S python-pyzmq python-plyvel protobuf |
||||
|
||||
""" |
||||
|
||||
import sys |
||||
import os |
||||
import time |
||||
import json |
||||
import traceback |
||||
import signal |
||||
import subprocess |
||||
import logging |
||||
|
||||
import basicswap.config as cfg |
||||
from basicswap import __version__ |
||||
from basicswap.basicswap import BasicSwap |
||||
from basicswap.http_server import HttpThread |
||||
|
||||
|
||||
logger = logging.getLogger() |
||||
logger.level = logging.DEBUG |
||||
logger.addHandler(logging.StreamHandler(sys.stdout)) |
||||
|
||||
ALLOW_CORS = False |
||||
swap_client = None |
||||
|
||||
|
||||
def signal_handler(sig, frame): |
||||
logger.info('Signal %d detected, ending program.' % (sig)) |
||||
if swap_client is not None: |
||||
swap_client.stopRunning() |
||||
|
||||
|
||||
def startDaemon(node_dir, bin_dir, daemon_bin): |
||||
daemon_bin = os.path.join(bin_dir, daemon_bin) |
||||
|
||||
args = [daemon_bin, '-datadir=' + node_dir] |
||||
logger.info('Starting node ' + daemon_bin + ' ' + '-datadir=' + node_dir) |
||||
return subprocess.Popen(args, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) |
||||
|
||||
|
||||
def runClient(fp, dataDir, chain): |
||||
global swap_client |
||||
settings_path = os.path.join(dataDir, 'basicswap.json') |
||||
|
||||
if not os.path.exists(settings_path): |
||||
raise ValueError('Settings file not found: ' + str(settings_path)) |
||||
|
||||
with open(settings_path) as fs: |
||||
settings = json.load(fs) |
||||
|
||||
daemons = [] |
||||
|
||||
for c, v in settings['chainclients'].items(): |
||||
if v['manage_daemon'] is True: |
||||
logger.info('Starting {} daemon'.format(c.capitalize())) |
||||
if c == 'particl': |
||||
daemons.append(startDaemon(v['datadir'], cfg.PARTICL_BINDIR, cfg.PARTICLD)) |
||||
logger.info('Started {} {}'.format(cfg.PARTICLD, daemons[-1].pid)) |
||||
elif c == 'bitcoin': |
||||
daemons.append(startDaemon(v['datadir'], cfg.BITCOIN_BINDIR, cfg.BITCOIND)) |
||||
logger.info('Started {} {}'.format(cfg.BITCOIND, daemons[-1].pid)) |
||||
elif c == 'litecoin': |
||||
daemons.append(startDaemon(v['datadir'], cfg.LITECOIN_BINDIR, cfg.LITECOIND)) |
||||
logger.info('Started {} {}'.format(cfg.LITECOIND, daemons[-1].pid)) |
||||
else: |
||||
logger.warning('Unknown chain', c) |
||||
|
||||
swap_client = BasicSwap(fp, dataDir, settings, chain) |
||||
|
||||
signal.signal(signal.SIGINT, signal_handler) |
||||
signal.signal(signal.SIGTERM, signal_handler) |
||||
swap_client.start() |
||||
|
||||
threads = [] |
||||
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 |
||||
tS1 = HttpThread(fp, settings['htmlhost'], settings['htmlport'], allow_cors, swap_client) |
||||
threads.append(tS1) |
||||
tS1.start() |
||||
|
||||
try: |
||||
logger.info('Exit with Ctrl + c.') |
||||
while swap_client.is_running: |
||||
time.sleep(0.5) |
||||
swap_client.update() |
||||
except Exception: |
||||
traceback.print_exc() |
||||
|
||||
swap_client.log.info('Stopping threads.') |
||||
for t in threads: |
||||
t.stop() |
||||
t.join() |
||||
|
||||
for d in daemons: |
||||
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() |
||||
|
||||
|
||||
def printVersion(): |
||||
logger.info('Basicswap version:', __version__) |
||||
|
||||
|
||||
def printHelp(): |
||||
logger.info('basicswap-run.py --datadir=path -testnet') |
||||
|
||||
|
||||
def main(): |
||||
data_dir = None |
||||
chain = 'mainnet' |
||||
|
||||
for v in sys.argv[1:]: |
||||
if len(v) < 2 or v[0] != '-': |
||||
logger.warning('Unknown argument', v) |
||||
continue |
||||
|
||||
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 == 'testnet': |
||||
chain = 'testnet' |
||||
continue |
||||
if name == 'regtest': |
||||
chain = 'regtest' |
||||
continue |
||||
|
||||
if len(s) == 2: |
||||
if name == 'datadir': |
||||
data_dir = os.path.expanduser(s[1]) |
||||
continue |
||||
|
||||
logger.warning('Unknown argument', v) |
||||
|
||||
if data_dir is None: |
||||
default_datadir = '~/.basicswap' |
||||
data_dir = os.path.join(os.path.expanduser(default_datadir)) |
||||
logger.info('Using datadir:', data_dir) |
||||
logger.info('Chain:', chain) |
||||
|
||||
if not os.path.exists(data_dir): |
||||
os.makedirs(data_dir) |
||||
|
||||
with open(os.path.join(data_dir, 'basicswap.log'), 'a') as fp: |
||||
logger.info(os.path.basename(sys.argv[0]) + ', version: ' + __version__ + '\n\n') |
||||
runClient(fp, data_dir, chain) |
||||
|
||||
logger.info('Done.') |
||||
return swap_client.fail_code if swap_client is not None else 0 |
||||
|
||||
|
||||
if __name__ == '__main__': |
||||
main() |
@ -1,182 +0,0 @@ |
||||
#!/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. |
||||
|
||||
""" |
||||
Particl Atomic Swap - Proof of Concept |
||||
|
||||
Dependencies: |
||||
$ pacman -S python-pyzmq python-plyvel protobuf |
||||
|
||||
""" |
||||
|
||||
import sys |
||||
import os |
||||
import time |
||||
import json |
||||
import traceback |
||||
import signal |
||||
import subprocess |
||||
import logging |
||||
|
||||
import basicswap.config as cfg |
||||
from basicswap import __version__ |
||||
from basicswap.basicswap import BasicSwap |
||||
from basicswap.http_server import HttpThread |
||||
|
||||
|
||||
logger = logging.getLogger() |
||||
logger.level = logging.DEBUG |
||||
logger.addHandler(logging.StreamHandler(sys.stdout)) |
||||
|
||||
ALLOW_CORS = False |
||||
swap_client = None |
||||
|
||||
|
||||
def signal_handler(sig, frame): |
||||
logger.info('Signal %d detected, ending program.' % (sig)) |
||||
if swap_client is not None: |
||||
swap_client.stopRunning() |
||||
|
||||
|
||||
def startDaemon(node_dir, bin_dir, daemon_bin): |
||||
daemon_bin = os.path.join(bin_dir, daemon_bin) |
||||
|
||||
args = [daemon_bin, '-datadir=' + node_dir] |
||||
logger.info('Starting node ' + daemon_bin + ' ' + '-datadir=' + node_dir) |
||||
return subprocess.Popen(args, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) |
||||
|
||||
|
||||
def runClient(fp, dataDir, chain): |
||||
global swap_client |
||||
settings_path = os.path.join(dataDir, 'basicswap.json') |
||||
|
||||
if not os.path.exists(settings_path): |
||||
raise ValueError('Settings file not found: ' + str(settings_path)) |
||||
|
||||
with open(settings_path) as fs: |
||||
settings = json.load(fs) |
||||
|
||||
daemons = [] |
||||
|
||||
for c, v in settings['chainclients'].items(): |
||||
if v['manage_daemon'] is True: |
||||
logger.info('Starting {} daemon'.format(c.capitalize())) |
||||
if c == 'particl': |
||||
daemons.append(startDaemon(v['datadir'], cfg.PARTICL_BINDIR, cfg.PARTICLD)) |
||||
logger.info('Started {} {}'.format(cfg.PARTICLD, daemons[-1].pid)) |
||||
elif c == 'bitcoin': |
||||
daemons.append(startDaemon(v['datadir'], cfg.BITCOIN_BINDIR, cfg.BITCOIND)) |
||||
logger.info('Started {} {}'.format(cfg.BITCOIND, daemons[-1].pid)) |
||||
elif c == 'litecoin': |
||||
daemons.append(startDaemon(v['datadir'], cfg.LITECOIN_BINDIR, cfg.LITECOIND)) |
||||
logger.info('Started {} {}'.format(cfg.LITECOIND, daemons[-1].pid)) |
||||
else: |
||||
logger.warning('Unknown chain', c) |
||||
|
||||
swap_client = BasicSwap(fp, dataDir, settings, chain) |
||||
|
||||
signal.signal(signal.SIGINT, signal_handler) |
||||
signal.signal(signal.SIGTERM, signal_handler) |
||||
swap_client.start() |
||||
|
||||
threads = [] |
||||
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 |
||||
tS1 = HttpThread(fp, settings['htmlhost'], settings['htmlport'], allow_cors, swap_client) |
||||
threads.append(tS1) |
||||
tS1.start() |
||||
|
||||
try: |
||||
logger.info('Exit with Ctrl + c.') |
||||
while swap_client.is_running: |
||||
time.sleep(0.5) |
||||
swap_client.update() |
||||
except Exception: |
||||
traceback.print_exc() |
||||
|
||||
swap_client.log.info('Stopping threads.') |
||||
for t in threads: |
||||
t.stop() |
||||
t.join() |
||||
|
||||
for d in daemons: |
||||
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() |
||||
|
||||
|
||||
def printVersion(): |
||||
logger.info('Basicswap version:', __version__) |
||||
|
||||
|
||||
def printHelp(): |
||||
logger.info('basicswap-run.py --datadir=path -testnet') |
||||
|
||||
|
||||
def main(): |
||||
data_dir = None |
||||
chain = 'mainnet' |
||||
|
||||
for v in sys.argv[1:]: |
||||
if len(v) < 2 or v[0] != '-': |
||||
logger.warning('Unknown argument', v) |
||||
continue |
||||
|
||||
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 == 'testnet': |
||||
chain = 'testnet' |
||||
continue |
||||
if name == 'regtest': |
||||
chain = 'regtest' |
||||
continue |
||||
|
||||
if len(s) == 2: |
||||
if name == 'datadir': |
||||
data_dir = os.path.expanduser(s[1]) |
||||
continue |
||||
|
||||
logger.warning('Unknown argument', v) |
||||
|
||||
if data_dir is None: |
||||
data_dir = os.path.join(os.path.expanduser(os.path.join(cfg.DATADIRS)), 'particl', ('' if chain == 'mainnet' else chain), 'basicswap') |
||||
|
||||
print('data_dir:', data_dir) |
||||
if chain != 'mainnet': |
||||
logger.info('chain:', chain) |
||||
|
||||
if not os.path.exists(data_dir): |
||||
os.makedirs(data_dir) |
||||
|
||||
with open(os.path.join(data_dir, 'basicswap.log'), 'a') as fp: |
||||
logger.info(os.path.basename(sys.argv[0]) + ', version: ' + __version__ + '\n\n') |
||||
runClient(fp, data_dir, chain) |
||||
|
||||
logger.info('Done.') |
||||
return swap_client.fail_code if swap_client is not None else 0 |
||||
|
||||
|
||||
if __name__ == '__main__': |
||||
main() |
@ -1,11 +1,14 @@ |
||||
import unittest |
||||
|
||||
import tests.test_run |
||||
import tests.test_other |
||||
import tests.test_prepare |
||||
import tests.test_run |
||||
|
||||
|
||||
def test_suite(): |
||||
loader = unittest.TestLoader() |
||||
suite = loader.loadTestsFromModule(tests.test_run) |
||||
suite.addTests(loader.loadTestsFromModule(tests.test_other)) |
||||
suite.addTests(loader.loadTestsFromModule(tests.test_prepare)) |
||||
suite = loader.loadTestsFromModule(tests.test_run) |
||||
|
||||
return suite |
||||
|
@ -0,0 +1,51 @@ |
||||
#!/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. |
||||
|
||||
import os |
||||
import sys |
||||
import unittest |
||||
from unittest.mock import patch |
||||
from io import StringIO |
||||
import logging |
||||
import shutil |
||||
import importlib |
||||
|
||||
prepareSystem = importlib.import_module('bin.basicswap-prepare') |
||||
test_path = os.path.expanduser('~/test_basicswap') |
||||
|
||||
logger = logging.getLogger() |
||||
logger.level = logging.DEBUG |
||||
|
||||
|
||||
class Test(unittest.TestCase): |
||||
@classmethod |
||||
def tearDownClass(self): |
||||
try: |
||||
shutil.rmtree(test_path) |
||||
except Exception as e: |
||||
logger.warning('tearDownClass %s', str(e)) |
||||
|
||||
def test_no_overwrite(self): |
||||
testargs = ['basicswap-prepare', '-datadir=' + test_path] |
||||
with patch.object(sys, 'argv', testargs): |
||||
prepareSystem.main() |
||||
|
||||
self.assertTrue(os.path.exists(os.path.join(test_path, 'basicswap.json'))) |
||||
|
||||
testargs = ['basicswap-prepare', '-datadir=' + test_path] |
||||
with patch('sys.stderr', new=StringIO()) as fake_stderr: |
||||
with patch.object(sys, 'argv', testargs): |
||||
with self.assertRaises(SystemExit) as cm: |
||||
prepareSystem.main() |
||||
|
||||
self.assertEqual(cm.exception.code, 1) |
||||
logger.info('fake_stderr.getvalue() %s', fake_stderr.getvalue()) |
||||
self.assertTrue('exists, exiting' in fake_stderr.getvalue()) |
||||
|
||||
|
||||
if __name__ == '__main__': |
||||
unittest.main() |
Loading…
Reference in new issue