nmc: Update test.

This commit is contained in:
tecnovert 2025-03-28 22:31:50 +02:00
parent 8967f677c3
commit f263bb53c3
6 changed files with 309 additions and 741 deletions

View file

@ -52,11 +52,17 @@ PARTICL_VERSION = os.getenv("PARTICL_VERSION", "23.2.7.0")
PARTICL_VERSION_TAG = os.getenv("PARTICL_VERSION_TAG", "") PARTICL_VERSION_TAG = os.getenv("PARTICL_VERSION_TAG", "")
PARTICL_LINUX_EXTRA = os.getenv("PARTICL_LINUX_EXTRA", "nousb") PARTICL_LINUX_EXTRA = os.getenv("PARTICL_LINUX_EXTRA", "nousb")
BITCOIN_VERSION = os.getenv("BITCOIN_VERSION", "28.0")
BITCOIN_VERSION_TAG = os.getenv("BITCOIN_VERSION_TAG", "")
LITECOIN_VERSION = os.getenv("LITECOIN_VERSION", "0.21.4") LITECOIN_VERSION = os.getenv("LITECOIN_VERSION", "0.21.4")
LITECOIN_VERSION_TAG = os.getenv("LITECOIN_VERSION_TAG", "") LITECOIN_VERSION_TAG = os.getenv("LITECOIN_VERSION_TAG", "")
BITCOIN_VERSION = os.getenv("BITCOIN_VERSION", "28.0") DCR_VERSION = os.getenv("DCR_VERSION", "1.8.1")
BITCOIN_VERSION_TAG = os.getenv("BITCOIN_VERSION_TAG", "") DCR_VERSION_TAG = os.getenv("DCR_VERSION_TAG", "")
NMC_VERSION = os.getenv("NMC_VERSION", "28.0")
NMC_VERSION_TAG = os.getenv("NMC_VERSION_TAG", "")
MONERO_VERSION = os.getenv("MONERO_VERSION", "0.18.3.4") MONERO_VERSION = os.getenv("MONERO_VERSION", "0.18.3.4")
MONERO_VERSION_TAG = os.getenv("MONERO_VERSION_TAG", "") MONERO_VERSION_TAG = os.getenv("MONERO_VERSION_TAG", "")
@ -82,12 +88,6 @@ FIRO_VERSION_TAG = os.getenv("FIRO_VERSION_TAG", "")
NAV_VERSION = os.getenv("NAV_VERSION", "7.0.3") NAV_VERSION = os.getenv("NAV_VERSION", "7.0.3")
NAV_VERSION_TAG = os.getenv("NAV_VERSION_TAG", "") NAV_VERSION_TAG = os.getenv("NAV_VERSION_TAG", "")
NMC_VERSION = os.getenv("NAV_VERSION", "28.0")
NMC_VERSION_TAG = os.getenv("NAV_VERSION_TAG", "")
DCR_VERSION = os.getenv("DCR_VERSION", "1.8.1")
DCR_VERSION_TAG = os.getenv("DCR_VERSION_TAG", "")
BITCOINCASH_VERSION = os.getenv("BITCOINCASH_VERSION", "28.0.1") BITCOINCASH_VERSION = os.getenv("BITCOINCASH_VERSION", "28.0.1")
BITCOINCASH_VERSION_TAG = os.getenv("BITCOINCASH_VERSION_TAG", "") BITCOINCASH_VERSION_TAG = os.getenv("BITCOINCASH_VERSION_TAG", "")
@ -117,9 +117,7 @@ known_coins = {
"dogecoin": (DOGECOIN_VERSION, DOGECOIN_VERSION_TAG, ("tecnovert",)), "dogecoin": (DOGECOIN_VERSION, DOGECOIN_VERSION_TAG, ("tecnovert",)),
} }
disabled_coins = [ disabled_coins = ["navcoin"]
"navcoin"
]
expected_key_ids = { expected_key_ids = {
"tecnovert": ("13F13651C9CF0D6B",), "tecnovert": ("13F13651C9CF0D6B",),
@ -184,6 +182,35 @@ PART_ONION_PORT = int(os.getenv("PART_ONION_PORT", 51734))
PART_RPC_USER = os.getenv("PART_RPC_USER", "") PART_RPC_USER = os.getenv("PART_RPC_USER", "")
PART_RPC_PWD = os.getenv("PART_RPC_PWD", "") PART_RPC_PWD = os.getenv("PART_RPC_PWD", "")
BTC_RPC_HOST = os.getenv("BTC_RPC_HOST", "127.0.0.1")
BTC_RPC_PORT = int(os.getenv("BTC_RPC_PORT", 19996))
BTC_PORT = int(os.getenv("BTC_PORT", 8333))
BTC_ONION_PORT = int(os.getenv("BTC_ONION_PORT", 8334))
BTC_RPC_USER = os.getenv("BTC_RPC_USER", "")
BTC_RPC_PWD = os.getenv("BTC_RPC_PWD", "")
LTC_RPC_HOST = os.getenv("LTC_RPC_HOST", "127.0.0.1")
LTC_RPC_PORT = int(os.getenv("LTC_RPC_PORT", 19895))
LTC_ONION_PORT = int(os.getenv("LTC_ONION_PORT", 9333))
LTC_RPC_USER = os.getenv("LTC_RPC_USER", "")
LTC_RPC_PWD = os.getenv("LTC_RPC_PWD", "")
DCR_RPC_HOST = os.getenv("DCR_RPC_HOST", "127.0.0.1")
DCR_RPC_PORT = int(os.getenv("DCR_RPC_PORT", 9109))
DCR_WALLET_RPC_HOST = os.getenv("DCR_WALLET_RPC_HOST", "127.0.0.1")
DCR_WALLET_RPC_PORT = int(os.getenv("DCR_WALLET_RPC_PORT", 9209))
DCR_WALLET_PWD = os.getenv(
"DCR_WALLET_PWD", random.randbytes(random.randint(14, 18)).hex()
)
DCR_RPC_USER = os.getenv("DCR_RPC_USER", "user")
DCR_RPC_PWD = os.getenv("DCR_RPC_PWD", random.randbytes(random.randint(14, 18)).hex())
NMC_RPC_HOST = os.getenv("NMC_RPC_HOST", "127.0.0.1")
NMC_RPC_PORT = int(os.getenv("NMC_RPC_PORT", 19698))
NMC_ONION_PORT = int(os.getenv("NMC_ONION_PORT", 9698))
NMC_RPC_USER = os.getenv("NMC_RPC_USER", "")
NMC_RPC_PWD = os.getenv("NMC_RPC_PWD", "")
XMR_RPC_HOST = os.getenv("XMR_RPC_HOST", "127.0.0.1") XMR_RPC_HOST = os.getenv("XMR_RPC_HOST", "127.0.0.1")
XMR_RPC_PORT = int(os.getenv("XMR_RPC_PORT", 29798)) XMR_RPC_PORT = int(os.getenv("XMR_RPC_PORT", 29798))
XMR_ZMQ_PORT = int(os.getenv("XMR_ZMQ_PORT", 30898)) XMR_ZMQ_PORT = int(os.getenv("XMR_ZMQ_PORT", 30898))
@ -206,35 +233,6 @@ WOW_RPC_USER = os.getenv("WOW_RPC_USER", "")
WOW_RPC_PWD = os.getenv("WOW_RPC_PWD", "") WOW_RPC_PWD = os.getenv("WOW_RPC_PWD", "")
DEFAULT_WOW_RESTORE_HEIGHT = int(os.getenv("DEFAULT_WOW_RESTORE_HEIGHT", 450000)) DEFAULT_WOW_RESTORE_HEIGHT = int(os.getenv("DEFAULT_WOW_RESTORE_HEIGHT", 450000))
LTC_RPC_HOST = os.getenv("LTC_RPC_HOST", "127.0.0.1")
LTC_RPC_PORT = int(os.getenv("LTC_RPC_PORT", 19895))
LTC_ONION_PORT = int(os.getenv("LTC_ONION_PORT", 9333))
LTC_RPC_USER = os.getenv("LTC_RPC_USER", "")
LTC_RPC_PWD = os.getenv("LTC_RPC_PWD", "")
BTC_RPC_HOST = os.getenv("BTC_RPC_HOST", "127.0.0.1")
BTC_RPC_PORT = int(os.getenv("BTC_RPC_PORT", 19996))
BTC_PORT = int(os.getenv("BTC_PORT", 8333))
BTC_ONION_PORT = int(os.getenv("BTC_ONION_PORT", 8334))
BTC_RPC_USER = os.getenv("BTC_RPC_USER", "")
BTC_RPC_PWD = os.getenv("BTC_RPC_PWD", "")
DCR_RPC_HOST = os.getenv("DCR_RPC_HOST", "127.0.0.1")
DCR_RPC_PORT = int(os.getenv("DCR_RPC_PORT", 9109))
DCR_WALLET_RPC_HOST = os.getenv("DCR_WALLET_RPC_HOST", "127.0.0.1")
DCR_WALLET_RPC_PORT = int(os.getenv("DCR_WALLET_RPC_PORT", 9209))
DCR_WALLET_PWD = os.getenv(
"DCR_WALLET_PWD", random.randbytes(random.randint(14, 18)).hex()
)
DCR_RPC_USER = os.getenv("DCR_RPC_USER", "user")
DCR_RPC_PWD = os.getenv("DCR_RPC_PWD", random.randbytes(random.randint(14, 18)).hex())
NMC_RPC_HOST = os.getenv("NMC_RPC_HOST", "127.0.0.1")
NMC_RPC_PORT = int(os.getenv("NMC_RPC_PORT", 19698))
NMC_ONION_PORT = int(os.getenv("NMC_ONION_PORT", 9698))
NMC_RPC_USER = os.getenv("NMC_RPC_USER", "")
NMC_RPC_PWD = os.getenv("NMC_RPC_PWD", "")
PIVX_RPC_HOST = os.getenv("PIVX_RPC_HOST", "127.0.0.1") PIVX_RPC_HOST = os.getenv("PIVX_RPC_HOST", "127.0.0.1")
PIVX_RPC_PORT = int(os.getenv("PIVX_RPC_PORT", 51473)) PIVX_RPC_PORT = int(os.getenv("PIVX_RPC_PORT", 51473))
PIVX_ONION_PORT = int(os.getenv("PIVX_ONION_PORT", 51472)) # nDefaultPort PIVX_ONION_PORT = int(os.getenv("PIVX_ONION_PORT", 51472)) # nDefaultPort
@ -1400,8 +1398,10 @@ def prepareDataDir(coin, settings, chain, particl_mnemonic, extra_opts={}):
) )
) )
elif coin == "namecoin": elif coin == "namecoin":
fp.write("deprecatedrpc=create_bdb\n")
fp.write("prune=2000\n") fp.write("prune=2000\n")
fp.write("deprecatedrpc=create_bdb\n")
fp.write("addresstype=bech32\n")
fp.write("changetype=bech32\n")
elif coin == "pivx": elif coin == "pivx":
params_dir = os.path.join(data_dir, "pivx-params") params_dir = os.path.join(data_dir, "pivx-params")
downloadPIVXParams(params_dir) downloadPIVXParams(params_dir)

