tecnovert
5 years ago
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