diff --git a/basicswap/basicswap.py b/basicswap/basicswap.py index 9bc9b92..814fad2 100644 --- a/basicswap/basicswap.py +++ b/basicswap/basicswap.py @@ -712,7 +712,7 @@ class BasicSwap(BaseApp): self.upgradeDatabase(self.db_version) for c in Coins: - if not c in chainparams: + if c not in chainparams: continue self.setCoinRunParams(c) self.createCoinInterface(c) @@ -780,7 +780,7 @@ class BasicSwap(BaseApp): def stopDaemons(self): for c in Coins: - if not c in chainparams: + if c not in chainparams: continue chain_client_settings = self.getChainClientSettings(c) if self.coin_clients[c]['connection_type'] == 'rpc' and chain_client_settings['manage_daemon'] is True: @@ -4893,8 +4893,9 @@ class BasicSwap(BaseApp): } if coin == Coins.PART: + rv['stealth_address'] = self.getCachedStealthAddressForCoin(Coins.PART) rv['anon_balance'] = walletinfo['anon_balance'] - rv['anon_unconfirmed'] = walletinfo['unconfirmed_anon'] + rv['anon_pending'] = walletinfo['unconfirmed_anon'] + walletinfo['immature_anon_balance'] rv['blind_balance'] = walletinfo['blind_balance'] rv['blind_unconfirmed'] = walletinfo['unconfirmed_blind'] @@ -4903,7 +4904,7 @@ class BasicSwap(BaseApp): def getWalletsInfo(self, opts=None): rv = {} for c in Coins: - if not c in chainparams: + if c not in chainparams: continue if self.coin_clients[c]['connection_type'] == 'rpc': try: diff --git a/basicswap/http_server.py b/basicswap/http_server.py index 66b38b7..dff3ff9 100644 --- a/basicswap/http_server.py +++ b/basicswap/http_server.py @@ -76,7 +76,7 @@ def extractDomain(url): def listAvailableExplorers(swap_client): explorers = [] for c in Coins: - if not c in chainparams: + if c not in chainparams: continue for i, e in enumerate(swap_client.coin_clients[c]['explorers']): explorers.append(('{}_{}'.format(int(c), i), swap_client.coin_clients[c]['name'].capitalize() + ' - ' + extractDomain(e.base_url))) @@ -220,7 +220,7 @@ class HttpHandler(BaseHTTPRequestHandler): form_data = self.checkForm(post_string, 'wallets', messages) if form_data: for c in Coins: - if not c in chainparams: + if c not in chainparams: continue cid = str(int(c)) @@ -304,13 +304,12 @@ class HttpHandler(BaseHTTPRequestHandler): wf['unconfirmed'] = w['unconfirmed'] if k == Coins.PART: - wf['stealth_address'] = swap_client.getCachedStealthAddressForCoin(Coins.PART) wf['blind_balance'] = w['blind_balance'] if float(w['blind_unconfirmed']) > 0.0: wf['blind_unconfirmed'] = w['blind_unconfirmed'] wf['anon_balance'] = w['anon_balance'] - if float(w['anon_unconfirmed']) > 0.0: - wf['anon_unconfirmed'] = w['anon_unconfirmed'] + if float(w['anon_pending']) > 0.0: + wf['anon_pending'] = w['anon_pending'] if 'wd_type_from_' + cid in page_data: wf['wd_type_from'] = page_data['wd_type_from_' + cid] diff --git a/basicswap/interface_part.py b/basicswap/interface_part.py index 7d358c1..82373c1 100644 --- a/basicswap/interface_part.py +++ b/basicswap/interface_part.py @@ -97,4 +97,3 @@ class PARTInterfaceAnon(PARTInterface): @staticmethod def balance_type(): return BalanceTypes.ANON - diff --git a/basicswap/js_server.py b/basicswap/js_server.py index 5ac3da1..1fc37de 100644 --- a/basicswap/js_server.py +++ b/basicswap/js_server.py @@ -8,19 +8,25 @@ import json import urllib.parse from .util import ( + toBool, format_timestamp, ) from .basicswap import ( strBidState, SwapTypes, ) +from .chainparams import ( + Coins, +) from .ui import ( PAGE_LIMIT, inputAmount, describeBid, setCoinFilter, get_data_entry, + get_data_entry_or, have_data_entry, + tickerToCoinId, ) @@ -29,8 +35,40 @@ def js_error(self, error_str): return bytes(error_str_json, 'UTF-8') +def withdraw_coin(swap_client, coin_type, post_string, is_json): + if is_json: + post_data = json.loads(post_string) + post_data['is_json'] = True + else: + post_data = urllib.parse.parse_qs(post_string) + + value = get_data_entry(post_data, 'value') + address = get_data_entry(post_data, 'address') + subfee = get_data_entry(post_data, 'subfee') + if not isinstance(subfee, bool): + subfee = toBool(subfee) + + if coin_type == Coins.PART: + type_from = get_data_entry_or(post_data, 'type_from', 'plain') + type_to = get_data_entry_or(post_data, 'type_to', 'plain') + txid_hex = swap_client.withdrawParticl(type_from, type_to, value, address, subfee) + else: + txid_hex = swap_client.withdrawCoin(coin_type, value, address, subfee) + + return {'txid': txid_hex} + + def js_wallets(self, url_split, post_string, is_json): - # TODO: Withdrawals + if len(url_split) > 3: + ticker_str = url_split[3] + coin_type = tickerToCoinId(ticker_str) + + if len(url_split) > 4: + cmd = url_split[4] + if cmd == 'withdraw': + return bytes(json.dumps(withdraw_coin(self.server.swap_client, coin_type, post_string, is_json)), 'UTF-8') + raise ValueError('Unknown command') + return bytes(json.dumps(self.server.swap_client.getWalletInfo(coin_type)), 'UTF-8') return bytes(json.dumps(self.server.swap_client.getWalletsInfo()), 'UTF-8') diff --git a/basicswap/templates/wallets.html b/basicswap/templates/wallets.html index a8566c1..8c56d5a 100644 --- a/basicswap/templates/wallets.html +++ b/basicswap/templates/wallets.html @@ -22,7 +22,7 @@ {% if w.cid == '1' %} Blind Balance:{{ w.blind_balance }}{% if w.blind_unconfirmed %}Blind Unconfirmed:{{ w.blind_unconfirmed }}{% endif %} -Anon Balance:{{ w.anon_balance }}{% if w.anon_unconfirmed %}Anon Unconfirmed:{{ w.anon_unconfirmed }}{% endif %} +Anon Balance:{{ w.anon_balance }}{% if w.anon_pending %}Anon Pending:{{ w.anon_pending }}{% endif %} {% endif %} diff --git a/basicswap/ui.py b/basicswap/ui.py index c4c58c6..4c68d2c 100644 --- a/basicswap/ui.py +++ b/basicswap/ui.py @@ -56,6 +56,15 @@ def inputAmount(amount_str, ci): return make_int(amount_str, ci.exp()) +def get_data_entry_or(post_data, name, default): + if 'is_json' in post_data: + return post_data.get(name, default) + key_bytes = name.encode('utf-8') + if key_bytes in post_data: + return post_data[key_bytes][0].decode('utf-8') + return default + + def get_data_entry(post_data, name): if 'is_json' in post_data: return post_data[name] diff --git a/tests/basicswap/common.py b/tests/basicswap/common.py index 0b05039..a060a71 100644 --- a/tests/basicswap/common.py +++ b/tests/basicswap/common.py @@ -9,6 +9,7 @@ import os import json import signal import logging +import urllib from urllib.request import urlopen from basicswap.rpc import callrpc @@ -230,6 +231,26 @@ def waitForNumSwapping(delay_event, port, bids, wait_for=60): raise ValueError('waitForNumSwapping failed') +def wait_for_balance(delay_event, url, balance_key, expect_amount, iterations=20, delay_time=3): + i = 0 + while not delay_event.is_set(): + rv_js = json.loads(urlopen(url).read()) + if float(rv_js[balance_key]) >= expect_amount: + break + delay_event.wait(delay_time) + i += 1 + if i > iterations: + raise ValueError('Expect {} {}'.format(balance_key, expect_amount)) + + +def post_json_req(url, json_data): + req = urllib.request.Request(url) + req.add_header('Content-Type', 'application/json; charset=utf-8') + post_bytes = json.dumps(json_data).encode('utf-8') + req.add_header('Content-Length', len(post_bytes)) + return urlopen(req, post_bytes).read() + + def delay_for(delay_event, delay_for=60): logging.info('Delaying for {} seconds.'.format(delay_for)) delay_event.wait(delay_for) diff --git a/tests/basicswap/test_run.py b/tests/basicswap/test_run.py index ed01bc3..57b1606 100644 --- a/tests/basicswap/test_run.py +++ b/tests/basicswap/test_run.py @@ -16,7 +16,6 @@ $ pytest -v -s tests/basicswap/test_run.py::Test::test_04_ltc_btc import os import sys import json -import time import random import shutil import signal @@ -73,8 +72,7 @@ NUM_NODES = 3 LTC_NODE = 3 BTC_NODE = 4 -delay_event = threading.Event() -stop_test = False +test_delay_event = threading.Event() logger = logging.getLogger() @@ -215,27 +213,25 @@ def ltcRpc(cmd): def signal_handler(sig, frame): - global stop_test print('signal {} detected.'.format(sig)) - stop_test = True - delay_event.set() + test_delay_event.set() def run_coins_loop(cls): - while not stop_test: + while not test_delay_event.is_set(): try: ltcRpc('generatetoaddress 1 {}'.format(cls.ltc_addr)) btcRpc('generatetoaddress 1 {}'.format(cls.btc_addr)) except Exception as e: logging.warning('run_coins_loop ' + str(e)) - time.sleep(1.0) + test_delay_event.wait(1.0) def run_loop(cls): - while not stop_test: + while not test_delay_event.is_set(): for c in cls.swap_clients: c.update() - time.sleep(1) + test_delay_event.wait(1) def make_part_cli_rpc_func(node_id): @@ -358,14 +354,13 @@ class Test(unittest.TestCase): print('particl_blocks', particl_blocks) if particl_blocks >= num_blocks: break - delay_event.wait(1) + test_delay_event.wait(1) assert(particl_blocks >= num_blocks) @classmethod def tearDownClass(cls): - global stop_test logging.info('Finalising') - stop_test = True + test_delay_event.set() cls.update_thread.join() cls.coins_update_thread.join() for t in cls.http_threads: @@ -418,21 +413,21 @@ class Test(unittest.TestCase): offer_id = swap_clients[0].postOffer(Coins.PART, Coins.LTC, 100 * COIN, 0.1 * COIN, 100 * COIN, SwapTypes.SELLER_FIRST) - wait_for_offer(delay_event, swap_clients[1], offer_id) + wait_for_offer(test_delay_event, swap_clients[1], offer_id) offers = swap_clients[1].listOffers() assert(len(offers) == 1) for offer in offers: if offer.offer_id == offer_id: bid_id = swap_clients[1].postBid(offer_id, offer.amount_from) - wait_for_bid(delay_event, swap_clients[0], bid_id) + wait_for_bid(test_delay_event, swap_clients[0], bid_id) swap_clients[0].acceptBid(bid_id) - wait_for_in_progress(delay_event, swap_clients[1], bid_id, sent=True) + wait_for_in_progress(test_delay_event, swap_clients[1], bid_id, sent=True) - wait_for_bid(delay_event, swap_clients[0], bid_id, BidStates.SWAP_COMPLETED, wait_for=60) - wait_for_bid(delay_event, swap_clients[1], bid_id, BidStates.SWAP_COMPLETED, sent=True, wait_for=60) + wait_for_bid(test_delay_event, swap_clients[0], bid_id, BidStates.SWAP_COMPLETED, wait_for=60) + wait_for_bid(test_delay_event, swap_clients[1], bid_id, BidStates.SWAP_COMPLETED, sent=True, wait_for=60) js_0 = json.loads(urlopen('http://127.0.0.1:1800/json').read()) js_1 = json.loads(urlopen('http://127.0.0.1:1801/json').read()) @@ -445,17 +440,17 @@ class Test(unittest.TestCase): offer_id = swap_clients[1].postOffer(Coins.LTC, Coins.PART, 10 * COIN, 9.0 * COIN, 10 * COIN, SwapTypes.SELLER_FIRST) - wait_for_offer(delay_event, swap_clients[0], offer_id) + wait_for_offer(test_delay_event, swap_clients[0], offer_id) offer = swap_clients[0].getOffer(offer_id) bid_id = swap_clients[0].postBid(offer_id, offer.amount_from) - wait_for_bid(delay_event, swap_clients[1], bid_id) + wait_for_bid(test_delay_event, swap_clients[1], bid_id) swap_clients[1].acceptBid(bid_id) - wait_for_in_progress(delay_event, swap_clients[0], bid_id, sent=True) + wait_for_in_progress(test_delay_event, swap_clients[0], bid_id, sent=True) - wait_for_bid(delay_event, swap_clients[0], bid_id, BidStates.SWAP_COMPLETED, sent=True, wait_for=60) - wait_for_bid(delay_event, swap_clients[1], bid_id, BidStates.SWAP_COMPLETED, wait_for=60) + wait_for_bid(test_delay_event, swap_clients[0], bid_id, BidStates.SWAP_COMPLETED, sent=True, wait_for=60) + wait_for_bid(test_delay_event, swap_clients[1], bid_id, BidStates.SWAP_COMPLETED, wait_for=60) js_0 = json.loads(urlopen('http://127.0.0.1:1800/json').read()) js_1 = json.loads(urlopen('http://127.0.0.1:1801/json').read()) @@ -468,17 +463,17 @@ class Test(unittest.TestCase): offer_id = swap_clients[0].postOffer(Coins.LTC, Coins.BTC, 10 * COIN, 0.1 * COIN, 10 * COIN, SwapTypes.SELLER_FIRST) - wait_for_offer(delay_event, swap_clients[1], offer_id) + wait_for_offer(test_delay_event, swap_clients[1], offer_id) offer = swap_clients[1].getOffer(offer_id) bid_id = swap_clients[1].postBid(offer_id, offer.amount_from) - wait_for_bid(delay_event, swap_clients[0], bid_id) + wait_for_bid(test_delay_event, swap_clients[0], bid_id) swap_clients[0].acceptBid(bid_id) - wait_for_in_progress(delay_event, swap_clients[1], bid_id, sent=True) + wait_for_in_progress(test_delay_event, swap_clients[1], bid_id, sent=True) - wait_for_bid(delay_event, swap_clients[0], bid_id, BidStates.SWAP_COMPLETED, wait_for=60) - wait_for_bid(delay_event, swap_clients[1], bid_id, BidStates.SWAP_COMPLETED, sent=True, wait_for=60) + wait_for_bid(test_delay_event, swap_clients[0], bid_id, BidStates.SWAP_COMPLETED, wait_for=60) + wait_for_bid(test_delay_event, swap_clients[1], bid_id, BidStates.SWAP_COMPLETED, sent=True, wait_for=60) js_0bid = json.loads(urlopen('http://127.0.0.1:1800/json/bids/{}'.format(bid_id.hex())).read()) @@ -496,16 +491,16 @@ class Test(unittest.TestCase): offer_id = swap_clients[0].postOffer(Coins.LTC, Coins.BTC, 10 * COIN, 0.1 * COIN, 10 * COIN, SwapTypes.SELLER_FIRST, SEQUENCE_LOCK_BLOCKS, 10) - wait_for_offer(delay_event, swap_clients[1], offer_id) + wait_for_offer(test_delay_event, swap_clients[1], offer_id) offer = swap_clients[1].getOffer(offer_id) bid_id = swap_clients[1].postBid(offer_id, offer.amount_from) - wait_for_bid(delay_event, swap_clients[0], bid_id) + wait_for_bid(test_delay_event, swap_clients[0], bid_id) swap_clients[1].abandonBid(bid_id) swap_clients[0].acceptBid(bid_id) - wait_for_bid(delay_event, swap_clients[0], bid_id, BidStates.SWAP_COMPLETED, wait_for=60) - wait_for_bid(delay_event, swap_clients[1], bid_id, BidStates.BID_ABANDONED, sent=True, wait_for=60) + wait_for_bid(test_delay_event, swap_clients[0], bid_id, BidStates.SWAP_COMPLETED, wait_for=60) + wait_for_bid(test_delay_event, swap_clients[1], bid_id, BidStates.BID_ABANDONED, sent=True, wait_for=60) js_0_bid = json.loads(urlopen('http://127.0.0.1:1800/json/bids/{}'.format(bid_id.hex())).read()) js_1_bid = json.loads(urlopen('http://127.0.0.1:1801/json/bids/{}'.format(bid_id.hex())).read()) @@ -525,16 +520,16 @@ class Test(unittest.TestCase): offer_id = swap_clients[0].postOffer(Coins.BTC, Coins.LTC, 10 * COIN, 10 * COIN, 10 * COIN, SwapTypes.SELLER_FIRST) - wait_for_offer(delay_event, swap_clients[0], offer_id) + wait_for_offer(test_delay_event, swap_clients[0], offer_id) offer = swap_clients[0].getOffer(offer_id) offers = swap_clients[0].listOffers() bid_id = swap_clients[0].postBid(offer_id, offer.amount_from) - wait_for_bid(delay_event, swap_clients[0], bid_id) + wait_for_bid(test_delay_event, swap_clients[0], bid_id) swap_clients[0].acceptBid(bid_id) - wait_for_bid_tx_state(delay_event, swap_clients[0], bid_id, TxStates.TX_REDEEMED, TxStates.TX_REDEEMED, wait_for=60) - wait_for_bid(delay_event, swap_clients[0], bid_id, BidStates.SWAP_COMPLETED, wait_for=60) + wait_for_bid_tx_state(test_delay_event, swap_clients[0], bid_id, TxStates.TX_REDEEMED, TxStates.TX_REDEEMED, wait_for=60) + wait_for_bid(test_delay_event, swap_clients[0], bid_id, BidStates.SWAP_COMPLETED, wait_for=60) js_0 = json.loads(urlopen('http://127.0.0.1:1800/json').read()) assert(js_0['num_swapping'] == 0 and js_0['num_watched_outputs'] == 0) @@ -548,16 +543,16 @@ class Test(unittest.TestCase): offer_id = swap_clients[0].postOffer(Coins.BTC, Coins.LTC, 0.001 * COIN, 1.0 * COIN, 0.001 * COIN, SwapTypes.SELLER_FIRST) - wait_for_offer(delay_event, swap_clients[0], offer_id) + wait_for_offer(test_delay_event, swap_clients[0], offer_id) offer = swap_clients[0].getOffer(offer_id) bid_id = swap_clients[0].postBid(offer_id, offer.amount_from) - wait_for_bid(delay_event, swap_clients[0], bid_id) + wait_for_bid(test_delay_event, swap_clients[0], bid_id) swap_clients[0].acceptBid(bid_id) swap_clients[0].getChainClientSettings(Coins.BTC)['override_feerate'] = 10.0 swap_clients[0].getChainClientSettings(Coins.LTC)['override_feerate'] = 10.0 - wait_for_bid(delay_event, swap_clients[0], bid_id, BidStates.BID_ERROR, wait_for=60) + wait_for_bid(test_delay_event, swap_clients[0], bid_id, BidStates.BID_ERROR, wait_for=60) swap_clients[0].abandonBid(bid_id) del swap_clients[0].getChainClientSettings(Coins.BTC)['override_feerate'] @@ -577,15 +572,15 @@ class Test(unittest.TestCase): offer_id = swap_clients[0].postOffer(Coins.PART, Coins.LTC, 100 * COIN, 0.1 * COIN, 100 * COIN, SwapTypes.SELLER_FIRST, auto_accept_bids=True) - wait_for_offer(delay_event, swap_clients[1], offer_id) + wait_for_offer(test_delay_event, swap_clients[1], offer_id) offers = swap_clients[1].listOffers() assert(len(offers) >= 1) for offer in offers: if offer.offer_id == offer_id: bid_id = swap_clients[1].postBid(offer_id, offer.amount_from) - wait_for_bid(delay_event, swap_clients[0], bid_id, BidStates.SWAP_COMPLETED, wait_for=60) - wait_for_bid(delay_event, swap_clients[1], bid_id, BidStates.SWAP_COMPLETED, sent=True, wait_for=60) + wait_for_bid(test_delay_event, swap_clients[0], bid_id, BidStates.SWAP_COMPLETED, wait_for=60) + wait_for_bid(test_delay_event, swap_clients[1], bid_id, BidStates.SWAP_COMPLETED, sent=True, wait_for=60) def test_10_bad_ptx(self): # Invalid PTX sent, swap should stall and ITx and PTx should be reclaimed by senders @@ -597,16 +592,16 @@ class Test(unittest.TestCase): offer_id = swap_clients[0].postOffer(Coins.LTC, Coins.BTC, swap_value, 0.1 * COIN, swap_value, SwapTypes.SELLER_FIRST, SEQUENCE_LOCK_BLOCKS, 10) - wait_for_offer(delay_event, swap_clients[1], offer_id) + wait_for_offer(test_delay_event, swap_clients[1], offer_id) offer = swap_clients[1].getOffer(offer_id) bid_id = swap_clients[1].postBid(offer_id, offer.amount_from) swap_clients[1].setBidDebugInd(bid_id, DebugTypes.MAKE_INVALID_PTX) - wait_for_bid(delay_event, swap_clients[0], bid_id) + wait_for_bid(test_delay_event, swap_clients[0], bid_id) swap_clients[0].acceptBid(bid_id) - wait_for_bid(delay_event, swap_clients[0], bid_id, BidStates.SWAP_COMPLETED, wait_for=120) - wait_for_bid(delay_event, swap_clients[1], bid_id, BidStates.SWAP_COMPLETED, sent=True, wait_for=120) + wait_for_bid(test_delay_event, swap_clients[0], bid_id, BidStates.SWAP_COMPLETED, wait_for=120) + wait_for_bid(test_delay_event, swap_clients[1], bid_id, BidStates.SWAP_COMPLETED, sent=True, wait_for=120) js_0_bid = json.loads(urlopen('http://127.0.0.1:1800/json/bids/{}'.format(bid_id.hex())).read()) js_1_bid = json.loads(urlopen('http://127.0.0.1:1801/json/bids/{}'.format(bid_id.hex())).read()) @@ -629,16 +624,16 @@ class Test(unittest.TestCase): offer_id = swap_clients[0].postOffer(Coins.LTC, Coins.BTC, swap_value, 0.1 * COIN, swap_value, SwapTypes.SELLER_FIRST, SEQUENCE_LOCK_BLOCKS, 10) - wait_for_offer(delay_event, swap_clients[1], offer_id) + wait_for_offer(test_delay_event, swap_clients[1], offer_id) offer = swap_clients[1].getOffer(offer_id) bid_id = swap_clients[1].postBid(offer_id, offer.amount_from) swap_clients[1].setBidDebugInd(bid_id, DebugTypes.BUYER_STOP_AFTER_ITX) - wait_for_bid(delay_event, swap_clients[0], bid_id) + wait_for_bid(test_delay_event, swap_clients[0], bid_id) swap_clients[0].acceptBid(bid_id) - wait_for_bid(delay_event, swap_clients[0], bid_id, BidStates.SWAP_COMPLETED, wait_for=120) - wait_for_bid(delay_event, swap_clients[1], bid_id, BidStates.BID_ABANDONED, sent=True, wait_for=120) + wait_for_bid(test_delay_event, swap_clients[0], bid_id, BidStates.SWAP_COMPLETED, wait_for=120) + wait_for_bid(test_delay_event, swap_clients[1], bid_id, BidStates.BID_ABANDONED, sent=True, wait_for=120) js_0_bid = json.loads(urlopen('http://127.0.0.1:1800/json/bids/{}'.format(bid_id.hex())).read()) js_1_bid = json.loads(urlopen('http://127.0.0.1:1801/json/bids/{}'.format(bid_id.hex())).read()) @@ -652,20 +647,17 @@ class Test(unittest.TestCase): ''' def pass_99_delay(self): - global stop_test logging.info('Delay') for i in range(60 * 10): - if stop_test: + if test_delay_event.is_set(): break - time.sleep(1) + test_delay_event.wait(1) print('delay', i) if i % 2 == 0: offer_id = self.swap_clients[0].postOffer(Coins.BTC, Coins.LTC, 0.001 * (i + 1) * COIN, 1.0 * (i + 1) * COIN, 0.001 * (i + 1) * COIN, SwapTypes.SELLER_FIRST) else: offer_id = self.swap_clients[1].postOffer(Coins.LTC, Coins.BTC, 0.001 * (i + 1) * COIN, 1.0 * (i + 1) * COIN, 0.001 * COIN, SwapTypes.SELLER_FIRST) - stop_test = True - if __name__ == '__main__': unittest.main() diff --git a/tests/basicswap/test_xmr.py b/tests/basicswap/test_xmr.py index ef1654b..a694a56 100644 --- a/tests/basicswap/test_xmr.py +++ b/tests/basicswap/test_xmr.py @@ -59,6 +59,8 @@ from tests.basicswap.common import ( wait_for_offer, wait_for_no_offer, wait_for_none_active, + wait_for_balance, + post_json_req, TEST_HTTP_HOST, TEST_HTTP_PORT, BASE_RPC_PORT, @@ -82,8 +84,7 @@ XMR_BASE_RPC_PORT = 21792 XMR_BASE_ZMQ_PORT = 22792 XMR_BASE_WALLET_RPC_PORT = 23792 -delay_event = threading.Event() -stop_test = False +test_delay_event = threading.Event() def prepareXmrDataDir(datadir, node_id, conf_file): @@ -203,10 +204,8 @@ def btcRpc(cmd, node_id=0): def signal_handler(sig, frame): - global stop_test logging.info('signal {} detected.'.format(sig)) - stop_test = True - delay_event.set() + test_delay_event.set() def waitForXMRNode(rpc_offset, max_tries=7): @@ -239,7 +238,7 @@ def callnoderpc(node_id, method, params=[], wallet=None, base_rpc_port=BASE_RPC_ def run_coins_loop(cls): - while not stop_test: + while not test_delay_event.is_set(): try: if cls.btc_addr is not None: btcRpc('generatetoaddress 1 {}'.format(cls.btc_addr)) @@ -247,14 +246,14 @@ def run_coins_loop(cls): callrpc_xmr_na(XMR_BASE_RPC_PORT + 1, 'generateblocks', {'wallet_address': cls.xmr_addr, 'amount_of_blocks': 1}) except Exception as e: logging.warning('run_coins_loop ' + str(e)) - time.sleep(1.0) + test_delay_event.wait(1.0) def run_loop(cls): - while not stop_test: + while not test_delay_event.is_set(): for c in cls.swap_clients: c.update() - time.sleep(1.0) + test_delay_event.wait(1.0) class Test(unittest.TestCase): @@ -401,9 +400,8 @@ class Test(unittest.TestCase): @classmethod def tearDownClass(cls): - global stop_test logging.info('Finalising') - stop_test = True + test_delay_event.set() if cls.update_thread is not None: try: cls.update_thread.join() @@ -440,22 +438,22 @@ class Test(unittest.TestCase): assert(make_int(js_1[str(int(Coins.XMR))]['unconfirmed'], scale=12) > 0) offer_id = swap_clients[0].postOffer(Coins.PART, Coins.XMR, 100 * COIN, 0.11 * XMR_COIN, 100 * COIN, SwapTypes.XMR_SWAP) - wait_for_offer(delay_event, swap_clients[1], offer_id) + wait_for_offer(test_delay_event, swap_clients[1], offer_id) offers = swap_clients[1].listOffers(filters={'offer_id': offer_id}) assert(len(offers) == 1) offer = offers[0] bid_id = swap_clients[1].postXmrBid(offer_id, offer.amount_from) - wait_for_bid(delay_event, swap_clients[0], bid_id, BidStates.BID_RECEIVED) + wait_for_bid(test_delay_event, swap_clients[0], bid_id, BidStates.BID_RECEIVED) bid, xmr_swap = swap_clients[0].getXmrBid(bid_id) assert(xmr_swap) swap_clients[0].acceptXmrBid(bid_id) - wait_for_bid(delay_event, swap_clients[0], bid_id, BidStates.SWAP_COMPLETED, wait_for=180) - wait_for_bid(delay_event, swap_clients[1], bid_id, BidStates.SWAP_COMPLETED, sent=True) + wait_for_bid(test_delay_event, swap_clients[0], bid_id, BidStates.SWAP_COMPLETED, wait_for=180) + wait_for_bid(test_delay_event, swap_clients[1], bid_id, BidStates.SWAP_COMPLETED, sent=True) js_0_end = json.loads(urlopen('http://127.0.0.1:1800/json/wallets').read()) end_xmr = float(js_0_end['6']['balance']) + float(js_0_end['6']['unconfirmed']) @@ -470,12 +468,12 @@ class Test(unittest.TestCase): offer_id = swap_clients[0].postOffer( Coins.PART, Coins.XMR, 101 * COIN, 0.12 * XMR_COIN, 101 * COIN, SwapTypes.XMR_SWAP, lock_type=SEQUENCE_LOCK_BLOCKS, lock_value=12) - wait_for_offer(delay_event, swap_clients[1], offer_id) + wait_for_offer(test_delay_event, swap_clients[1], offer_id) offer = swap_clients[1].getOffer(offer_id) bid_id = swap_clients[1].postXmrBid(offer_id, offer.amount_from) - wait_for_bid(delay_event, swap_clients[0], bid_id, BidStates.BID_RECEIVED) + wait_for_bid(test_delay_event, swap_clients[0], bid_id, BidStates.BID_RECEIVED) bid, xmr_swap = swap_clients[0].getXmrBid(bid_id) assert(xmr_swap) @@ -484,8 +482,8 @@ class Test(unittest.TestCase): swap_clients[0].acceptXmrBid(bid_id) - wait_for_bid(delay_event, swap_clients[0], bid_id, BidStates.XMR_SWAP_FAILED_REFUNDED, wait_for=180) - wait_for_bid(delay_event, swap_clients[1], bid_id, BidStates.XMR_SWAP_FAILED_REFUNDED, sent=True) + wait_for_bid(test_delay_event, swap_clients[0], bid_id, BidStates.XMR_SWAP_FAILED_REFUNDED, wait_for=180) + wait_for_bid(test_delay_event, swap_clients[1], bid_id, BidStates.XMR_SWAP_FAILED_REFUNDED, sent=True) js_w0_after = json.loads(urlopen('http://127.0.0.1:1800/json/wallets').read()) print('[rm] js_w0_before', json.dumps(js_w0_before)) @@ -500,12 +498,12 @@ class Test(unittest.TestCase): offer_id = swap_clients[0].postOffer( Coins.PART, Coins.XMR, 101 * COIN, 0.13 * XMR_COIN, 101 * COIN, SwapTypes.XMR_SWAP, lock_type=SEQUENCE_LOCK_BLOCKS, lock_value=12) - wait_for_offer(delay_event, swap_clients[1], offer_id) + wait_for_offer(test_delay_event, swap_clients[1], offer_id) offer = swap_clients[1].getOffer(offer_id) bid_id = swap_clients[1].postXmrBid(offer_id, offer.amount_from) - wait_for_bid(delay_event, swap_clients[0], bid_id, BidStates.BID_RECEIVED) + wait_for_bid(test_delay_event, swap_clients[0], bid_id, BidStates.BID_RECEIVED) bid, xmr_swap = swap_clients[0].getXmrBid(bid_id) assert(xmr_swap) @@ -515,13 +513,13 @@ class Test(unittest.TestCase): swap_clients[0].acceptXmrBid(bid_id) - wait_for_bid(delay_event, swap_clients[0], bid_id, BidStates.BID_STALLED_FOR_TEST, wait_for=180) - wait_for_bid(delay_event, swap_clients[1], bid_id, BidStates.XMR_SWAP_FAILED_SWIPED, wait_for=80, sent=True) + wait_for_bid(test_delay_event, swap_clients[0], bid_id, BidStates.BID_STALLED_FOR_TEST, wait_for=180) + wait_for_bid(test_delay_event, swap_clients[1], bid_id, BidStates.XMR_SWAP_FAILED_SWIPED, wait_for=80, sent=True) js_w0_after = json.loads(urlopen('http://127.0.0.1:1800/json/wallets').read()) - wait_for_none_active(delay_event, 1800) - wait_for_none_active(delay_event, 1801) + wait_for_none_active(test_delay_event, 1800) + wait_for_none_active(test_delay_event, 1801) def test_04_follower_recover_b_lock_tx(self): logging.info('---------- Test PART to XMR follower recovers coin b lock tx') @@ -531,12 +529,12 @@ class Test(unittest.TestCase): offer_id = swap_clients[0].postOffer( Coins.PART, Coins.XMR, 101 * COIN, 0.14 * XMR_COIN, 101 * COIN, SwapTypes.XMR_SWAP, lock_type=SEQUENCE_LOCK_BLOCKS, lock_value=18) - wait_for_offer(delay_event, swap_clients[1], offer_id) + wait_for_offer(test_delay_event, swap_clients[1], offer_id) offer = swap_clients[1].getOffer(offer_id) bid_id = swap_clients[1].postXmrBid(offer_id, offer.amount_from) - wait_for_bid(delay_event, swap_clients[0], bid_id, BidStates.BID_RECEIVED) + wait_for_bid(test_delay_event, swap_clients[0], bid_id, BidStates.BID_RECEIVED) bid, xmr_swap = swap_clients[0].getXmrBid(bid_id) assert(xmr_swap) @@ -545,14 +543,14 @@ class Test(unittest.TestCase): swap_clients[0].acceptXmrBid(bid_id) - wait_for_bid(delay_event, swap_clients[0], bid_id, BidStates.XMR_SWAP_FAILED_REFUNDED, wait_for=180) - wait_for_bid(delay_event, swap_clients[1], bid_id, BidStates.XMR_SWAP_FAILED_REFUNDED, sent=True) + wait_for_bid(test_delay_event, swap_clients[0], bid_id, BidStates.XMR_SWAP_FAILED_REFUNDED, wait_for=180) + wait_for_bid(test_delay_event, swap_clients[1], bid_id, BidStates.XMR_SWAP_FAILED_REFUNDED, sent=True) def test_05_btc_xmr(self): logging.info('---------- Test BTC to XMR') swap_clients = self.swap_clients offer_id = swap_clients[0].postOffer(Coins.BTC, Coins.XMR, 10 * COIN, 100 * XMR_COIN, 10 * COIN, SwapTypes.XMR_SWAP) - wait_for_offer(delay_event, swap_clients[1], offer_id) + wait_for_offer(test_delay_event, swap_clients[1], offer_id) offers = swap_clients[1].listOffers(filters={'offer_id': offer_id}) offer = offers[0] @@ -560,15 +558,15 @@ class Test(unittest.TestCase): bid_id = swap_clients[1].postXmrBid(offer_id, offer.amount_from) - wait_for_bid(delay_event, swap_clients[0], bid_id, BidStates.BID_RECEIVED) + wait_for_bid(test_delay_event, swap_clients[0], bid_id, BidStates.BID_RECEIVED) bid, xmr_swap = swap_clients[0].getXmrBid(bid_id) assert(xmr_swap) swap_clients[0].acceptXmrBid(bid_id) - wait_for_bid(delay_event, swap_clients[0], bid_id, BidStates.SWAP_COMPLETED, wait_for=180) - wait_for_bid(delay_event, swap_clients[1], bid_id, BidStates.SWAP_COMPLETED, sent=True) + wait_for_bid(test_delay_event, swap_clients[0], bid_id, BidStates.SWAP_COMPLETED, wait_for=180) + wait_for_bid(test_delay_event, swap_clients[1], bid_id, BidStates.SWAP_COMPLETED, sent=True) swap_clients[1].ci(Coins.XMR).setFeePriority(0) @@ -590,9 +588,9 @@ class Test(unittest.TestCase): offer1_id = swap_clients[0].postOffer(Coins.BTC, Coins.XMR, amt_1, rate_1, amt_1, SwapTypes.XMR_SWAP) offer2_id = swap_clients[0].postOffer(Coins.PART, Coins.XMR, amt_2, rate_2, amt_2, SwapTypes.XMR_SWAP) - wait_for_offer(delay_event, swap_clients[1], offer1_id) + wait_for_offer(test_delay_event, swap_clients[1], offer1_id) offer1 = swap_clients[1].getOffer(offer1_id) - wait_for_offer(delay_event, swap_clients[1], offer2_id) + wait_for_offer(test_delay_event, swap_clients[1], offer2_id) offer2 = swap_clients[1].getOffer(offer2_id) bid1_id = swap_clients[1].postXmrBid(offer1_id, offer1.amount_from) @@ -600,30 +598,30 @@ class Test(unittest.TestCase): offer3_id = swap_clients[0].postOffer(Coins.PART, Coins.XMR, 11 * COIN, 0.15 * XMR_COIN, 11 * COIN, SwapTypes.XMR_SWAP) - wait_for_bid(delay_event, swap_clients[0], bid1_id, BidStates.BID_RECEIVED) + wait_for_bid(test_delay_event, swap_clients[0], bid1_id, BidStates.BID_RECEIVED) swap_clients[0].acceptXmrBid(bid1_id) - wait_for_offer(delay_event, swap_clients[1], offer3_id) + wait_for_offer(test_delay_event, swap_clients[1], offer3_id) offer3 = swap_clients[1].getOffer(offer3_id) bid3_id = swap_clients[1].postXmrBid(offer3_id, offer3.amount_from) - wait_for_bid(delay_event, swap_clients[0], bid2_id, BidStates.BID_RECEIVED) + wait_for_bid(test_delay_event, swap_clients[0], bid2_id, BidStates.BID_RECEIVED) swap_clients[0].acceptXmrBid(bid2_id) - wait_for_bid(delay_event, swap_clients[0], bid3_id, BidStates.BID_RECEIVED) + wait_for_bid(test_delay_event, swap_clients[0], bid3_id, BidStates.BID_RECEIVED) swap_clients[0].acceptXmrBid(bid3_id) - wait_for_bid(delay_event, swap_clients[0], bid1_id, BidStates.SWAP_COMPLETED, wait_for=180) - wait_for_bid(delay_event, swap_clients[1], bid1_id, BidStates.SWAP_COMPLETED, sent=True) + wait_for_bid(test_delay_event, swap_clients[0], bid1_id, BidStates.SWAP_COMPLETED, wait_for=180) + wait_for_bid(test_delay_event, swap_clients[1], bid1_id, BidStates.SWAP_COMPLETED, sent=True) - wait_for_bid(delay_event, swap_clients[0], bid2_id, BidStates.SWAP_COMPLETED, wait_for=120) - wait_for_bid(delay_event, swap_clients[1], bid2_id, BidStates.SWAP_COMPLETED, sent=True) + wait_for_bid(test_delay_event, swap_clients[0], bid2_id, BidStates.SWAP_COMPLETED, wait_for=120) + wait_for_bid(test_delay_event, swap_clients[1], bid2_id, BidStates.SWAP_COMPLETED, sent=True) - wait_for_bid(delay_event, swap_clients[0], bid3_id, BidStates.SWAP_COMPLETED, wait_for=120) - wait_for_bid(delay_event, swap_clients[1], bid3_id, BidStates.SWAP_COMPLETED, sent=True) + wait_for_bid(test_delay_event, swap_clients[0], bid3_id, BidStates.SWAP_COMPLETED, wait_for=120) + wait_for_bid(test_delay_event, swap_clients[1], bid3_id, BidStates.SWAP_COMPLETED, sent=True) - wait_for_none_active(delay_event, 1800) - wait_for_none_active(delay_event, 1801) + wait_for_none_active(test_delay_event, 1800) + wait_for_none_active(test_delay_event, 1801) js_w0_after = json.loads(urlopen('http://127.0.0.1:1800/json/wallets').read()) js_w1_after = json.loads(urlopen('http://127.0.0.1:1801/json/wallets').read()) @@ -636,11 +634,11 @@ class Test(unittest.TestCase): logging.info('---------- Test offer revocaction') swap_clients = self.swap_clients offer_id = swap_clients[0].postOffer(Coins.BTC, Coins.XMR, 10 * COIN, 100 * XMR_COIN, 10 * COIN, SwapTypes.XMR_SWAP) - wait_for_offer(delay_event, swap_clients[1], offer_id) + wait_for_offer(test_delay_event, swap_clients[1], offer_id) swap_clients[0].revokeOffer(offer_id) - wait_for_no_offer(delay_event, swap_clients[1], offer_id) + wait_for_no_offer(test_delay_event, swap_clients[1], offer_id) def test_08_withdraw(self): logging.info('---------- Test xmr withdrawals') @@ -658,24 +656,24 @@ class Test(unittest.TestCase): logging.info('---------- Test BTC to XMR auto accept') swap_clients = self.swap_clients offer_id = swap_clients[0].postOffer(Coins.BTC, Coins.XMR, 11 * COIN, 101 * XMR_COIN, 10 * COIN, SwapTypes.XMR_SWAP, auto_accept_bids=True) - wait_for_offer(delay_event, swap_clients[1], offer_id) + wait_for_offer(test_delay_event, swap_clients[1], offer_id) offer = swap_clients[1].listOffers(filters={'offer_id': offer_id})[0] bid_id = swap_clients[1].postXmrBid(offer_id, offer.amount_from) - wait_for_bid(delay_event, swap_clients[0], bid_id, BidStates.SWAP_COMPLETED, wait_for=180) - wait_for_bid(delay_event, swap_clients[1], bid_id, BidStates.SWAP_COMPLETED, sent=True) + wait_for_bid(test_delay_event, swap_clients[0], bid_id, BidStates.SWAP_COMPLETED, wait_for=180) + wait_for_bid(test_delay_event, swap_clients[1], bid_id, BidStates.SWAP_COMPLETED, sent=True) def test_10_locked_refundtx(self): logging.info('---------- Test Refund tx is locked') swap_clients = self.swap_clients offer_id = swap_clients[0].postOffer(Coins.BTC, Coins.XMR, 10 * COIN, 100 * XMR_COIN, 10 * COIN, SwapTypes.XMR_SWAP) - wait_for_offer(delay_event, swap_clients[1], offer_id) + wait_for_offer(test_delay_event, swap_clients[1], offer_id) offers = swap_clients[1].listOffers(filters={'offer_id': offer_id}) offer = offers[0] bid_id = swap_clients[1].postXmrBid(offer_id, offer.amount_from) - wait_for_bid(delay_event, swap_clients[0], bid_id, BidStates.BID_RECEIVED) + wait_for_bid(test_delay_event, swap_clients[0], bid_id, BidStates.BID_RECEIVED) bid, xmr_swap = swap_clients[0].getXmrBid(bid_id) assert(xmr_swap) @@ -684,7 +682,7 @@ class Test(unittest.TestCase): swap_clients[0].acceptXmrBid(bid_id) - wait_for_bid(delay_event, swap_clients[0], bid_id, BidStates.XMR_SWAP_SCRIPT_COIN_LOCKED, wait_for=180) + wait_for_bid(test_delay_event, swap_clients[0], bid_id, BidStates.XMR_SWAP_SCRIPT_COIN_LOCKED, wait_for=180) bid, xmr_swap = swap_clients[0].getXmrBid(bid_id) assert(xmr_swap) @@ -695,6 +693,48 @@ class Test(unittest.TestCase): except Exception as e: assert('non-BIP68-final' in str(e)) + def test_11_particl_anon(self): + logging.info('---------- Test Particl anon transactions') + swap_clients = self.swap_clients + + js_0 = json.loads(urlopen('http://127.0.0.1:1800/json/wallets/part').read()) + assert(float(js_0['anon_balance']) == 0.0) + + js_1 = json.loads(urlopen('http://127.0.0.1:1801/json/wallets/part').read()) + assert(float(js_1['balance']) > 200.0) + + post_json = { + 'value': 100, + 'address': js_0['stealth_address'], + 'subfee': False, + 'type_to': 'anon', + } + json_rv = json.loads(post_json_req('http://127.0.0.1:1801/json/wallets/part/withdraw', post_json)) + assert(len(json_rv['txid']) == 64) + + post_json['value'] = 0.5 + for i in range(22): + json_rv = json.loads(post_json_req('http://127.0.0.1:1801/json/wallets/part/withdraw', post_json)) + assert(len(json_rv['txid']) == 64) + + logging.info('Waiting for anon balance') + wait_for_balance(test_delay_event, 'http://127.0.0.1:1800/json/wallets/part', 'anon_balance', 110.0) + + post_json = { + 'value': 10, + 'address': js_0['stealth_address'], + 'subfee': True, + 'type_from': 'anon', + 'type_to': 'blind', + } + json_rv = json.loads(post_json_req('http://127.0.0.1:1800/json/wallets/part/withdraw', post_json)) + assert(len(json_rv['txid']) == 64) + + logging.info('Waiting for blind balance') + wait_for_balance(test_delay_event, 'http://127.0.0.1:1800/json/wallets/part', 'blind_balance', 9.8) + if float(js_0['blind_balance']) >= 10.0: + raise ValueError('Expect blind balance < 10') + if __name__ == '__main__': unittest.main()