View file

@ -256,6 +256,8 @@ chainparams = {
"bip44": 7, "bip44": 7,
"min_amount": 100000, "min_amount": 100000,
"max_amount": 10000000 * COIN, "max_amount": 10000000 * COIN,
"ext_public_key_prefix": 0x0488B21E, # base58Prefixes[EXT_PUBLIC_KEY]
"ext_secret_key_prefix": 0x0488ADE4,
}, },
"testnet": { "testnet": {
"rpcport": 18336, "rpcport": 18336,
@ -267,6 +269,8 @@ chainparams = {
"min_amount": 100000, "min_amount": 100000,
"max_amount": 10000000 * COIN, "max_amount": 10000000 * COIN,
"name": "testnet3", "name": "testnet3",
"ext_public_key_prefix": 0x043587CF,
"ext_secret_key_prefix": 0x04358394,
}, },
"regtest": { "regtest": {
"rpcport": 18443, "rpcport": 18443,
@ -277,6 +281,8 @@ chainparams = {
"bip44": 1, "bip44": 1,
"min_amount": 100000, "min_amount": 100000,
"max_amount": 10000000 * COIN, "max_amount": 10000000 * COIN,
"ext_public_key_prefix": 0x043587CF,
"ext_secret_key_prefix": 0x04358394,
}, },
}, },
Coins.XMR: { Coins.XMR: {

View file

@ -2,6 +2,7 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# Copyright (c) 2020-2022 tecnovert # Copyright (c) 2020-2022 tecnovert
# Copyright (c) 2025 The Basicswap developers
# Distributed under the MIT software license, see the accompanying # Distributed under the MIT software license, see the accompanying
# file LICENSE or http://www.opensource.org/licenses/mit-license.php. # file LICENSE or http://www.opensource.org/licenses/mit-license.php.
@ -14,38 +15,56 @@ class NMCInterface(BTCInterface):
def coin_type(): def coin_type():
return Coins.NMC return Coins.NMC
def getLockTxHeight( def lockNonSegwitPrevouts(self) -> None:
self, # For tests
txid, # NMC Seems to ignore utxo locks
dest_address, unspent = self.rpc_wallet("listunspent")
bid_amount,
rescan_from,
find_index: bool = False,
vout: int = -1,
):
self._log.debug("[rm] scantxoutset start") # scantxoutset is slow
ro = self.rpc(
"scantxoutset", ["start", ["addr({})".format(dest_address)]]
) # TODO: Use combo(address) where possible
self._log.debug("[rm] scantxoutset end")
return_txid = True if txid is None else False
for o in ro["unspents"]:
if txid and o["txid"] != txid.hex():
continue
# Verify amount
if self.make_int(o["amount"]) != int(bid_amount):
self._log.warning(
"Found output to lock tx address of incorrect value: %s, %s",
str(o["amount"]),
o["txid"],
)
continue
rv = {"depth": 0, "height": o["height"]} to_lock = []
if o["height"] > 0: for u in unspent:
rv["depth"] = ro["height"] - o["height"] if u.get("spendable", False) is False:
if find_index: continue
rv["index"] = o["vout"] if "desc" in u:
if return_txid: desc = u["desc"]
rv["txid"] = o["txid"] if self.use_p2shp2wsh():
return rv if not desc.startswith("sh(wpkh"):
to_lock.append(
{
"txid": u["txid"],
"vout": u["vout"],
"amount": u["amount"],
}
)
else:
if not desc.startswith("wpkh"):
to_lock.append(
{
"txid": u["txid"],
"vout": u["vout"],
"amount": u["amount"],
}
)
if len(to_lock) > 0:
self._log.debug(f"Spending {len(to_lock)} non segwit prevouts")
addr_out = self.rpc_wallet(
"getnewaddress", ["convert non segwit", "bech32"]
)
prevouts = []
sum_amount: int = 0
for utxo in to_lock:
prevouts.append(
{
"txid": utxo["txid"],
"vout": utxo["vout"],
}
)
sum_amount += self.make_int(utxo["amount"])
fee = 100000 * len(prevouts)
funded_tx = self.rpc(
"createrawtransaction",
[prevouts, {addr_out: self.format_amount(sum_amount - fee)}],
)
signed_tx = self.rpc_wallet("signrawtransactionwithwallet", [funded_tx])
self.rpc("sendrawtransaction", [signed_tx["hex"]])

View file

@ -138,7 +138,6 @@ def run_test_success_path(self, coin_from: Coins, coin_to: Coins):
# Verify lock tx spends are found in the expected wallets # Verify lock tx spends are found in the expected wallets
bid, offer = swap_clients[node_from].getBidAndOffer(bid_id) bid, offer = swap_clients[node_from].getBidAndOffer(bid_id)
max_fee: int = 10000
itx_spend = bid.initiate_tx.spend_txid.hex() itx_spend = bid.initiate_tx.spend_txid.hex()
node_to_ci_from = swap_clients[node_to].ci(coin_from) node_to_ci_from = swap_clients[node_to].ci(coin_from)
wtx = node_to_ci_from.rpc_wallet( wtx = node_to_ci_from.rpc_wallet(
@ -147,7 +146,9 @@ def run_test_success_path(self, coin_from: Coins, coin_to: Coins):
itx_spend, itx_spend,
], ],
) )
assert amt_swap - node_to_ci_from.make_int(wtx["details"][0]["amount"]) < max_fee assert (
amt_swap - node_to_ci_from.make_int(wtx["details"][0]["amount"]) < self.max_fee
)
node_from_ci_to = swap_clients[node_from].ci(coin_to) node_from_ci_to = swap_clients[node_from].ci(coin_to)
ptx_spend = bid.participate_tx.spend_txid.hex() ptx_spend = bid.participate_tx.spend_txid.hex()
@ -158,7 +159,8 @@ def run_test_success_path(self, coin_from: Coins, coin_to: Coins):
], ],
) )
assert ( assert (
bid.amount_to - node_from_ci_to.make_int(wtx["details"][0]["amount"]) < max_fee bid.amount_to - node_from_ci_to.make_int(wtx["details"][0]["amount"])
< self.max_fee
) )
js_0 = read_json_api(1800 + node_from) js_0 = read_json_api(1800 + node_from)
@ -235,7 +237,6 @@ def run_test_bad_ptx(self, coin_from: Coins, coin_to: Coins):
# Verify lock tx spends are found in the expected wallets # Verify lock tx spends are found in the expected wallets
bid, offer = swap_clients[node_from].getBidAndOffer(bid_id) bid, offer = swap_clients[node_from].getBidAndOffer(bid_id)
max_fee: int = 10000
itx_spend = bid.initiate_tx.spend_txid.hex() itx_spend = bid.initiate_tx.spend_txid.hex()
node_from_ci_from = swap_clients[node_from].ci(coin_from) node_from_ci_from = swap_clients[node_from].ci(coin_from)
wtx = node_from_ci_from.rpc_wallet( wtx = node_from_ci_from.rpc_wallet(
@ -244,7 +245,10 @@ def run_test_bad_ptx(self, coin_from: Coins, coin_to: Coins):
itx_spend, itx_spend,
], ],
) )
assert amt_swap - node_from_ci_from.make_int(wtx["details"][0]["amount"]) < max_fee assert (
amt_swap - node_from_ci_from.make_int(wtx["details"][0]["amount"])
< self.max_fee
)
node_to_ci_to = swap_clients[node_to].ci(coin_to) node_to_ci_to = swap_clients[node_to].ci(coin_to)
bid, offer = swap_clients[node_to].getBidAndOffer(bid_id) bid, offer = swap_clients[node_to].getBidAndOffer(bid_id)
@ -255,7 +259,10 @@ def run_test_bad_ptx(self, coin_from: Coins, coin_to: Coins):
ptx_spend, ptx_spend,
], ],
) )
assert bid.amount_to - node_to_ci_to.make_int(wtx["details"][0]["amount"]) < max_fee assert (
bid.amount_to - node_to_ci_to.make_int(wtx["details"][0]["amount"])
< self.max_fee
)
bid_id_hex = bid_id.hex() bid_id_hex = bid_id.hex()
path = f"bids/{bid_id_hex}/states" path = f"bids/{bid_id_hex}/states"
@ -338,7 +345,6 @@ def run_test_itx_refund(self, coin_from: Coins, coin_to: Coins):
# Verify lock tx spends are found in the expected wallets # Verify lock tx spends are found in the expected wallets
bid, offer = swap_clients[node_from].getBidAndOffer(bid_id) bid, offer = swap_clients[node_from].getBidAndOffer(bid_id)
max_fee: int = 10000
itx_spend = bid.initiate_tx.spend_txid.hex() itx_spend = bid.initiate_tx.spend_txid.hex()
node_from_ci_from = swap_clients[node_from].ci(coin_from) node_from_ci_from = swap_clients[node_from].ci(coin_from)
wtx = node_from_ci_from.rpc_wallet( wtx = node_from_ci_from.rpc_wallet(
@ -348,7 +354,8 @@ def run_test_itx_refund(self, coin_from: Coins, coin_to: Coins):
], ],
) )
assert ( assert (
swap_value - node_from_ci_from.make_int(wtx["details"][0]["amount"]) < max_fee swap_value - node_from_ci_from.make_int(wtx["details"][0]["amount"])
< self.max_fee
) )
node_from_ci_to = swap_clients[node_from].ci(coin_to) node_from_ci_to = swap_clients[node_from].ci(coin_to)
@ -360,7 +367,8 @@ def run_test_itx_refund(self, coin_from: Coins, coin_to: Coins):
], ],
) )
assert ( assert (
bid.amount_to - node_from_ci_to.make_int(wtx["details"][0]["amount"]) < max_fee bid.amount_to - node_from_ci_to.make_int(wtx["details"][0]["amount"])
< self.max_fee
) )
@ -425,7 +433,6 @@ def run_test_ads_success_path(self, coin_from: Coins, coin_to: Coins):
bid, xmr_swap = swap_clients[id_offerer].getXmrBid(bid_id) bid, xmr_swap = swap_clients[id_offerer].getXmrBid(bid_id)
node_from_ci_to = swap_clients[0].ci(coin_to) node_from_ci_to = swap_clients[0].ci(coin_to)
max_fee: int = 10000
if node_from_ci_to.coin_type() in (Coins.XMR, Coins.WOW): if node_from_ci_to.coin_type() in (Coins.XMR, Coins.WOW):
pass pass
else: else:
@ -437,7 +444,7 @@ def run_test_ads_success_path(self, coin_from: Coins, coin_to: Coins):
) )
assert ( assert (
bid.amount_to - node_from_ci_to.make_int(wtx["details"][0]["amount"]) bid.amount_to - node_from_ci_to.make_int(wtx["details"][0]["amount"])
< max_fee < self.max_fee
) )
node_to_ci_from = swap_clients[1].ci(coin_from) node_to_ci_from = swap_clients[1].ci(coin_from)
@ -451,7 +458,8 @@ def run_test_ads_success_path(self, coin_from: Coins, coin_to: Coins):
], ],
) )
assert ( assert (
bid.amount - node_to_ci_from.make_int(wtx["details"][0]["amount"]) < max_fee bid.amount - node_to_ci_from.make_int(wtx["details"][0]["amount"])
< self.max_fee
) )
bid_id_hex = bid_id.hex() bid_id_hex = bid_id.hex()
@ -550,7 +558,6 @@ def run_test_ads_both_refund(
bid, xmr_swap = swap_clients[id_bidder].getXmrBid(bid_id) bid, xmr_swap = swap_clients[id_bidder].getXmrBid(bid_id)
node_from_ci_from = swap_clients[0].ci(coin_from) node_from_ci_from = swap_clients[0].ci(coin_from)
max_fee: int = 10000
if node_from_ci_from.coin_type() in (Coins.XMR, Coins.WOW): if node_from_ci_from.coin_type() in (Coins.XMR, Coins.WOW):
pass pass
else: else:
@ -562,7 +569,7 @@ def run_test_ads_both_refund(
) )
assert ( assert (
bid.amount - node_from_ci_from.make_int(wtx["details"][0]["amount"]) bid.amount - node_from_ci_from.make_int(wtx["details"][0]["amount"])
< max_fee < self.max_fee
) )
node_to_ci_to = swap_clients[1].ci(coin_to) node_to_ci_to = swap_clients[1].ci(coin_to)
@ -577,7 +584,7 @@ def run_test_ads_both_refund(
) )
assert ( assert (
bid.amount_to - node_to_ci_to.make_int(wtx["details"][0]["amount"]) bid.amount_to - node_to_ci_to.make_int(wtx["details"][0]["amount"])
< max_fee < self.max_fee
) )
bid_id_hex = bid_id.hex() bid_id_hex = bid_id.hex()
@ -720,6 +727,7 @@ class Test(BaseTest):
start_xmr_nodes = True start_xmr_nodes = True
dcr_mining_addr = "SsYbXyjkKAEXXcGdFgr4u4bo4L8RkCxwQpH" dcr_mining_addr = "SsYbXyjkKAEXXcGdFgr4u4bo4L8RkCxwQpH"
extra_wait_time = 0 extra_wait_time = 0
max_fee: int = 10000
hex_seeds = [ hex_seeds = [
"e8574b2a94404ee62d8acc0258cab4c0defcfab8a5dfc2f4954c1f9d7e09d72a", "e8574b2a94404ee62d8acc0258cab4c0defcfab8a5dfc2f4954c1f9d7e09d72a",

View file

@ -11,67 +11,38 @@ basicswap]$ python tests/basicswap/extended/test_nmc.py
""" """
import json
import logging import logging
import os import os
import shutil import random
import signal
import sys import sys
import threading
import time
import unittest import unittest
import basicswap.config as cfg import basicswap.config as cfg
from basicswap.basicswap import ( from basicswap.basicswap import (
BasicSwap,
Coins, Coins,
SwapTypes,
BidStates,
TxStates,
) )
from basicswap.util import ( from basicswap.util import (
COIN, toBool,
)
from basicswap.basicswap_util import (
TxLockTypes,
)
from basicswap.util.address import (
toWIF,
)
from basicswap.rpc import (
callrpc_cli,
)
from basicswap.contrib.key import (
ECKey,
) )
from basicswap.bin.run import startDaemon
from basicswap.contrib.rpcauth import generate_salt, password_to_hmac from basicswap.contrib.rpcauth import generate_salt, password_to_hmac
from basicswap.http_server import (
HttpThread,
)
from tests.basicswap.util import (
read_json_api,
)
from tests.basicswap.common import ( from tests.basicswap.common import (
checkForks,
stopDaemons, 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,
waitForRPC, waitForRPC,
make_rpc_func, make_rpc_func,
) )
from basicswap.bin.run import startDaemon
from tests.basicswap.test_btc_xmr import BasicSwapTest, test_delay_event
from tests.basicswap.test_xmr import NUM_NODES
from tests.basicswap.extended.test_dcr import (
run_test_success_path,
run_test_bad_ptx,
run_test_itx_refund,
)
logger = logging.getLogger() logger = logging.getLogger("BSX Tests")
logger.level = logging.DEBUG
if not len(logger.handlers): if not len(logger.handlers):
logger.addHandler(logging.StreamHandler(sys.stdout)) logger.addHandler(logging.StreamHandler(sys.stdout))
@ -83,19 +54,14 @@ NAMECOIND = os.getenv("NAMECOIND", "namecoind" + cfg.bin_suffix)
NAMECOIN_CLI = os.getenv("NAMECOIN_CLI", "namecoin-cli" + cfg.bin_suffix) NAMECOIN_CLI = os.getenv("NAMECOIN_CLI", "namecoin-cli" + cfg.bin_suffix)
NAMECOIN_TX = os.getenv("NAMECOIN_TX", "namecoin-tx" + cfg.bin_suffix) NAMECOIN_TX = os.getenv("NAMECOIN_TX", "namecoin-tx" + cfg.bin_suffix)
USE_DESCRIPTOR_WALLETS = toBool(os.getenv("USE_DESCRIPTOR_WALLETS", False))
NMC_BASE_PORT = 8136 NMC_BASE_PORT = 8136
NMC_BASE_RPC_PORT= 8146 NMC_BASE_RPC_PORT = 8146
NUM_NODES = 3
NMC_NODE = 3
BTC_NODE = 4
delay_event = threading.Event()
stop_test = False
def prepareOtherDir(datadir, nodeId, conf_file="namecoin.conf"): def prepareNMCDataDir(datadir, nodeId, conf_file="namecoin.conf"):
node_dir = os.path.join(datadir, str(nodeId)) node_dir = os.path.join(datadir, "nmc_" + str(nodeId))
if not os.path.exists(node_dir): if not os.path.exists(node_dir):
os.makedirs(node_dir) os.makedirs(node_dir)
filePath = os.path.join(node_dir, conf_file) filePath = os.path.join(node_dir, conf_file)
@ -104,20 +70,16 @@ def prepareOtherDir(datadir, nodeId, conf_file="namecoin.conf"):
fp.write("regtest=1\n") fp.write("regtest=1\n")
fp.write("[regtest]\n") fp.write("[regtest]\n")
if conf_file == "bitcoin.conf": fp.write("port=" + str(NMC_BASE_PORT + nodeId) + "\n")
fp.write("port=" + str(BASE_PORT + nodeId) + "\n") fp.write("rpcport=" + str(NMC_BASE_RPC_PORT + nodeId) + "\n")
fp.write("rpcport=" + str(BASE_RPC_PORT + nodeId) + "\n") salt = generate_salt(16)
else: fp.write(
fp.write("port=" + str(NMC_BASE_PORT + nodeId) + "\n") "rpcauth={}:{}${}\n".format(
fp.write("rpcport=" + str(NMC_BASE_RPC_PORT + nodeId) + "\n") "test" + str(nodeId),
salt = generate_salt(16) salt,
fp.write( password_to_hmac(salt, "test_pass" + str(nodeId)),
"rpcauth={}:{}${}\n".format(
"test" + str(nodeId),
salt,
password_to_hmac(salt, "test_pass" + str(nodeId)),
)
) )
)
fp.write("daemon=0\n") fp.write("daemon=0\n")
fp.write("printtoconsole=0\n") fp.write("printtoconsole=0\n")
@ -125,592 +87,171 @@ def prepareOtherDir(datadir, nodeId, conf_file="namecoin.conf"):
fp.write("discover=0\n") fp.write("discover=0\n")
fp.write("listenonion=0\n") fp.write("listenonion=0\n")
fp.write("bind=127.0.0.1\n") fp.write("bind=127.0.0.1\n")
fp.write("findpeers=0\n")
fp.write("debug=1\n") fp.write("debug=1\n")
fp.write("debugexclude=libevent\n") fp.write("debugexclude=libevent\n")
fp.write("fallbackfee=0.01\n") fp.write("fallbackfee=0.01\n")
fp.write("acceptnonstdtxn=0\n") fp.write("acceptnonstdtxn=0\n")
fp.write("deprecatedrpc=create_bdb\n") fp.write("deprecatedrpc=create_bdb\n")
fp.write("wallet=wallet.dat\n") fp.write("addresstype=bech32\n")
fp.write("changetype=bech32\n")
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("fallbackfee=0.01\n")
fp.write("acceptnonstdtxn=0\n")
fp.write("minstakeinterval=5\n")
fp.write("smsgsregtestadjust=0\n")
for i in range(0, NUM_NODES): for i in range(0, NUM_NODES):
if nodeId == i: if nodeId == i:
continue continue
fp.write("addnode=127.0.0.1:%d\n" % (BASE_PORT + i)) fp.write("addnode=127.0.0.1:{}\n".format(NMC_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)
nmcdatadir = os.path.join(datadir, str(NMC_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
},
"namecoin": {
"connection_type": "rpc",
"manage_daemon": False,
"rpcport": NMC_BASE_RPC_PORT + NMC_NODE,
"datadir": nmcdatadir,
"bindir": NAMECOIN_BINDIR,
"use_csv": True,
"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,
"restrict_unknown_seed_wallets": False,
}
with open(settings_path, "w") as fp:
json.dump(settings, fp, indent=4)
def partRpc(cmd, node_id=0): class TestNMC(BasicSwapTest):
return callrpc_cli( __test__ = True
cfg.PARTICL_BINDIR, test_coin = Coins.NMC
os.path.join(cfg.TEST_DATADIRS, str(node_id)), test_coin_from = Coins.NMC
"regtest", nmc_daemons = []
cmd, start_ltc_nodes = False
cfg.PARTICL_CLI, start_xmr_nodes = True
) base_rpc_port = NMC_BASE_RPC_PORT
nmc_addr = None
max_fee: int = 200000
test_fee_rate: int = 10000 # sats/kvB
def mineBlock(self, num_blocks: int = 1) -> None:
def btcRpc(cmd): self.callnoderpc("generatetoaddress", [num_blocks, self.nmc_addr])
return callrpc_cli(
cfg.BITCOIN_BINDIR,
os.path.join(cfg.TEST_DATADIRS, str(BTC_NODE)),
"regtest",
cmd,
cfg.BITCOIN_CLI,
)
def nmcRpc(cmd):
return callrpc_cli(
NAMECOIN_BINDIR,
os.path.join(cfg.TEST_DATADIRS, str(NMC_NODE)),
"regtest",
cmd,
NAMECOIN_CLI,
)
def signal_handler(sig, frame):
global stop_test
os.write(sys.stdout.fileno(), f"Signal {sig} detected.\n".encode("utf-8"))
stop_test = True
delay_event.set()
def run_coins_loop(cls):
while not stop_test:
try:
nmcRpc("generatetoaddress 1 {}".format(cls.nmc_addr))
btcRpc("generatetoaddress 1 {}".format(cls.btc_addr))
except Exception as e:
logging.warning("run_coins_loop " + str(e))
time.sleep(1.0)
def run_loop(self):
while not stop_test:
for c in self.swap_clients:
c.update()
time.sleep(1)
def make_part_cli_rpc_func(node_id):
node_id = node_id
def rpc_func(method, params=None, wallet=None):
cmd = method
if params:
for p in params:
cmd += ' "' + p + '"'
return partRpc(cmd, node_id)
return rpc_func
class Test(unittest.TestCase):
@classmethod @classmethod
def setUpClass(cls): def tearDownClass(cls):
super(Test, cls).setUpClass() logging.info("Finalising Namecoin Test")
stopDaemons(cls.nmc_daemons)
cls.nmc_daemons.clear()
eckey = ECKey() super(TestNMC, cls).tearDownClass()
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): @classmethod
logging.info("Removing " + cfg.TEST_DATADIRS) def coins_loop(cls):
shutil.rmtree(cfg.TEST_DATADIRS) super(TestNMC, cls).coins_loop()
ci0 = cls.swap_clients[0].ci(cls.test_coin)
try:
if cls.nmc_addr is not None:
ci0.rpc_wallet("generatetoaddress", [1, cls.nmc_addr])
except Exception as e:
logging.warning(f"coins_loop generate {e}")
for i in range(NUM_NODES): @classmethod
prepareDir(cfg.TEST_DATADIRS, i, cls.network_key, cls.network_pubkey) def prepareExtraDataDir(cls, i: int) -> None:
if not cls.restore_instance:
prepareNMCDataDir(cfg.TEST_DATADIRS, i)
prepareOtherDir(cfg.TEST_DATADIRS, NMC_NODE) cls.nmc_daemons.append(
prepareOtherDir(cfg.TEST_DATADIRS, BTC_NODE, "bitcoin.conf")
cls.daemons = []
cls.swap_clients = []
cls.http_threads = []
btc_data_dir = os.path.join(cfg.TEST_DATADIRS, str(BTC_NODE))
if os.path.exists(os.path.join(cfg.BITCOIN_BINDIR, "bitcoin-wallet")):
callrpc_cli(
cfg.BITCOIN_BINDIR,
btc_data_dir,
"regtest",
"-wallet=wallet.dat -legacy create",
"bitcoin-wallet",
)
cls.daemons.append(startDaemon(btc_data_dir, cfg.BITCOIN_BINDIR, cfg.BITCOIND))
logging.info("Started %s %d", cfg.BITCOIND, cls.daemons[-1].handle.pid)
cls.daemons.append(
startDaemon( startDaemon(
os.path.join(cfg.TEST_DATADIRS, str(NMC_NODE)), os.path.join(cfg.TEST_DATADIRS, "nmc_" + str(i)),
NAMECOIN_BINDIR, NAMECOIN_BINDIR,
NAMECOIND, NAMECOIND,
) )
) )
logging.info("Started %s %d", NAMECOIND, cls.daemons[-1].handle.pid) logging.info("Started {} {}".format(NAMECOIND, cls.nmc_daemons[-1].handle.pid))
nmcRpc2 = make_rpc_func(NMC_NODE, base_rpc_port=NMC_BASE_RPC_PORT)
waitForRPC(nmcRpc2, delay_event, rpc_command="getblockchaininfo")
if len(nmcRpc2("listwallets")) < 1:
nmcRpc2("createwallet", ["wallet.dat", False, False, "", False, False])
for i in range(NUM_NODES): nmc_rpc = make_rpc_func(i, base_rpc_port=NMC_BASE_RPC_PORT)
data_dir = os.path.join(cfg.TEST_DATADIRS, str(i)) waitForRPC(
if os.path.exists(os.path.join(cfg.PARTICL_BINDIR, "particl-wallet")): nmc_rpc,
callrpc_cli( test_delay_event,
cfg.PARTICL_BINDIR, rpc_command="getnetworkinfo",
data_dir, max_tries=12,
"regtest", )
"-wallet=wallet.dat -legacy create", waitForRPC(nmc_rpc, test_delay_event, rpc_command="getblockchaininfo")
"particl-wallet", if len(nmc_rpc("listwallets")) < 1:
) nmc_rpc(
cls.daemons.append(startDaemon(data_dir, cfg.PARTICL_BINDIR, cfg.PARTICLD)) "createwallet",
logging.info("Started %s %d", cfg.PARTICLD, cls.daemons[-1].handle.pid) ["wallet.dat", False, False, "", False, USE_DESCRIPTOR_WALLETS],
for i in range(NUM_NODES):
rpc = make_part_cli_rpc_func(i)
waitForRPC(rpc, delay_event)
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"]])
rpc(
"walletsettings",
[
"stakingoptions",
json.dumps(
{"stakecombinethreshold": 100, "stakesplitthreshold": 200}
).replace('"', '\\"'),
],
) )
rpc("reservebalance", ["false"])
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)
sc = BasicSwap(
basicswap_dir, settings, "regtest", log_name="BasicSwap{}".format(i)
)
cls.swap_clients.append(sc)
sc.setDaemonPID(Coins.BTC, cls.daemons[0].handle.pid)
sc.setDaemonPID(Coins.NMC, cls.daemons[1].handle.pid)
sc.setDaemonPID(Coins.PART, cls.daemons[2 + i].handle.pid)
sc.start()
t = HttpThread(TEST_HTTP_HOST, TEST_HTTP_PORT + i, False, sc)
cls.http_threads.append(t)
t.start()
num_blocks = 500
logging.info("Mining %d namecoin blocks", num_blocks)
cls.nmc_addr = nmcRpc("getnewaddress mining_addr bech32")
nmcRpc("generatetoaddress {} {}".format(num_blocks, cls.nmc_addr))
ro = nmcRpc("getblockchaininfo")
try:
assert ro["bip9_softforks"]["csv"]["status"] == "active"
except Exception:
logging.info("nmc: csv is not active")
try:
assert ro["bip9_softforks"]["segwit"]["status"] == "active"
except Exception:
logging.info("nmc: segwit is not active")
waitForRPC(btcRpc, delay_event)
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 = nmcRpc("getwalletinfo")
print("nmcRpc", 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("getblockcount")
print("particl_blocks", particl_blocks)
if particl_blocks >= num_blocks:
break
delay_event.wait(1)
assert particl_blocks >= num_blocks
@classmethod @classmethod
def tearDownClass(cls): def addPIDInfo(cls, sc, i):
global stop_test sc.setDaemonPID(Coins.DCR, cls.nmc_daemons[i].handle.pid)
logging.info("Finalising")
stop_test = True
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()
stopDaemons(cls.daemons) @classmethod
cls.http_threads.clear() def addCoinSettings(cls, settings, datadir, node_id):
cls.swap_clients.clear() settings["chainclients"]["namecoin"] = {
cls.daemons.clear() "connection_type": "rpc",
"manage_daemon": False,
"rpcport": NMC_BASE_RPC_PORT + node_id,
"rpcuser": "test" + str(node_id),
"rpcpassword": "test_pass" + str(node_id),
"datadir": os.path.join(datadir, "nmc_" + str(node_id)),
"bindir": NAMECOIN_BINDIR,
"use_csv": True,
"use_segwit": True,
"blocks_confirmed": 1,
}
super(Test, cls).tearDownClass() @classmethod
def prepareExtraCoins(cls):
def test_02_part_nmc(self): ci0 = cls.swap_clients[0].ci(cls.test_coin)
logging.info("---------- Test PART to NMC") if not cls.restore_instance:
swap_clients = self.swap_clients cls.nmc_addr = ci0.rpc_wallet("getnewaddress", ["mining_addr", "bech32"])
else:
offer_id = swap_clients[0].postOffer( addrs = ci0.rpc_wallet(
Coins.PART, "getaddressesbylabel",
Coins.NMC, [
100 * COIN, "mining_addr",
0.1 * COIN, ],
100 * COIN,
SwapTypes.SELLER_FIRST
)
wait_for_offer(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)
swap_clients[0].acceptBid(bid_id)
wait_for_in_progress(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,
)
js_0 = read_json_api(1800)
js_1 = read_json_api(1801)
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_nmc_part(self):
logging.info("---------- Test NMC to PART")
swap_clients = self.swap_clients
offer_id = swap_clients[1].postOffer(
Coins.NMC,
Coins.PART,
10 * COIN,
9.0 * COIN,
10 * COIN,
SwapTypes.SELLER_FIRST
)
wait_for_offer(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)
swap_clients[1].acceptBid(bid_id)
wait_for_in_progress(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
)
js_0 = read_json_api(1800)
js_1 = read_json_api(1801)
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_nmc_btc(self):
logging.info("---------- Test NMC to BTC")
swap_clients = self.swap_clients
offer_id = swap_clients[0].postOffer(
Coins.NMC,
Coins.BTC,
10 * COIN,
0.1 * COIN,
10 * COIN,
SwapTypes.SELLER_FIRST
)
wait_for_offer(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)
swap_clients[0].acceptBid(bid_id)
wait_for_in_progress(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,
)
js_0 = read_json_api(1800)
js_1 = read_json_api(1801)
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, NMC to BTC")
swap_clients = self.swap_clients
offer_id = swap_clients[0].postOffer(
Coins.NMC,
Coins.BTC,
10 * COIN,
0.1 * COIN,
10 * COIN,
SwapTypes.SELLER_FIRST,
TxLockTypes.SEQUENCE_LOCK_BLOCKS,
10,
)
wait_for_offer(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)
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,
)
js_0 = read_json_api(1800)
js_1 = read_json_api(1801)
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 NMC")
swap_clients = self.swap_clients
js_0_before = read_json_api(1800)
offer_id = swap_clients[0].postOffer(
Coins.NMC,
Coins.BTC,
10 * COIN,
10 * COIN,
10 * COIN,
SwapTypes.SELLER_FIRST
)
wait_for_offer(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)
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
)
js_0 = read_json_api(1800)
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 NMC, set fee above bid value")
swap_clients = self.swap_clients
offer_id = swap_clients[0].postOffer(
Coins.NMC,
Coins.BTC,
0.01 * COIN,
1.0 * COIN,
0.01 * COIN,
SwapTypes.SELLER_FIRST
)
wait_for_offer(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)
swap_clients[0].acceptBid(bid_id)
try:
swap_clients[0].getChainClientSettings(Coins.BTC)["override_feerate"] = 100.0
swap_clients[0].getChainClientSettings(Coins.NMC)["override_feerate"] = 100.0
wait_for_bid(
delay_event, swap_clients[0], bid_id, BidStates.BID_ERROR, wait_for=60
) )
swap_clients[0].abandonBid(bid_id) cls.nmc_addr = addrs.keys()[0]
finally:
del swap_clients[0].getChainClientSettings(Coins.BTC)["override_feerate"]
del swap_clients[0].getChainClientSettings(Coins.NMC)["override_feerate"]
def pass_99_delay(self): num_blocks: int = 500
global stop_test if ci0.rpc("getblockcount") < num_blocks:
logging.info("Delay") logging.info(f"Mining {num_blocks} Namecoin blocks to {cls.nmc_addr}")
for i in range(60 * 5): ci0.rpc("generatetoaddress", [num_blocks, cls.nmc_addr])
if stop_test: logging.info("NMC blocks: {}".format(ci0.rpc("getblockcount")))
break
time.sleep(1) def test_007_hdwallet(self):
print("delay", i) logging.info("---------- Test {} hdwallet".format(self.test_coin_from.name))
stop_test = True
test_seed = "8e54a313e6df8918df6d758fafdbf127a115175fdd2238d0e908dd8093c9ac3b"
test_wif = (
self.swap_clients[0]
.ci(self.test_coin_from)
.encodeKey(bytes.fromhex(test_seed))
)
new_wallet_name = random.randbytes(10).hex()
self.callnoderpc(
"createwallet",
[new_wallet_name, False, False, "", False, USE_DESCRIPTOR_WALLETS],
)
self.callnoderpc("sethdseed", [True, test_wif], wallet=new_wallet_name)
addr = self.callnoderpc(
"getnewaddress", ["add test", "bech32"], wallet=new_wallet_name
)
self.callnoderpc("unloadwallet", [new_wallet_name])
assert addr == "ncrt1qps7hnjd866e9ynxadgseprkc2l56m00dxkl7pk"
def test_012_p2sh_p2wsh(self):
# Fee rate
pass
def test_02_sh_part_coin(self):
self.prepare_balance(self.test_coin, 200.0, 1801, 1800)
run_test_success_path(self, Coins.PART, self.test_coin)
def test_03_sh_coin_part(self):
run_test_success_path(self, self.test_coin, Coins.PART)
def test_04_sh_part_coin_bad_ptx(self):
self.prepare_balance(self.test_coin, 200.0, 1801, 1800)
run_test_bad_ptx(self, Coins.PART, self.test_coin)
def test_05_sh_coin_part_bad_ptx(self):
self.prepare_balance(self.test_coin, 200.0, 1801, 1800)
run_test_bad_ptx(self, self.test_coin, Coins.PART)
def test_06_sh_part_coin_itx_refund(self):
run_test_itx_refund(self, Coins.PART, self.test_coin)
def test_07_sh_coin_part_itx_refund(self):
self.prepare_balance(self.test_coin, 200.0, 1801, 1800)
run_test_itx_refund(self, self.test_coin, Coins.PART)
def test_01_b_full_swap_reverse(self):
self.prepare_balance(self.test_coin, 100.0, 1801, 1800)
self.do_test_01_full_swap(Coins.XMR, self.test_coin_from)
if __name__ == "__main__": if __name__ == "__main__":

