diff --git a/.travis.yml b/.travis.yml
index 6b29c61..dc6a34b 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -7,7 +7,7 @@ stages:
env:
global:
- TEST_DIR=~/test_basicswap2/
- - PARTICL_BINDIR=/opt/binaries/particl-0.18.1.1/bin/
+ - PARTICL_BINDIR=/opt/binaries/particl-0.18.1.2/bin/
- BITCOIN_BINDIR=/opt/binaries/bitcoin-0.18.0/bin/
- LITECOIN_BINDIR=/opt/binaries/litecoin-0.17.1/bin/
before_install:
@@ -16,10 +16,10 @@ before_script:
- if [ ! -d "/opt/binaries" ]; then mkdir -p "/opt/binaries" ; fi
- if [ ! -d "$BITCOIN_BINDIR" ]; then cd "/opt/binaries" && wget https://bitcoincore.org/bin/bitcoin-core-0.18.0/bitcoin-0.18.0-x86_64-linux-gnu.tar.gz && tar xvf bitcoin-0.18.0-x86_64-linux-gnu.tar.gz ; fi
- if [ ! -d "$LITECOIN_BINDIR" ]; then cd "/opt/binaries" && wget https://download.litecoin.org/litecoin-0.17.1/linux/litecoin-0.17.1-x86_64-linux-gnu.tar.gz && tar xvf litecoin-0.17.1-x86_64-linux-gnu.tar.gz ; fi
- - if [ ! -d "$PARTICL_BINDIR" ]; then cd "/opt/binaries" && wget https://github.com/particl/particl-core/releases/download/v0.18.1.1/particl-0.18.1.1-x86_64-linux-gnu_nousb.tar.gz && tar xvf particl-0.18.1.1-x86_64-linux-gnu_nousb.tar.gz ; fi
+ - if [ ! -d "$PARTICL_BINDIR" ]; then cd "/opt/binaries" && wget https://github.com/particl/particl-core/releases/download/v0.18.1.2/particl-0.18.1.2-x86_64-linux-gnu_nousb.tar.gz && tar xvf particl-0.18.1.2-x86_64-linux-gnu_nousb.tar.gz ; fi
script:
- cd $TRAVIS_BUILD_DIR
- - export PARTICL_BINDIR=/opt/binaries/particl-0.18.1.1/bin/
+ - export PARTICL_BINDIR=/opt/binaries/particl-0.18.1.2/bin/
- export BITCOIN_BINDIR=/opt/binaries/bitcoin-0.18.0/bin/
- export LITECOIN_BINDIR=/opt/binaries/litecoin-0.17.1/bin/
- export DATADIRS=~/test_basicswap2/
diff --git a/basicswap/http_server.py b/basicswap/http_server.py
index 64f246f..b3a3fd0 100644
--- a/basicswap/http_server.py
+++ b/basicswap/http_server.py
@@ -123,7 +123,7 @@ def validateAmountString(amount):
if type(amount) != str:
return
ar = amount.split('.')
- if len(ar) > 0 and len(ar[1]) > 8:
+ if len(ar) > 1 and len(ar[1]) > 8:
raise ValueError('Too many decimal places in amount {}'.format(amount))
@@ -166,18 +166,28 @@ class HttpHandler(BaseHTTPRequestHandler):
error_str_json = json.dumps({'error': error_str})
return bytes(error_str_json, 'UTF-8')
- def js_wallets(self, url_split):
+ def js_wallets(self, url_split, post_string):
return bytes(json.dumps(self.server.swap_client.getWalletsInfo()), 'UTF-8')
- def js_offers(self, url_split):
+ def js_offers(self, url_split, post_string):
+ if len(url_split) > 3:
+ if url_split[3] == 'new':
+ if post_string == '':
+ raise ValueError('No post data')
+ form_data = urllib.parse.parse_qs(post_string)
+ offer_id = self.postNewOffer(form_data)
+ rv = {'offer_id': offer_id.hex()}
+ return bytes(json.dumps(rv), 'UTF-8')
+ offer_id = bytes.fromhex(url_split[3])
+
assert(False), 'TODO'
return bytes(json.dumps(self.server.swap_client.listOffers()), 'UTF-8')
- def js_sentoffers(self, url_split):
+ def js_sentoffers(self, url_split, post_string):
assert(False), 'TODO'
return bytes(json.dumps(self.server.swap_client.listOffers(sent=True)), 'UTF-8')
- def js_bids(self, url_split):
+ def js_bids(self, url_split, post_string):
if len(url_split) > 3:
bid_id = bytes.fromhex(url_split[3])
assert(len(bid_id) == 28)
@@ -185,10 +195,10 @@ class HttpHandler(BaseHTTPRequestHandler):
assert(False), 'TODO'
return bytes(json.dumps(self.server.swap_client.listBids()), 'UTF-8')
- def js_sentbids(self, url_split):
+ def js_sentbids(self, url_split, post_string):
return bytes(json.dumps(self.server.swap_client.listBids(sent=True)), 'UTF-8')
- def js_index(self, url_split):
+ def js_index(self, url_split, post_string):
return bytes(json.dumps(self.server.swap_client.getSummary()), 'UTF-8')
def page_explorers(self, url_split, post_string):
@@ -357,47 +367,52 @@ class HttpHandler(BaseHTTPRequestHandler):
form_id=os.urandom(8).hex(),
), 'UTF-8')
+ def postNewOffer(self, form_data):
+ swap_client = self.server.swap_client
+ addr_from = form_data[b'addr_from'][0].decode('utf-8')
+ if addr_from == '-1':
+ addr_from = None
+
+ try:
+ coin_from = Coins(int(form_data[b'coin_from'][0]))
+ except Exception:
+ raise ValueError('Unknown Coin From')
+ try:
+ coin_to = Coins(int(form_data[b'coin_to'][0]))
+ except Exception:
+ raise ValueError('Unknown Coin To')
+
+ value_from = form_data[b'amt_from'][0].decode('utf-8')
+ value_to = form_data[b'amt_to'][0].decode('utf-8')
+
+ validateAmountString(value_from)
+ validateAmountString(value_to)
+ value_from = makeInt(value_from)
+ value_to = makeInt(value_to)
+
+ min_bid = int(value_from)
+ rate = int((value_to / value_from) * COIN)
+ autoaccept = True if b'autoaccept' in form_data else False
+ lock_seconds = int(form_data[b'lockhrs'][0]) * 60 * 60
+ # TODO: More accurate rate
+ # assert(value_to == (value_from * rate) // COIN)
+
+ if swap_client.coin_clients[coin_from]['use_csv'] and swap_client.coin_clients[coin_to]['use_csv']:
+ lock_type = SEQUENCE_LOCK_TIME
+ else:
+ lock_type = ABS_LOCK_TIME
+
+ offer_id = swap_client.postOffer(coin_from, coin_to, value_from, rate, min_bid, SwapTypes.SELLER_FIRST, lock_type=lock_type, lock_value=lock_seconds, auto_accept_bids=autoaccept, addr_send_from=addr_from)
+ return offer_id
+
def page_newoffer(self, url_split, post_string):
swap_client = self.server.swap_client
messages = []
form_data = self.checkForm(post_string, 'newoffer', messages)
if form_data:
- addr_from = form_data[b'addr_from'][0].decode('utf-8')
- if addr_from == '-1':
- addr_from = None
-
- try:
- coin_from = Coins(int(form_data[b'coin_from'][0]))
- except Exception:
- raise ValueError('Unknown Coin From')
- try:
- coin_to = Coins(int(form_data[b'coin_to'][0]))
- except Exception:
- raise ValueError('Unknown Coin To')
-
- value_from = form_data[b'amt_from'][0].decode('utf-8')
- value_to = form_data[b'amt_to'][0].decode('utf-8')
-
- validateAmountString(value_from)
- validateAmountString(value_to)
- value_from = makeInt(value_from)
- value_to = makeInt(value_to)
-
- min_bid = int(value_from)
- rate = int((value_to / value_from) * COIN)
- autoaccept = True if b'autoaccept' in form_data else False
- lock_seconds = int(form_data[b'lockhrs'][0]) * 60 * 60
- # TODO: More accurate rate
- # assert(value_to == (value_from * rate) // COIN)
-
- if swap_client.coin_clients[coin_from]['use_csv'] and swap_client.coin_clients[coin_to]['use_csv']:
- lock_type = SEQUENCE_LOCK_TIME
- else:
- lock_type = ABS_LOCK_TIME
-
- offer_id = swap_client.postOffer(coin_from, coin_to, value_from, rate, min_bid, SwapTypes.SELLER_FIRST, lock_type=lock_type, lock_value=lock_seconds, auto_accept_bids=autoaccept, addr_send_from=addr_from)
- messages.append('Sent Offer ' + offer_id.hex() + '
Rate: ' + format8(rate))
+ offer_id = self.postNewOffer(form_data)
+ messages.append('Sent Offer {}'.format(offer_id.hex()))
template = env.get_template('offer_new.html')
return bytes(template.render(
@@ -755,8 +770,10 @@ class HttpHandler(BaseHTTPRequestHandler):
'bids': self.js_bids,
'sentbids': self.js_sentbids,
}.get(url_split[2], self.js_index)
- return func(url_split)
+ return func(url_split, post_string)
except Exception as ex:
+ if self.server.swap_client.debug is True:
+ traceback.print_exc()
return self.js_error(str(ex))
try:
self.putHeaders(status_code, 'text/html')
@@ -793,7 +810,8 @@ class HttpHandler(BaseHTTPRequestHandler):
return self.page_shutdown(url_split, post_string)
return self.page_index(url_split)
except Exception as ex:
- traceback.print_exc() # TODO: Remove
+ if self.server.swap_client.debug is True:
+ traceback.print_exc()
return self.page_error(str(ex))
def do_GET(self):
diff --git a/bin/basicswap_prepare.py b/bin/basicswap_prepare.py
index 1557619..5c6ef60 100644
--- a/bin/basicswap_prepare.py
+++ b/bin/basicswap_prepare.py
@@ -40,7 +40,7 @@ else:
BIN_ARCH = 'x86_64-linux-gnu.tar.gz'
known_coins = {
- 'particl': '0.18.1.1',
+ 'particl': '0.18.1.2',
'litecoin': '0.17.1',
'bitcoin': '0.18.0',
'namecoin': '0.18.0',
@@ -247,6 +247,7 @@ def printHelp():
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.')
@@ -257,6 +258,7 @@ def printHelp():
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()))
@@ -293,6 +295,8 @@ def exitWithError(error_msg):
def main():
data_dir = None
+ bin_dir = None
+ port_offset = None
chain = 'mainnet'
particl_wallet_mnemonic = None
prepare_bin_only = False
@@ -331,10 +335,16 @@ def main():
if len(s) == 2:
if name == 'datadir':
- data_dir = os.path.expanduser(s[1])
+ 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]
+ particl_wallet_mnemonic = s[1].strip('"')
continue
if name == 'withcoin':
if s[1] not in known_coins:
@@ -363,9 +373,14 @@ def main():
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)
- port_offset = 300 if chain == 'testnet' else 0
+
+ if port_offset is None:
+ port_offset = 300 if chain == 'testnet' else 0
if not os.path.exists(data_dir):
os.makedirs(data_dir)
@@ -378,7 +393,7 @@ def main():
'manage_daemon': True,
'rpcport': 19792 + port_offset,
'datadir': os.path.join(data_dir, 'particl'),
- 'bindir': os.path.join(data_dir, 'bin', 'particl'),
+ 'bindir': os.path.join(bin_dir, 'particl'),
'blocks_confirmed': 2,
'override_feerate': 0.002,
'conf_target': 2,
@@ -390,7 +405,7 @@ def main():
'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(data_dir, 'bin', 'litecoin'),
+ 'bindir': os.path.join(bin_dir, 'litecoin'),
'use_segwit': True,
'blocks_confirmed': 2,
'conf_target': 2,
@@ -402,7 +417,7 @@ def main():
'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(data_dir, 'bin', 'bitcoin'),
+ 'bindir': os.path.join(bin_dir, 'bitcoin'),
'use_segwit': True,
'blocks_confirmed': 1,
'conf_target': 2,
@@ -414,7 +429,7 @@ def main():
'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(data_dir, 'bin', 'namecoin'),
+ 'bindir': os.path.join(bin_dir, 'namecoin'),
'use_segwit': False,
'use_csv': False,
'blocks_confirmed': 1,
diff --git a/tests/basicswap/test_reload.py b/tests/basicswap/test_reload.py
index bb581bc..a2eb34c 100644
--- a/tests/basicswap/test_reload.py
+++ b/tests/basicswap/test_reload.py
@@ -8,21 +8,25 @@
"""
mkdir -p /tmp/test_basicswap/bin/{particl,bitcoin}
-cp ~/tmp/particl-0.18.1.1-x86_64-linux-gnu.tar.gz /tmp/test_basicswap/bin/particl
+cp ~/tmp/particl-0.18.1.2-x86_64-linux-gnu.tar.gz /tmp/test_basicswap/bin/particl
cp ~/tmp/bitcoin-0.18.0-x86_64-linux-gnu.tar.gz /tmp/test_basicswap/bin/bitcoin
-
"""
import os
import sys
import time
import unittest
-from unittest.mock import patch
import logging
import shutil
import threading
+import json
+import traceback
+from unittest.mock import patch
+from urllib.request import urlopen
+from urllib import parse
+
import bin.basicswap_prepare as prepareSystem
import bin.basicswap_run as runSystem
@@ -34,41 +38,78 @@ if not len(logger.handlers):
logger.addHandler(logging.StreamHandler(sys.stdout))
+def waitForServer():
+ for i in range(20):
+ try:
+ time.sleep(1)
+ summary = json.loads(urlopen('http://localhost:12700/json').read())
+ break
+ except Exception:
+ traceback.print_exc()
+
+
class Test(unittest.TestCase):
@classmethod
def setUpClass(cls):
super(Test, cls).setUpClass()
- config_path = os.path.join(test_path, 'basicswap.json')
- try:
- os.remove(config_path)
- shutil.rmtree(os.path.join(test_path, 'particl'))
- shutil.rmtree(os.path.join(test_path, 'bitcoin'))
- except Exception as ex:
- logger.warning('setUpClass %s', str(ex))
+ mnemonics = [
+ 'abandon baby cabbage dad eager fabric gadget habit ice kangaroo lab absorb',
+ 'actuel comédie poésie noble facile éprouver brave cellule rotule académie hilarant chambre',
+ 'ちしき いてざ きおち あしあと ぽちぶくろ こえる さつえい むえき あける ほんき むさぼる ねいろ',
+ ]
- testargs = ['basicswap-prepare', '-datadir=' + test_path, '-regtest', '-withoutcoin=litecoin', '-withcoin=bitcoin']
- with patch.object(sys, 'argv', testargs):
- prepareSystem.main()
+ for i in range(3):
+ client_path = os.path.join(test_path, 'client{}'.format(i))
+ config_path = os.path.join(client_path, 'basicswap.json')
+ try:
+ shutil.rmtree(client_path)
+ except Exception as ex:
+ logger.warning('setUpClass %s', str(ex))
+ testargs = ['basicswap-prepare',
+ '-datadir="{}"'.format(client_path),
+ '-bindir="{}"'.format(test_path + '/bin'),
+ '-portoffset={}'.format(i),
+ '-particl_mnemonic="{}"'.format(mnemonics[i]),
+ '-regtest', '-withoutcoin=litecoin', '-withcoin=bitcoin']
+ with patch.object(sys, 'argv', testargs):
+ prepareSystem.main()
- assert(os.path.exists(config_path))
+ assert(os.path.exists(config_path))
- def run_thread(self):
- testargs = ['basicswap-run', '-datadir=' + test_path, '-regtest', '-testmode']
+ def run_thread(self, client_id):
+ client_path = os.path.join(test_path, 'client{}'.format(client_id))
+ testargs = ['basicswap-run', '-datadir=' + client_path, '-regtest', '-testmode']
with patch.object(sys, 'argv', testargs):
runSystem.main()
def test_reload(self):
- thread = threading.Thread(target=self.run_thread)
- thread.start()
+ thread0 = threading.Thread(target=self.run_thread, args=(0,))
+ thread0.start()
+
+ try:
+ waitForServer()
+ data = parse.urlencode({
+ 'addr_from': '-1',
+ 'coin_from': '1',
+ 'coin_to': '2',
+ '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)
+ except Exception:
+ traceback.print_exc()
logger.warning('TODO')
time.sleep(5)
runSystem.swap_client.stopRunning()
- thread.join()
+ thread0.join()
if __name__ == '__main__':