#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# Copyright (c) 2019-2021 tecnovert
# Distributed under the MIT software license, see the accompanying
# file LICENSE or http://www.opensource.org/licenses/mit-license.php.
"""
basicswap ] $ pytest
Run one test :
$ pytest - v - s tests / basicswap / test_run . py : : Test : : test_04_ltc_btc
"""
import os
import sys
import json
import random
import shutil
import signal
import logging
import unittest
import threading
from urllib . request import urlopen
import basicswap . config as cfg
from basicswap . basicswap import (
BasicSwap ,
Coins ,
SwapTypes ,
BidStates ,
TxStates ,
DebugTypes ,
SEQUENCE_LOCK_BLOCKS ,
)
from basicswap . util import (
COIN ,
toWIF ,
dumpje ,
make_int ,
format_amount ,
)
from basicswap . rpc import (
callrpc_cli ,
waitForRPC ,
)
from basicswap . contrib . key import (
ECKey ,
)
from basicswap . http_server import (
HttpThread ,
)
from tests . basicswap . common import (
checkForks ,
stopDaemons ,
wait_for_offer ,
wait_for_bid ,
wait_for_bid_tx_state ,
wait_for_in_progress ,
TEST_HTTP_HOST ,
TEST_HTTP_PORT ,
BASE_PORT ,
BASE_RPC_PORT ,
BASE_ZMQ_PORT ,
PREFIX_SECRET_KEY_REGTEST ,
)
from bin . basicswap_run import startDaemon
NUM_NODES = 3
LTC_NODE = 3
BTC_NODE = 4
test_delay_event = threading . Event ( )
logger = logging . getLogger ( )
logger . level = logging . DEBUG
if not len ( logger . handlers ) :
logger . addHandler ( logging . StreamHandler ( sys . stdout ) )
def prepareOtherDir ( datadir , nodeId , conf_file = ' litecoin.conf ' ) :
node_dir = os . path . join ( datadir , str ( nodeId ) )
if not os . path . exists ( node_dir ) :
os . makedirs ( node_dir )
filePath = os . path . join ( node_dir , conf_file )
with open ( filePath , ' w+ ' ) as fp :
fp . write ( ' regtest=1 \n ' )
fp . write ( ' [regtest] \n ' )
fp . write ( ' port= ' + str ( BASE_PORT + nodeId ) + ' \n ' )
fp . write ( ' rpcport= ' + str ( BASE_RPC_PORT + nodeId ) + ' \n ' )
fp . write ( ' daemon=0 \n ' )
fp . write ( ' printtoconsole=0 \n ' )
fp . write ( ' server=1 \n ' )
fp . write ( ' discover=0 \n ' )
fp . write ( ' listenonion=0 \n ' )
fp . write ( ' bind=127.0.0.1 \n ' )
fp . write ( ' findpeers=0 \n ' )
fp . write ( ' debug=1 \n ' )
fp . write ( ' debugexclude=libevent \n ' )
fp . write ( ' fallbackfee=0.0002 \n ' )
fp . write ( ' wallet=wallet.dat \n ' )
fp . write ( ' acceptnonstdtxn=0 \n ' )
return node_dir
def prepareDir ( datadir , nodeId , network_key , network_pubkey ) :
node_dir = os . path . join ( datadir , str ( nodeId ) )
if not os . path . exists ( node_dir ) :
os . makedirs ( node_dir )
filePath = os . path . join ( node_dir , ' particl.conf ' )
with open ( filePath , ' w+ ' ) as fp :
fp . write ( ' regtest=1 \n ' )
fp . write ( ' [regtest] \n ' )
fp . write ( ' port= ' + str ( BASE_PORT + nodeId ) + ' \n ' )
fp . write ( ' rpcport= ' + str ( BASE_RPC_PORT + nodeId ) + ' \n ' )
fp . write ( ' daemon=0 \n ' )
fp . write ( ' printtoconsole=0 \n ' )
fp . write ( ' server=1 \n ' )
fp . write ( ' discover=0 \n ' )
fp . write ( ' listenonion=0 \n ' )
fp . write ( ' bind=127.0.0.1 \n ' )
fp . write ( ' findpeers=0 \n ' )
fp . write ( ' debug=1 \n ' )
fp . write ( ' debugexclude=libevent \n ' )
fp . write ( ' zmqpubsmsg=tcp://127.0.0.1: ' + str ( BASE_ZMQ_PORT + nodeId ) + ' \n ' )
fp . write ( ' wallet=wallet.dat \n ' )
fp . write ( ' acceptnonstdtxn=0 \n ' )
fp . write ( ' minstakeinterval=2 \n ' )
fp . write ( ' smsgsregtestadjust=0 \n ' )
fp . write ( ' stakethreadconddelayms=1000 \n ' )
for i in range ( 0 , NUM_NODES ) :
if nodeId == i :
continue
fp . write ( ' addnode=127.0.0.1: %d \n ' % ( BASE_PORT + i ) )
if nodeId < 2 :
fp . write ( ' spentindex=1 \n ' )
fp . write ( ' txindex=1 \n ' )
basicswap_dir = os . path . join ( datadir , str ( nodeId ) , ' basicswap ' )
if not os . path . exists ( basicswap_dir ) :
os . makedirs ( basicswap_dir )
ltcdatadir = os . path . join ( datadir , str ( LTC_NODE ) )
btcdatadir = os . path . join ( datadir , str ( BTC_NODE ) )
settings_path = os . path . join ( basicswap_dir , cfg . CONFIG_FILENAME )
settings = {
' debug ' : True ,
' zmqhost ' : ' tcp://127.0.0.1 ' ,
' zmqport ' : BASE_ZMQ_PORT + nodeId ,
' htmlhost ' : ' 127.0.0.1 ' ,
' htmlport ' : 12700 + nodeId ,
' network_key ' : network_key ,
' network_pubkey ' : network_pubkey ,
' chainclients ' : {
' particl ' : {
' connection_type ' : ' rpc ' ,
' manage_daemon ' : False ,
' rpcport ' : BASE_RPC_PORT + nodeId ,
' datadir ' : node_dir ,
' bindir ' : cfg . PARTICL_BINDIR ,
' blocks_confirmed ' : 2 , # Faster testing
} ,
' litecoin ' : {
' connection_type ' : ' rpc ' ,
' manage_daemon ' : False ,
' rpcport ' : BASE_RPC_PORT + LTC_NODE ,
' datadir ' : ltcdatadir ,
' bindir ' : cfg . LITECOIN_BINDIR ,
# 'use_segwit': True,
} ,
' bitcoin ' : {
' connection_type ' : ' rpc ' ,
' manage_daemon ' : False ,
' rpcport ' : BASE_RPC_PORT + BTC_NODE ,
' datadir ' : btcdatadir ,
' bindir ' : cfg . BITCOIN_BINDIR ,
' use_segwit ' : True ,
}
} ,
' check_progress_seconds ' : 2 ,
' check_watched_seconds ' : 4 ,
' check_expired_seconds ' : 60 ,
' check_events_seconds ' : 1 ,
' min_delay_event ' : 1 ,
' max_delay_event ' : 5
}
with open ( settings_path , ' w ' ) as fp :
json . dump ( settings , fp , indent = 4 )
return node_dir
def partRpc ( cmd , node_id = 0 ) :
return callrpc_cli ( cfg . PARTICL_BINDIR , os . path . join ( cfg . TEST_DATADIRS , str ( node_id ) ) , ' regtest ' , cmd , cfg . PARTICL_CLI )
def btcRpc ( cmd ) :
return callrpc_cli ( cfg . BITCOIN_BINDIR , os . path . join ( cfg . TEST_DATADIRS , str ( BTC_NODE ) ) , ' regtest ' , cmd , cfg . BITCOIN_CLI )
def ltcRpc ( cmd ) :
return callrpc_cli ( cfg . LITECOIN_BINDIR , os . path . join ( cfg . TEST_DATADIRS , str ( LTC_NODE ) ) , ' regtest ' , cmd , cfg . LITECOIN_CLI )
def signal_handler ( sig , frame ) :
print ( ' signal {} detected. ' . format ( sig ) )
test_delay_event . set ( )
def run_coins_loop ( cls ) :
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 ) )
test_delay_event . wait ( 1.0 )
def run_loop ( cls ) :
while not test_delay_event . is_set ( ) :
for c in cls . swap_clients :
c . update ( )
test_delay_event . wait ( 1 )
def make_part_cli_rpc_func ( node_id ) :
node_id = node_id
def rpc_func ( method , params = None , wallet = None ) :
nonlocal node_id
cmd = method
if params :
for p in params :
if isinstance ( p , dict ) or isinstance ( p , list ) :
cmd + = ' " ' + dumpje ( p ) + ' " '
elif isinstance ( p , int ) :
cmd + = ' ' + str ( p )
else :
cmd + = ' " ' + p + ' " '
return partRpc ( cmd , node_id )
return rpc_func
class Test ( unittest . TestCase ) :
@classmethod
def setUpClass ( cls ) :
super ( Test , cls ) . setUpClass ( )
eckey = ECKey ( )
eckey . generate ( )
cls . network_key = toWIF ( PREFIX_SECRET_KEY_REGTEST , eckey . get_bytes ( ) )
cls . network_pubkey = eckey . get_pubkey ( ) . get_bytes ( ) . hex ( )
if os . path . isdir ( cfg . TEST_DATADIRS ) :
logging . info ( ' Removing ' + cfg . TEST_DATADIRS )
shutil . rmtree ( cfg . TEST_DATADIRS )
for i in range ( NUM_NODES ) :
data_dir = prepareDir ( cfg . TEST_DATADIRS , i , cls . network_key , cls . network_pubkey )
callrpc_cli ( cfg . PARTICL_BINDIR , data_dir , ' regtest ' , ' -wallet=wallet.dat create ' , ' particl-wallet ' ) # Necessary for 0.21
prepareOtherDir ( cfg . TEST_DATADIRS , LTC_NODE )
data_dir = prepareOtherDir ( cfg . TEST_DATADIRS , BTC_NODE , ' bitcoin.conf ' )
callrpc_cli ( cfg . BITCOIN_BINDIR , data_dir , ' regtest ' , ' -wallet=wallet.dat create ' , ' bitcoin-wallet ' ) # Necessary for 0.21
cls . daemons = [ ]
cls . swap_clients = [ ]
cls . http_threads = [ ]
cls . daemons . append ( startDaemon ( os . path . join ( cfg . TEST_DATADIRS , str ( BTC_NODE ) ) , cfg . BITCOIN_BINDIR , cfg . BITCOIND ) )
logging . info ( ' Started %s %d ' , cfg . BITCOIND , cls . daemons [ - 1 ] . pid )
cls . daemons . append ( startDaemon ( os . path . join ( cfg . TEST_DATADIRS , str ( LTC_NODE ) ) , cfg . LITECOIN_BINDIR , cfg . LITECOIND ) )
logging . info ( ' Started %s %d ' , cfg . LITECOIND , cls . daemons [ - 1 ] . pid )
for i in range ( NUM_NODES ) :
cls . daemons . append ( startDaemon ( os . path . join ( cfg . TEST_DATADIRS , str ( i ) ) , cfg . PARTICL_BINDIR , cfg . PARTICLD ) )
logging . info ( ' Started %s %d ' , cfg . PARTICLD , cls . daemons [ - 1 ] . pid )
for i in range ( NUM_NODES ) :
# Load mnemonics after all nodes have started to avoid staking getting stuck in TryToSync
rpc = make_part_cli_rpc_func ( i )
waitForRPC ( rpc )
if i == 0 :
rpc ( ' extkeyimportmaster ' , [ ' abandon baby cabbage dad eager fabric gadget habit ice kangaroo lab absorb ' ] )
elif i == 1 :
rpc ( ' extkeyimportmaster ' , [ ' pact mammal barrel matrix local final lecture chunk wasp survey bid various book strong spread fall ozone daring like topple door fatigue limb olympic ' , ' ' , ' true ' ] )
rpc ( ' getnewextaddress ' , [ ' lblExtTest ' ] )
rpc ( ' rescanblockchain ' )
else :
rpc ( ' extkeyimportmaster ' , [ rpc ( ' mnemonic ' , [ ' new ' ] ) [ ' master ' ] ] )
# Lower output split threshold for more stakeable outputs
rpc ( ' walletsettings ' , [ ' stakingoptions ' , { ' stakecombinethreshold ' : 100 , ' stakesplitthreshold ' : 200 } ] )
basicswap_dir = os . path . join ( os . path . join ( cfg . TEST_DATADIRS , str ( i ) ) , ' basicswap ' )
settings_path = os . path . join ( basicswap_dir , cfg . CONFIG_FILENAME )
with open ( settings_path ) as fs :
settings = json . load ( fs )
fp = open ( os . path . join ( basicswap_dir , ' basicswap.log ' ) , ' w ' )
sc = BasicSwap ( fp , basicswap_dir , settings , ' regtest ' , log_name = ' BasicSwap {} ' . format ( i ) )
sc . setDaemonPID ( Coins . BTC , cls . daemons [ 0 ] . pid )
sc . setDaemonPID ( Coins . LTC , cls . daemons [ 1 ] . pid )
sc . setDaemonPID ( Coins . PART , cls . daemons [ 2 + i ] . pid )
sc . start ( )
cls . swap_clients . append ( sc )
t = HttpThread ( cls . swap_clients [ i ] . fp , TEST_HTTP_HOST , TEST_HTTP_PORT + i , False , cls . swap_clients [ i ] )
cls . http_threads . append ( t )
t . start ( )
waitForRPC ( ltcRpc )
num_blocks = 500
logging . info ( ' Mining %d litecoin blocks ' , num_blocks )
cls . ltc_addr = ltcRpc ( ' getnewaddress mining_addr legacy ' )
ltcRpc ( ' generatetoaddress {} {} ' . format ( num_blocks , cls . ltc_addr ) )
ro = ltcRpc ( ' getblockchaininfo ' )
checkForks ( ro )
waitForRPC ( btcRpc )
cls . btc_addr = btcRpc ( ' getnewaddress mining_addr bech32 ' )
logging . info ( ' Mining %d Bitcoin blocks to %s ' , num_blocks , cls . btc_addr )
btcRpc ( ' generatetoaddress {} {} ' . format ( num_blocks , cls . btc_addr ) )
ro = btcRpc ( ' getblockchaininfo ' )
checkForks ( ro )
ro = ltcRpc ( ' getwalletinfo ' )
print ( ' ltcRpc ' , ro )
signal . signal ( signal . SIGINT , signal_handler )
cls . update_thread = threading . Thread ( target = run_loop , args = ( cls , ) )
cls . update_thread . start ( )
cls . coins_update_thread = threading . Thread ( target = run_coins_loop , args = ( cls , ) )
cls . coins_update_thread . start ( )
# Wait for height, or sequencelock is thrown off by genesis blocktime
num_blocks = 3
logging . info ( ' Waiting for Particl chain height %d ' , num_blocks )
for i in range ( 60 ) :
particl_blocks = cls . swap_clients [ 0 ] . callrpc ( ' getblockchaininfo ' ) [ ' blocks ' ]
print ( ' particl_blocks ' , particl_blocks )
if particl_blocks > = num_blocks :
break
test_delay_event . wait ( 1 )
assert ( particl_blocks > = num_blocks )
@classmethod
def tearDownClass ( cls ) :
logging . info ( ' Finalising ' )
test_delay_event . set ( )
cls . update_thread . join ( )
cls . coins_update_thread . join ( )
for t in cls . http_threads :
t . stop ( )
t . join ( )
for c in cls . swap_clients :
c . finalise ( )
c . fp . close ( )
stopDaemons ( cls . daemons )
super ( Test , cls ) . tearDownClass ( )
def test_01_verifyrawtransaction ( self ) :
txn = ' 0200000001eb6e5c4ebba4efa32f40c7314cad456a64008e91ee30b2dd0235ab9bb67fbdbb01000000ee47304402200956933242dde94f6cf8f195a470f8d02aef21ec5c9b66c5d3871594bdb74c9d02201d7e1b440de8f4da672d689f9e37e98815fb63dbc1706353290887eb6e8f7235012103dc1b24feb32841bc2f4375da91fa97834e5983668c2a39a6b7eadb60e7033f9d205a803b28fe2f86c17db91fa99d7ed2598f79b5677ffe869de2e478c0d1c02cc7514c606382012088a8201fe90717abb84b481c2a59112414ae56ec8acc72273642ca26cc7a5812fdc8f68876a914225fbfa4cb725b75e511810ac4d6f74069bdded26703520140b27576a914207eb66b2fd6ed9924d6217efc7fa7b38dfabe666888acffffffff01e0167118020000001976a9140044e188928710cecba8311f1cf412135b98145c88ac00000000 '
prevout = {
' txid ' : ' bbbd7fb69bab3502ddb230ee918e00646a45ad4c31c7402fa3efa4bb4e5c6eeb ' ,
' vout ' : 1 ,
' scriptPubKey ' : ' a9143d37191e8b864222d14952a14c85504677a0581d87 ' ,
' redeemScript ' : ' 6382012088a8201fe90717abb84b481c2a59112414ae56ec8acc72273642ca26cc7a5812fdc8f68876a914225fbfa4cb725b75e511810ac4d6f74069bdded26703520140b27576a914207eb66b2fd6ed9924d6217efc7fa7b38dfabe666888ac ' ,
' amount ' : 1.0 }
ro = partRpc ( ' verifyrawtransaction {} " {} " ' . format ( txn , dumpje ( [ prevout , ] ) ) )
assert ( ro [ ' inputs_valid ' ] is False )
assert ( ro [ ' validscripts ' ] == 1 )
prevout [ ' amount ' ] = 100.0
ro = partRpc ( ' verifyrawtransaction {} " {} " ' . format ( txn , dumpje ( [ prevout , ] ) ) )
assert ( ro [ ' inputs_valid ' ] is True )
assert ( ro [ ' validscripts ' ] == 1 )
txn = ' a000000000000128e8ba6a28673f2ebb5fd983b27a791fd1888447a47638b3cd8bfdd3f54a6f1e0100000000a90040000101e0c69a3b000000001976a9146c0f1ea47ca2bf84ed87bf3aa284e18748051f5788ac04473044022026b01f3a90e46883949404141467b741cd871722a4aaae8ddc8c4d6ab6fb1c77022047a2f3be2dcbe4c51837d2d5e0329aaa8a13a8186b03186b127cc51185e4f3ab012103dc1b24feb32841bc2f4375da91fa97834e5983668c2a39a6b7eadb60e7033f9d0100606382012088a8201fe90717abb84b481c2a59112414ae56ec8acc72273642ca26cc7a5812fdc8f68876a914207eb66b2fd6ed9924d6217efc7fa7b38dfabe666703a90040b27576a914225fbfa4cb725b75e511810ac4d6f74069bdded26888ac '
prevout = {
' txid ' : ' 1e6f4af5d3fd8bcdb33876a4478488d11f797ab283d95fbb2e3f67286abae828 ' ,
' vout ' : 1 ,
' scriptPubKey ' : ' a914129aee070317bbbd57062288849e85cf57d15c2687 ' ,
' redeemScript ' : ' 6382012088a8201fe90717abb84b481c2a59112414ae56ec8acc72273642ca26cc7a5812fdc8f68876a914207eb66b2fd6ed9924d6217efc7fa7b38dfabe666703a90040b27576a914225fbfa4cb725b75e511810ac4d6f74069bdded26888ac ' ,
' amount ' : 1.0 }
ro = partRpc ( ' verifyrawtransaction {} " {} " ' . format ( txn , dumpje ( [ prevout , ] ) ) )
assert ( ro [ ' inputs_valid ' ] is False )
assert ( ro [ ' validscripts ' ] == 0 ) # Amount covered by signature
prevout [ ' amount ' ] = 90.0
ro = partRpc ( ' verifyrawtransaction {} " {} " ' . format ( txn , dumpje ( [ prevout , ] ) ) )
assert ( ro [ ' inputs_valid ' ] is True )
assert ( ro [ ' validscripts ' ] == 1 )
def test_02_part_ltc ( self ) :
logging . info ( ' ---------- Test PART to LTC ' )
swap_clients = self . swap_clients
offer_id = swap_clients [ 0 ] . postOffer ( Coins . PART , Coins . LTC , 100 * COIN , 0.1 * COIN , 100 * COIN , SwapTypes . SELLER_FIRST )
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 ( test_delay_event , swap_clients [ 0 ] , bid_id )
swap_clients [ 0 ] . acceptBid ( bid_id )
wait_for_in_progress ( test_delay_event , swap_clients [ 1 ] , bid_id , sent = True )
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 ( ) )
assert ( js_0 [ ' num_swapping ' ] == 0 and js_0 [ ' num_watched_outputs ' ] == 0 )
assert ( js_1 [ ' num_swapping ' ] == 0 and js_1 [ ' num_watched_outputs ' ] == 0 )
def test_03_ltc_part ( self ) :
logging . info ( ' ---------- Test LTC to PART ' )
swap_clients = self . swap_clients
offer_id = swap_clients [ 1 ] . postOffer ( Coins . LTC , Coins . PART , 10 * COIN , 9.0 * COIN , 10 * COIN , SwapTypes . SELLER_FIRST )
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 ( test_delay_event , swap_clients [ 1 ] , bid_id )
swap_clients [ 1 ] . acceptBid ( bid_id )
wait_for_in_progress ( test_delay_event , swap_clients [ 0 ] , bid_id , sent = True )
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 ( ) )
assert ( js_0 [ ' num_swapping ' ] == 0 and js_0 [ ' num_watched_outputs ' ] == 0 )
assert ( js_1 [ ' num_swapping ' ] == 0 and js_1 [ ' num_watched_outputs ' ] == 0 )
def test_04_ltc_btc ( self ) :
logging . info ( ' ---------- Test LTC to BTC ' )
swap_clients = self . swap_clients
offer_id = swap_clients [ 0 ] . postOffer ( Coins . LTC , Coins . BTC , 10 * COIN , 0.1 * COIN , 10 * COIN , SwapTypes . SELLER_FIRST )
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 ( test_delay_event , swap_clients [ 0 ] , bid_id )
swap_clients [ 0 ] . acceptBid ( bid_id )
wait_for_in_progress ( test_delay_event , swap_clients [ 1 ] , bid_id , sent = True )
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 ( ) )
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 ( ) )
assert ( js_0 [ ' num_swapping ' ] == 0 and js_0 [ ' num_watched_outputs ' ] == 0 )
assert ( js_1 [ ' num_swapping ' ] == 0 and js_1 [ ' num_watched_outputs ' ] == 0 )
def test_05_refund ( self ) :
# Seller submits initiate txn, buyer doesn't respond
logging . info ( ' ---------- Test refund, LTC to BTC ' )
swap_clients = self . swap_clients
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 ( 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 ( test_delay_event , swap_clients [ 0 ] , bid_id )
swap_clients [ 1 ] . abandonBid ( bid_id )
swap_clients [ 0 ] . acceptBid ( bid_id )
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 ( ) )
assert ( js_0_bid [ ' itx_state ' ] == ' Refunded ' )
assert ( js_1_bid [ ' ptx_state ' ] == ' Unknown ' )
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 ( ) )
assert ( js_0 [ ' num_swapping ' ] == 0 and js_0 [ ' num_watched_outputs ' ] == 0 )
assert ( js_1 [ ' num_swapping ' ] == 0 and js_1 [ ' num_watched_outputs ' ] == 0 )
def test_06_self_bid ( self ) :
logging . info ( ' ---------- Test same client, BTC to LTC ' )
swap_clients = self . swap_clients
js_0_before = json . loads ( urlopen ( ' http://127.0.0.1:1800/json ' ) . read ( ) )
offer_id = swap_clients [ 0 ] . postOffer ( Coins . BTC , Coins . LTC , 10 * COIN , 10 * COIN , 10 * COIN , SwapTypes . SELLER_FIRST )
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 ( test_delay_event , swap_clients [ 0 ] , bid_id )
swap_clients [ 0 ] . acceptBid ( bid_id )
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 )
assert ( js_0 [ ' num_recv_bids ' ] == js_0_before [ ' num_recv_bids ' ] + 1 and js_0 [ ' num_sent_bids ' ] == js_0_before [ ' num_sent_bids ' ] + 1 )
def test_07_error ( self ) :
logging . info ( ' ---------- Test error, BTC to LTC, set fee above bid value ' )
swap_clients = self . swap_clients
js_0_before = json . loads ( urlopen ( ' http://127.0.0.1:1800/json ' ) . read ( ) )
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 ( 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 ( 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 ( 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 ' ]
del swap_clients [ 0 ] . getChainClientSettings ( Coins . LTC ) [ ' override_feerate ' ]
def test_08_part_ltc_buyer_first ( self ) :
logging . info ( ' ---------- Test PART to LTC, buyer first ' )
swap_clients = self . swap_clients
offer_id = swap_clients [ 0 ] . postOffer ( Coins . PART , Coins . LTC , 100 * COIN , 0.1 * COIN , 100 * COIN , SwapTypes . BUYER_FIRST )
logging . warning ( ' TODO ' )
def test_09_part_ltc_auto_accept ( self ) :
logging . info ( ' ---------- Test PART to LTC, auto accept bid ' )
swap_clients = self . swap_clients
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 ( 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 ( 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
logging . info ( ' ---------- Test bad PTx, LTC to BTC ' )
swap_clients = self . swap_clients
swap_value = make_int ( random . uniform ( 0.001 , 10.0 ) , scale = 8 , r = 1 )
logging . info ( ' swap_value {} ' . format ( format_amount ( swap_value , 8 ) ) )
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 ( 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 ( test_delay_event , swap_clients [ 0 ] , bid_id )
swap_clients [ 0 ] . acceptBid ( bid_id )
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 ( ) )
assert ( js_0_bid [ ' itx_state ' ] == ' Refunded ' )
assert ( js_1_bid [ ' ptx_state ' ] == ' Refunded ' )
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 ( ) )
assert ( js_0 [ ' num_swapping ' ] == 0 and js_0 [ ' num_watched_outputs ' ] == 0 )
assert ( js_1 [ ' num_swapping ' ] == 0 and js_1 [ ' num_watched_outputs ' ] == 0 )
'''
def test_11_refund ( self ) :
# Seller submits initiate txn, buyer doesn't respond, repeat of test 5 using debug_ind
logging . info ( ' ---------- Test refund, LTC to BTC ' )
swap_clients = self . swap_clients
swap_value = make_int ( random . uniform ( 0.001 , 10.0 ) , scale = 8 , r = 1 )
logging . info ( ' swap_value {} ' . format ( format_amount ( swap_value , 8 ) ) )
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 ( 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 ( test_delay_event , swap_clients [ 0 ] , bid_id )
swap_clients [ 0 ] . acceptBid ( bid_id )
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 ( ) )
assert ( js_0_bid [ ' itx_state ' ] == ' Refunded ' )
assert ( js_1_bid [ ' ptx_state ' ] == ' Unknown ' )
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 ( ) )
assert ( js_0 [ ' num_swapping ' ] == 0 and js_0 [ ' num_watched_outputs ' ] == 0 )
assert ( js_1 [ ' num_swapping ' ] == 0 and js_1 [ ' num_watched_outputs ' ] == 0 )
'''
def pass_99_delay ( self ) :
logging . info ( ' Delay ' )
for i in range ( 60 * 10 ) :
if test_delay_event . is_set ( ) :
break
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 )
if __name__ == ' __main__ ' :
unittest . main ( )