View file

@ -59,7 +59,6 @@ from basicswap.contrib.test_framework.script import (
from .test_xmr import BaseTest, test_delay_event, callnoderpc from .test_xmr import BaseTest, test_delay_event, callnoderpc
logger = logging.getLogger() logger = logging.getLogger()
test_seed = "8e54a313e6df8918df6d758fafdbf127a115175fdd2238d0e908dd8093c9ac3b" test_seed = "8e54a313e6df8918df6d758fafdbf127a115175fdd2238d0e908dd8093c9ac3b"
@ -666,7 +665,7 @@ class TestFunctions(BaseTest):
balance_from_before: float = self.getBalance(jsw, coin_from) balance_from_before: float = self.getBalance(jsw, coin_from)
self.prepare_balance( self.prepare_balance(
coin_to, coin_to,
balance_from_before + 1, balance_from_before * 3,
1800 + id_bidder, 1800 + id_bidder,
1801 if coin_to in (Coins.XMR,) else 1800, 1801 if coin_to in (Coins.XMR,) else 1800,
) )
@ -718,6 +717,7 @@ class TestFunctions(BaseTest):
assert False, "Should fail" assert False, "Should fail"
amt_swap -= ci_from.make_int(1) amt_swap -= ci_from.make_int(1)
rate_swap = ci_to.make_int(1.0, r=1)
offer_id = swap_clients[id_offerer].postOffer( offer_id = swap_clients[id_offerer].postOffer(
coin_from, coin_from,
coin_to, coin_to,
@ -770,6 +770,8 @@ class TestFunctions(BaseTest):
class BasicSwapTest(TestFunctions): class BasicSwapTest(TestFunctions):
test_fee_rate: int = 1000 # sats/kvB
@classmethod @classmethod
def setUpClass(cls): def setUpClass(cls):
super(BasicSwapTest, cls).setUpClass() super(BasicSwapTest, cls).setUpClass()
@ -1236,12 +1238,7 @@ class BasicSwapTest(TestFunctions):
swap_client = self.swap_clients[0] swap_client = self.swap_clients[0]
ci = swap_client.ci(self.test_coin_from) ci = swap_client.ci(self.test_coin_from)
addr_1 = ci.rpc_wallet( addr_1 = ci.getNewAddress(True, "gettxout test 1")
"getnewaddress",
[
"gettxout test 1",
],
)
txid = ci.rpc_wallet("sendtoaddress", [addr_1, 1.0]) txid = ci.rpc_wallet("sendtoaddress", [addr_1, 1.0])
assert len(txid) == 64 assert len(txid) == 64
@ -1266,12 +1263,7 @@ class BasicSwapTest(TestFunctions):
else: else:
assert addr_1 in txout["scriptPubKey"]["addresses"] assert addr_1 in txout["scriptPubKey"]["addresses"]
# Spend # Spend
addr_2 = ci.rpc_wallet( addr_2 = ci.getNewAddress(True, "gettxout test 2")
"getnewaddress",
[
"gettxout test 2",
],
)
tx_funded = ci.rpc( tx_funded = ci.rpc(
"createrawtransaction", "createrawtransaction",
[[{"txid": utxo["txid"], "vout": utxo["vout"]}], {addr_2: 0.99}], [[{"txid": utxo["txid"], "vout": utxo["vout"]}], {addr_2: 0.99}],
@ -1297,12 +1289,7 @@ class BasicSwapTest(TestFunctions):
logging.info("---------- Test {} scantxoutset".format(self.test_coin_from.name)) logging.info("---------- Test {} scantxoutset".format(self.test_coin_from.name))
ci = self.swap_clients[0].ci(self.test_coin_from) ci = self.swap_clients[0].ci(self.test_coin_from)
addr_1 = ci.rpc_wallet( addr_1 = ci.getNewAddress(True, "scantxoutset test")
"getnewaddress",
[
"scantxoutset test",
],
)
txid = ci.rpc_wallet("sendtoaddress", [addr_1, 1.0]) txid = ci.rpc_wallet("sendtoaddress", [addr_1, 1.0])
assert len(txid) == 64 assert len(txid) == 64
@ -1324,9 +1311,6 @@ class BasicSwapTest(TestFunctions):
# Record unspents before createSCLockTx as the used ones will be locked # Record unspents before createSCLockTx as the used ones will be locked
unspents = ci.rpc_wallet("listunspent") unspents = ci.rpc_wallet("listunspent")
# fee_rate is in sats/kvB
fee_rate: int = 1000
a = ci.getNewRandomKey() a = ci.getNewRandomKey()
b = ci.getNewRandomKey() b = ci.getNewRandomKey()
@ -1335,7 +1319,7 @@ class BasicSwapTest(TestFunctions):
lock_tx_script = pi.genScriptLockTxScript(ci, A, B) lock_tx_script = pi.genScriptLockTxScript(ci, A, B)
lock_tx = ci.createSCLockTx(amount, lock_tx_script) lock_tx = ci.createSCLockTx(amount, lock_tx_script)
lock_tx = ci.fundSCLockTx(lock_tx, fee_rate) lock_tx = ci.fundSCLockTx(lock_tx, self.test_fee_rate)
lock_tx = ci.signTxWithWallet(lock_tx) lock_tx = ci.signTxWithWallet(lock_tx)
unspents_after = ci.rpc_wallet("listunspent") unspents_after = ci.rpc_wallet("listunspent")
@ -1345,7 +1329,7 @@ class BasicSwapTest(TestFunctions):
txid = tx_decoded["txid"] txid = tx_decoded["txid"]
vsize = tx_decoded["vsize"] vsize = tx_decoded["vsize"]
expect_fee_int = round(fee_rate * vsize / 1000) expect_fee_int = round(self.test_fee_rate * vsize / 1000)
out_value: int = 0 out_value: int = 0
for txo in tx_decoded["vout"]: for txo in tx_decoded["vout"]:
@ -1372,7 +1356,7 @@ class BasicSwapTest(TestFunctions):
pkh_out = ci.decodeAddress(addr_out) pkh_out = ci.decodeAddress(addr_out)
fee_info = {} fee_info = {}
lock_spend_tx = ci.createSCLockSpendTx( lock_spend_tx = ci.createSCLockSpendTx(
lock_tx, lock_tx_script, pkh_out, fee_rate, fee_info=fee_info lock_tx, lock_tx_script, pkh_out, self.test_fee_rate, fee_info=fee_info
) )
vsize_estimated: int = fee_info["vsize"] vsize_estimated: int = fee_info["vsize"]
@ -1400,11 +1384,11 @@ class BasicSwapTest(TestFunctions):
v = ci.getNewRandomKey() v = ci.getNewRandomKey()
s = ci.getNewRandomKey() s = ci.getNewRandomKey()
S = ci.getPubkey(s) S = ci.getPubkey(s)
lock_tx_b_txid = ci.publishBLockTx(v, S, amount, fee_rate) lock_tx_b_txid = ci.publishBLockTx(v, S, amount, self.test_fee_rate)
addr_out = ci.getNewAddress(True) addr_out = ci.getNewAddress(True)
lock_tx_b_spend_txid = ci.spendBLockTx( lock_tx_b_spend_txid = ci.spendBLockTx(
lock_tx_b_txid, addr_out, v, s, amount, fee_rate, 0 lock_tx_b_txid, addr_out, v, s, amount, self.test_fee_rate, 0
) )
lock_tx_b_spend = ci.getTransaction(lock_tx_b_spend_txid) lock_tx_b_spend = ci.getTransaction(lock_tx_b_spend_txid)
if lock_tx_b_spend is None: if lock_tx_b_spend is None:
@ -1635,7 +1619,9 @@ class BasicSwapTest(TestFunctions):
wallet=new_wallet_name, wallet=new_wallet_name,
) )
addr = self.callnoderpc("getnewaddress", wallet=new_wallet_name) addr = self.callnoderpc(
"getnewaddress", ["test descriptors"], wallet=new_wallet_name
)
addr_info = self.callnoderpc( addr_info = self.callnoderpc(
"getaddressinfo", "getaddressinfo",
[ [
@ -1645,7 +1631,8 @@ class BasicSwapTest(TestFunctions):
) )
assert addr_info["hdmasterfingerprint"] == "a55b7ea9" assert addr_info["hdmasterfingerprint"] == "a55b7ea9"
assert addr_info["hdkeypath"] == "m/0h/0h/0h" assert addr_info["hdkeypath"] == "m/0h/0h/0h"
assert addr == "bcrt1qps7hnjd866e9ynxadgseprkc2l56m00dvwargr" if self.test_coin_from == Coins.BTC:
assert addr == "bcrt1qps7hnjd866e9ynxadgseprkc2l56m00dvwargr"
addr_change = self.callnoderpc("getrawchangeaddress", wallet=new_wallet_name) addr_change = self.callnoderpc("getrawchangeaddress", wallet=new_wallet_name)
addr_info = self.callnoderpc( addr_info = self.callnoderpc(
@ -1657,7 +1644,8 @@ class BasicSwapTest(TestFunctions):
) )
assert addr_info["hdmasterfingerprint"] == "a55b7ea9" assert addr_info["hdmasterfingerprint"] == "a55b7ea9"
assert addr_info["hdkeypath"] == "m/0h/1h/0h" assert addr_info["hdkeypath"] == "m/0h/1h/0h"
assert addr_change == "bcrt1qdl9ryxkqjltv42lhfnqgdjf9tagxsjpp2xak9a" if self.test_coin_from == Coins.BTC:
assert addr_change == "bcrt1qdl9ryxkqjltv42lhfnqgdjf9tagxsjpp2xak9a"
desc_watch = descsum_create(f"addr({addr})") desc_watch = descsum_create(f"addr({addr})")
self.callnoderpc( self.callnoderpc(
@ -1683,7 +1671,13 @@ class BasicSwapTest(TestFunctions):
# Test that addresses can be generated beyond range in listdescriptors # Test that addresses can be generated beyond range in listdescriptors
for i in range(2000): for i in range(2000):
self.callnoderpc("getnewaddress", wallet=new_wallet_name) self.callnoderpc(
"getnewaddress",
[
f"t{i}",
],
wallet=new_wallet_name,
)
self.callnoderpc("unloadwallet", [new_wallet_name]) self.callnoderpc("unloadwallet", [new_wallet_name])
self.callnoderpc("unloadwallet", [new_watch_wallet_name]) self.callnoderpc("unloadwallet", [new_watch_wallet_name])