From 24c8e8b2ddb73e8c82d1264241e3577c0f1c9ced Mon Sep 17 00:00:00 2001 From: tecnovert Date: Wed, 27 May 2026 23:51:51 +0200 Subject: [PATCH 1/5] refactor: remove duplicate method --- basicswap/basicswap.py | 4 ++-- basicswap/interface/base.py | 6 ------ 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/basicswap/basicswap.py b/basicswap/basicswap.py index a08cbe8..2c27b18 100644 --- a/basicswap/basicswap.py +++ b/basicswap/basicswap.py @@ -3965,7 +3965,7 @@ class BasicSwap(BaseApp, BSXNetwork, UIApp): def isValidSwapDest(self, ci, dest: bytes): ensure(isinstance(dest, bytes), "Swap destination must be bytes") if ci.coin_type() in (Coins.PART_BLIND,): - return ci.isValidPubkey(dest) + return ci.verifyPubkey(dest) # TODO: allow p2wsh return ci.isValidAddressHash(dest) @@ -10905,7 +10905,7 @@ class BasicSwap(BaseApp, BSXNetwork, UIApp): ) ensure( ci_from.isValidAddressHash(bid_data.dest_af) - or ci_from.isValidPubkey(bid_data.dest_af), + or ci_from.verifyPubkey(bid_data.dest_af), "Invalid destination address", ) diff --git a/basicswap/interface/base.py b/basicswap/interface/base.py index 295e9d7..9ed10ef 100644 --- a/basicswap/interface/base.py +++ b/basicswap/interface/base.py @@ -220,12 +220,6 @@ class Secp256k1Interface(CoinInterface, AdaptorSigInterface): if hash_len == 20: return True - def isValidPubkey(self, pubkey: bytes) -> bool: - try: - return self.verifyPubkey(pubkey) - except Exception: - return False - def verifySig(self, pubkey: bytes, signed_hash: bytes, sig: bytes) -> bool: pubkey = PublicKey(pubkey) return pubkey.verify(sig, signed_hash, hasher=None) From e8ebfd34d082dc7aacd2128f04f6edff2d520e16 Mon Sep 17 00:00:00 2001 From: tecnovert Date: Thu, 28 May 2026 01:55:36 +0200 Subject: [PATCH 2/5] refactor: black --- basicswap/basicswap.py | 9 ++------- basicswap/db.py | 1 - basicswap/explorers.py | 1 - basicswap/interface/btc.py | 1 - basicswap/interface/dcr/dcr.py | 1 - basicswap/interface/dcr/util.py | 2 +- basicswap/interface/xmr.py | 1 - basicswap/messages_npb.py | 1 - basicswap/network/network.py | 1 - basicswap/network/simplex_chat.py | 2 +- basicswap/util/__init__.py | 1 - basicswap/util/smsg.py | 1 - tests/basicswap/common.py | 1 - tests/basicswap/common_xmr.py | 1 - tests/basicswap/extended/test_dash.py | 1 - tests/basicswap/extended/test_doge_with_prepare.py | 1 - tests/basicswap/extended/test_key_paths.py | 1 - tests/basicswap/extended/test_network.py | 1 - tests/basicswap/extended/test_nmc.py | 1 - tests/basicswap/extended/test_pivx.py | 1 - tests/basicswap/extended/test_scripts.py | 1 - tests/basicswap/selenium/test_recover_chain_b_lock_tx.py | 1 - tests/basicswap/selenium/test_swap_direction.py | 1 - tests/basicswap/selenium/util.py | 1 - tests/basicswap/test_other.py | 1 - tests/basicswap/test_run.py | 1 - tests/basicswap/test_xmr.py | 1 - tests/basicswap/util.py | 1 - 28 files changed, 4 insertions(+), 34 deletions(-) diff --git a/basicswap/basicswap.py b/basicswap/basicswap.py index 2c27b18..2634bc9 100644 --- a/basicswap/basicswap.py +++ b/basicswap/basicswap.py @@ -166,7 +166,6 @@ import basicswap.network.network as bsn import basicswap.protocols.atomic_swap_1 as atomic_swap_1 import basicswap.protocols.xmr_swap_1 as xmr_swap_1 - PROTOCOL_VERSION_SECRET_HASH = 5 MINPROTO_VERSION_SECRET_HASH = 4 @@ -13811,8 +13810,7 @@ class BasicSwap(BaseApp, BSXNetwork, UIApp): num_watched_outputs += len(v["watched_outputs"]) now: int = self.getTime() - q_bids_str: str = ( - """SELECT + q_bids_str: str = """SELECT COUNT(CASE WHEN b.was_sent THEN 1 ELSE NULL END) AS count_sent, COUNT(CASE WHEN b.was_sent AND (s.in_progress OR (s.swap_ended = 0 AND b.expire_at > :now AND o.expire_at > :now)) THEN 1 ELSE NULL END) AS count_sent_active, COUNT(CASE WHEN b.was_received THEN 1 ELSE NULL END) AS count_received, @@ -13822,15 +13820,12 @@ class BasicSwap(BaseApp, BSXNetwork, UIApp): JOIN offers o ON b.offer_id = o.offer_id JOIN bidstates s ON b.state = s.state_id WHERE b.active_ind = 1""" - ) - q_offers_str: str = ( - """SELECT + q_offers_str: str = """SELECT COUNT(CASE WHEN expire_at > :now THEN 1 ELSE NULL END) AS count_active, COUNT(CASE WHEN was_sent THEN 1 ELSE NULL END) AS count_sent, COUNT(CASE WHEN was_sent AND expire_at > :now THEN 1 ELSE NULL END) AS count_sent_active FROM offers WHERE active_ind = 1""" - ) try: cursor = self.openDB() diff --git a/basicswap/db.py b/basicswap/db.py index c3bdc47..d310f44 100644 --- a/basicswap/db.py +++ b/basicswap/db.py @@ -12,7 +12,6 @@ import time from enum import IntEnum, auto from typing import Optional - CURRENT_DB_VERSION = 34 CURRENT_DB_DATA_VERSION = 8 diff --git a/basicswap/explorers.py b/basicswap/explorers.py index b34f254..fcc2035 100644 --- a/basicswap/explorers.py +++ b/basicswap/explorers.py @@ -7,7 +7,6 @@ import json - default_coingecko_api_key = "CG-8hm3r9iLfpEXv4ied8oLbeUj" diff --git a/basicswap/interface/btc.py b/basicswap/interface/btc.py index d9121af..5704c76 100644 --- a/basicswap/interface/btc.py +++ b/basicswap/interface/btc.py @@ -99,7 +99,6 @@ from basicswap.basicswap_util import TxLockTypes from basicswap.chainparams import Coins from basicswap.rpc import make_rpc_func, openrpc - SEQUENCE_LOCKTIME_GRANULARITY = 9 # 512 seconds SEQUENCE_LOCKTIME_TYPE_FLAG = 1 << 22 SEQUENCE_LOCKTIME_MASK = 0x0000FFFF diff --git a/basicswap/interface/dcr/dcr.py b/basicswap/interface/dcr/dcr.py index ded8ad5..c200c2d 100644 --- a/basicswap/interface/dcr/dcr.py +++ b/basicswap/interface/dcr/dcr.py @@ -82,7 +82,6 @@ from coincurve.ecdsaotves import ( ecdsaotves_rec_enc_key, ) - SEQUENCE_LOCKTIME_GRANULARITY = 9 # 512 seconds SEQUENCE_LOCKTIME_TYPE_FLAG = 1 << 22 SEQUENCE_LOCKTIME_MASK = 0x0000F diff --git a/basicswap/interface/dcr/util.py b/basicswap/interface/dcr/util.py index b49de29..ffff96b 100644 --- a/basicswap/interface/dcr/util.py +++ b/basicswap/interface/dcr/util.py @@ -13,7 +13,7 @@ import subprocess def createDCRWallet(args, hex_seed, logging, delay_event): logging.info("Creating DCR wallet") - (pipe_r, pipe_w) = os.pipe() # subprocess.PIPE is buffered, blocks when read + pipe_r, pipe_w = os.pipe() # subprocess.PIPE is buffered, blocks when read if os.name == "nt": str_args = " ".join(args) diff --git a/basicswap/interface/xmr.py b/basicswap/interface/xmr.py index 0ce9de2..d30e93a 100644 --- a/basicswap/interface/xmr.py +++ b/basicswap/interface/xmr.py @@ -34,7 +34,6 @@ from basicswap.rpc_xmr import make_xmr_rpc_func, make_xmr_rpc2_func from basicswap.chainparams import XMR_COIN, Coins from basicswap.interface.base import CoinInterface - ed25519_l = 2**252 + 27742317777372353535851937790883648493 diff --git a/basicswap/messages_npb.py b/basicswap/messages_npb.py index c513714..4192fb9 100644 --- a/basicswap/messages_npb.py +++ b/basicswap/messages_npb.py @@ -23,7 +23,6 @@ protobuf ParseFromString would reset the whole object, from_bytes won't. from basicswap.util.integer import encode_varint, decode_varint - NPBW_INT = 0 NPBW_BYTES = 2 diff --git a/basicswap/network/network.py b/basicswap/network/network.py index 7e424a3..53f20df 100644 --- a/basicswap/network/network.py +++ b/basicswap/network/network.py @@ -39,7 +39,6 @@ from basicswap.contrib.rfc6979 import ( rfc6979_hmac_sha256_generate, ) - START_TOKEN = 0xABCD MSG_START_TOKEN = START_TOKEN.to_bytes(2, "big") diff --git a/basicswap/network/simplex_chat.py b/basicswap/network/simplex_chat.py index 987239d..cbd47b6 100644 --- a/basicswap/network/simplex_chat.py +++ b/basicswap/network/simplex_chat.py @@ -53,7 +53,7 @@ def initSimplexClient(args, logger, delay_event): # TODO: Must be a better way? logger.info("Initialising Simplex client") - (pipe_r, pipe_w) = os.pipe() # subprocess.PIPE is buffered, blocks when read + pipe_r, pipe_w = os.pipe() # subprocess.PIPE is buffered, blocks when read if os.name == "nt": str_args = " ".join(args) diff --git a/basicswap/util/__init__.py b/basicswap/util/__init__.py index b8d1b37..b29f4bd 100644 --- a/basicswap/util/__init__.py +++ b/basicswap/util/__init__.py @@ -10,7 +10,6 @@ import json import time import decimal - COIN = 100000000 diff --git a/basicswap/util/smsg.py b/basicswap/util/smsg.py index 3bdcd7e..3422b54 100644 --- a/basicswap/util/smsg.py +++ b/basicswap/util/smsg.py @@ -25,7 +25,6 @@ from basicswap.contrib.test_framework.messages import ( uint256_from_str, ) - AES_BLOCK_SIZE = 16 diff --git a/tests/basicswap/common.py b/tests/basicswap/common.py index 5f0c2af..066549f 100644 --- a/tests/basicswap/common.py +++ b/tests/basicswap/common.py @@ -21,7 +21,6 @@ from basicswap.util import toBool from basicswap.contrib.rpcauth import generate_salt, password_to_hmac from basicswap.bin.prepare import downloadPIVXParams - TEST_HTTP_HOST = os.getenv( "TEST_HTTP_HOST", "127.0.0.1" ) # Set to 0.0.0.0 when used in docker diff --git a/tests/basicswap/common_xmr.py b/tests/basicswap/common_xmr.py index 9ef8179..b4de182 100644 --- a/tests/basicswap/common_xmr.py +++ b/tests/basicswap/common_xmr.py @@ -56,7 +56,6 @@ from tests.basicswap.extended.test_doge import ( import basicswap.config as cfg import basicswap.bin.run as runSystem - TEST_PATH = os.path.expanduser(os.getenv("TEST_PATH", "~/test_basicswap1")) PARTICL_PORT_BASE = int(os.getenv("PARTICL_PORT_BASE", BASE_PORT)) diff --git a/tests/basicswap/extended/test_dash.py b/tests/basicswap/extended/test_dash.py index 59fca97..c052f78 100644 --- a/tests/basicswap/extended/test_dash.py +++ b/tests/basicswap/extended/test_dash.py @@ -65,7 +65,6 @@ from tests.basicswap.common import ( ) from basicswap.bin.run import startDaemon - logger = logging.getLogger() logger.level = logging.DEBUG if not len(logger.handlers): diff --git a/tests/basicswap/extended/test_doge_with_prepare.py b/tests/basicswap/extended/test_doge_with_prepare.py index 80712a7..7402732 100644 --- a/tests/basicswap/extended/test_doge_with_prepare.py +++ b/tests/basicswap/extended/test_doge_with_prepare.py @@ -34,7 +34,6 @@ from tests.basicswap.util import ( read_json_api, ) - logger = logging.getLogger() logger.level = logging.DEBUG if not len(logger.handlers): diff --git a/tests/basicswap/extended/test_key_paths.py b/tests/basicswap/extended/test_key_paths.py index 8dcc16d..3c66b37 100644 --- a/tests/basicswap/extended/test_key_paths.py +++ b/tests/basicswap/extended/test_key_paths.py @@ -31,7 +31,6 @@ from tests.basicswap.util import ( waitForServer, ) - logger = logging.getLogger() logger.level = logging.DEBUG if not len(logger.handlers): diff --git a/tests/basicswap/extended/test_network.py b/tests/basicswap/extended/test_network.py index 6b1a109..d9725ff 100644 --- a/tests/basicswap/extended/test_network.py +++ b/tests/basicswap/extended/test_network.py @@ -58,7 +58,6 @@ from tests.basicswap.common import ( from basicswap.bin.run import startDaemon - logger = logging.getLogger() NUM_NODES = 3 diff --git a/tests/basicswap/extended/test_nmc.py b/tests/basicswap/extended/test_nmc.py index bfac72d..a7e33df 100644 --- a/tests/basicswap/extended/test_nmc.py +++ b/tests/basicswap/extended/test_nmc.py @@ -40,7 +40,6 @@ from tests.basicswap.extended.test_dcr import ( run_test_itx_refund, ) - logger = logging.getLogger("BSX Tests") if not len(logger.handlers): diff --git a/tests/basicswap/extended/test_pivx.py b/tests/basicswap/extended/test_pivx.py index 9102dc0..49381db 100644 --- a/tests/basicswap/extended/test_pivx.py +++ b/tests/basicswap/extended/test_pivx.py @@ -66,7 +66,6 @@ from tests.basicswap.common import ( from basicswap.bin.run import startDaemon from basicswap.bin.prepare import downloadPIVXParams - logger = logging.getLogger() logger.level = logging.DEBUG if not len(logger.handlers): diff --git a/tests/basicswap/extended/test_scripts.py b/tests/basicswap/extended/test_scripts.py index f9bc46c..d1b49ca 100644 --- a/tests/basicswap/extended/test_scripts.py +++ b/tests/basicswap/extended/test_scripts.py @@ -38,7 +38,6 @@ from tests.basicswap.util import ( waitForServer, ) - logger = logging.getLogger() logger.level = logging.DEBUG if not len(logger.handlers): diff --git a/tests/basicswap/selenium/test_recover_chain_b_lock_tx.py b/tests/basicswap/selenium/test_recover_chain_b_lock_tx.py index 2162fe1..be49a9d 100644 --- a/tests/basicswap/selenium/test_recover_chain_b_lock_tx.py +++ b/tests/basicswap/selenium/test_recover_chain_b_lock_tx.py @@ -20,7 +20,6 @@ from util import ( ) from tests.basicswap.util import read_json_api - base_url = "http://localhost" diff --git a/tests/basicswap/selenium/test_swap_direction.py b/tests/basicswap/selenium/test_swap_direction.py index 78051ec..82f38b3 100644 --- a/tests/basicswap/selenium/test_swap_direction.py +++ b/tests/basicswap/selenium/test_swap_direction.py @@ -16,7 +16,6 @@ from tests.basicswap.util import ( from util import get_driver from selenium.webdriver.common.by import By - logger = logging.getLogger() logger.level = logging.INFO if not len(logger.handlers): diff --git a/tests/basicswap/selenium/util.py b/tests/basicswap/selenium/util.py index 74708ec..5bf0f07 100644 --- a/tests/basicswap/selenium/util.py +++ b/tests/basicswap/selenium/util.py @@ -9,7 +9,6 @@ import os from selenium.webdriver.common.by import By - BSX_0_PORT = int(os.getenv("BSX_0_PORT", 12701)) BSX_1_PORT = int(os.getenv("BSX_1_PORT", BSX_0_PORT + 1)) BSX_2_PORT = int(os.getenv("BSX_1_PORT", BSX_0_PORT + 2)) diff --git a/tests/basicswap/test_other.py b/tests/basicswap/test_other.py index d8d7035..20c85c2 100644 --- a/tests/basicswap/test_other.py +++ b/tests/basicswap/test_other.py @@ -61,7 +61,6 @@ from basicswap.contrib.test_framework.messages import ( uint256_from_str, ) - logger = logging.getLogger() diff --git a/tests/basicswap/test_run.py b/tests/basicswap/test_run.py index e56bb58..a6266f4 100644 --- a/tests/basicswap/test_run.py +++ b/tests/basicswap/test_run.py @@ -63,7 +63,6 @@ from basicswap.contrib.test_framework.script import ( ) from tests.basicswap.test_xmr import BaseTest, test_delay_event, callnoderpc - logger = logging.getLogger() diff --git a/tests/basicswap/test_xmr.py b/tests/basicswap/test_xmr.py index 92d5525..01e439d 100644 --- a/tests/basicswap/test_xmr.py +++ b/tests/basicswap/test_xmr.py @@ -91,7 +91,6 @@ from basicswap.db_util import ( ) from basicswap.bin.run import startDaemon, startXmrDaemon, startXmrWalletDaemon - logger = logging.getLogger() NUM_NODES = 3 diff --git a/tests/basicswap/util.py b/tests/basicswap/util.py index 3b55a2e..04948d1 100644 --- a/tests/basicswap/util.py +++ b/tests/basicswap/util.py @@ -10,7 +10,6 @@ import json import urllib from urllib.request import urlopen - REQUIRED_SETTINGS = { "blocks_confirmed": 1, "conf_target": 1, From 6b4b97376b66055a8f6ba33a90f0f7f31400586c Mon Sep 17 00:00:00 2001 From: tecnovert Date: Fri, 29 May 2026 09:38:37 +0200 Subject: [PATCH 3/5] test: print xmr daemon logs on ci failure --- .github/workflows/ci.yml | 10 ++++ tests/basicswap/common_xmr.py | 4 +- .../basicswap/extended/test_xmr_persistent.py | 52 +++++++++++-------- 3 files changed, 41 insertions(+), 25 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c62a248..6a60d72 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -94,12 +94,22 @@ jobs: export XMR_BINDIR="$BIN_DIR/monero" pytest tests/basicswap/test_btc_xmr.py::TestBTC -k "test_003_api or test_02_a_leader_recover_a_lock_tx" - name: Run test_encrypted_xmr_reload + id: test_encrypted_xmr_reload run: | export PYTHONPATH=$(pwd) export TEST_PATH=${TEST_RELOAD_PATH} mkdir -p ${TEST_PATH}/bin cp -r $BIN_DIR/* ${TEST_PATH}/bin/ pytest tests/basicswap/extended/test_encrypted_xmr_reload.py + - name: Print log files on failure + if: ${{ failure() && steps.test_encrypted_xmr_reload.conclusion == 'failure' }} + run: | + for i in 0 1 2; do + for logname in core_stderr core_stdout wallet_stderr wallet_stdout; do + echo "=== client${i} ${logname}.log ===" + cat /tmp/test_basicswap/client${i}/monero/${logname}.log || true + done + done - name: Run selenium tests id: selenium_tests run: | diff --git a/tests/basicswap/common_xmr.py b/tests/basicswap/common_xmr.py index b4de182..52ab89d 100644 --- a/tests/basicswap/common_xmr.py +++ b/tests/basicswap/common_xmr.py @@ -585,7 +585,7 @@ def prepare_nodes( class TestBase(unittest.TestCase): def setUpClass(cls): - super(TestBase, cls).setUpClass() + super().setUpClass() cls.delay_event = threading.Event() signal.signal( @@ -645,7 +645,7 @@ class XmrTestBase(TestBase): prepare_nodes(3, "monero") def start_processes(self): - multiprocessing.set_start_method("fork") + multiprocessing.set_start_method("spawn") self.delay_event.clear() for i in range(3): diff --git a/tests/basicswap/extended/test_xmr_persistent.py b/tests/basicswap/extended/test_xmr_persistent.py index b893a6a..896562e 100644 --- a/tests/basicswap/extended/test_xmr_persistent.py +++ b/tests/basicswap/extended/test_xmr_persistent.py @@ -248,7 +248,7 @@ def updateThreadDCR(cls): if "double spend" in str(e): pass else: - logging.warning("updateThreadDCR purchaseticket {}".format(e)) + logging.warning(f"updateThreadDCR purchaseticket {e}") cls.delay_event.wait(0.5) try: if num_passed >= 5: @@ -260,7 +260,7 @@ def updateThreadDCR(cls): ], ) except Exception as e: - logging.warning("updateThreadDCR generate {}".format(e)) + logging.warning(f"updateThreadDCR generate {e}") except Exception as e: print("updateThreadDCR error", str(e)) cls.delay_event.wait(random.uniform(cls.dcr_update_min, cls.dcr_update_max)) @@ -272,7 +272,7 @@ def signal_handler(self, sig, frame): def run_process(client_id): - client_path = os.path.join(test_path, "client{}".format(client_id)) + client_path = os.path.join(test_path, f"client{client_id}") testargs = [ "basicswap-run", "-datadir=" + client_path, @@ -299,15 +299,24 @@ def start_processes(self): for i in range(NUM_NODES): waitForServer(self.delay_event, UI_PORT + i) - wallets = read_json_api(UI_PORT + 1, "wallets") - if "monero" in self.test_coins_list: + try: + for i in range(8): + wallets = read_json_api(UI_PORT + 1, "wallets") + if "XMR" in wallets and "main_address" in wallets["XMR"]: + break + logging.info("Waiting for wallets output") + self.delay_event.wait(1.0) + self.xmr_addr = wallets["XMR"]["main_address"] + except Exception as e: + logging.error("{} - wallets json: {}".format(str(e), json.dumps(wallets))) + raise + xmr_auth = None if os.getenv("XMR_RPC_USER", "") != "": xmr_auth = (os.getenv("XMR_RPC_USER", ""), os.getenv("XMR_RPC_PWD", "")) - self.xmr_addr = wallets["XMR"]["main_address"] - num_blocks = 100 + num_blocks: int = 100 if ( callrpc_xmr(XMR_BASE_RPC_PORT + 1, "get_block_count", auth=xmr_auth)[ "count" @@ -322,10 +331,11 @@ def start_processes(self): auth=xmr_auth, ) logging.info( - "XMR blocks: %d", - callrpc_xmr(XMR_BASE_RPC_PORT + 1, "get_block_count", auth=xmr_auth)[ - "count" - ], + "XMR blocks: {}".format( + callrpc_xmr(XMR_BASE_RPC_PORT + 1, "get_block_count", auth=xmr_auth)[ + "count" + ] + ) ) self.btc_addr = callbtcrpc(0, "getnewaddress", ["mining_addr", "bech32"]) @@ -402,9 +412,7 @@ def start_processes(self): have_blocks: int = callfirorpc(0, "getblockcount") if have_blocks < num_blocks: logging.info( - "Mining %d Firo blocks to %s", - num_blocks - have_blocks, - self.firo_addr, + f"Mining {num_blocks - have_blocks} Firo blocks to {self.firo_addr}" ) callfirorpc( 0, @@ -420,9 +428,7 @@ def start_processes(self): have_blocks: int = callbchrpc(0, "getblockcount") if have_blocks < num_blocks: logging.info( - "Mining %d Bitcoincash blocks to %s", - num_blocks - have_blocks, - self.bch_addr, + f"Mining {num_blocks - have_blocks} Bitcoincash blocks to {self.bch_addr}" ) callbchrpc( 0, @@ -437,9 +443,7 @@ def start_processes(self): have_blocks: int = calldogerpc(0, "getblockcount") if have_blocks < num_blocks: logging.info( - "Mining %d Dogecoin blocks to %s", - num_blocks - have_blocks, - self.doge_addr, + f"Mining {num_blocks - have_blocks} Dogecoin blocks to {self.doge_addr}" ) calldogerpc( 0, "generatetoaddress", [num_blocks - have_blocks, self.doge_addr] @@ -557,7 +561,10 @@ class BaseTestWithPrepare(unittest.TestCase): @classmethod def setUpClass(cls): - super(BaseTestWithPrepare, cls).setUpClass() + cls.addClassCleanup( + cls.finalise + ) # tearDownClass is not run if setUpClass fails + super().setUpClass() random.seed(time.time()) @@ -577,7 +584,7 @@ class BaseTestWithPrepare(unittest.TestCase): waitForServer(cls.delay_event, UI_PORT + 1) @classmethod - def tearDownClass(cls): + def finalise(cls): logging.info("Stopping test") cls.delay_event.set() if cls.update_thread: @@ -598,7 +605,6 @@ class BaseTestWithPrepare(unittest.TestCase): class Test(BaseTestWithPrepare): def test_persistent(self): - while not self.delay_event.is_set(): logging.info("Looping indefinitely, ctrl+c to exit.") self.delay_event.wait(10) From 248b8046b1991b4d1f456fab26c7c3ed8fe92217 Mon Sep 17 00:00:00 2001 From: tecnovert Date: Fri, 29 May 2026 12:05:58 +0200 Subject: [PATCH 4/5] test: wait longer, add startup_delay option --- basicswap/base.py | 9 +++++++-- basicswap/basicswap.py | 31 +++++++++++++++++++------------ tests/basicswap/common_xmr.py | 15 ++++++--------- tests/basicswap/util.py | 4 ++-- 4 files changed, 34 insertions(+), 25 deletions(-) diff --git a/basicswap/base.py b/basicswap/base.py index 6181e12..3473e53 100644 --- a/basicswap/base.py +++ b/basicswap/base.py @@ -365,8 +365,10 @@ class BaseApp(DBMethods): self.log.warning(f"Setting mocktime to {new_offset}") self.mock_time_offset = new_offset - def get_int_setting(self, name: str, default_v: int, min_v: int, max_v) -> int: - value: int = self.settings.get(name, default_v) + def get_clamped_int_from( + self, settings: dict, name: str, default_v: int, min_v: int, max_v + ) -> int: + value: int = settings.get(name, default_v) if value < min_v: self.log.warning(f"Setting {name} to {min_v}") value = min_v @@ -375,6 +377,9 @@ class BaseApp(DBMethods): value = max_v return value + def get_int_setting(self, name: str, default_v: int, min_v: int, max_v) -> int: + return self.get_clamped_int_from(self.settings, name, default_v, min_v, max_v) + def get_delay_event_seconds(self): if self.min_delay_event == self.max_delay_event: return self.min_delay_event diff --git a/basicswap/basicswap.py b/basicswap/basicswap.py index 2634bc9..337d3ba 100644 --- a/basicswap/basicswap.py +++ b/basicswap/basicswap.py @@ -440,9 +440,6 @@ class BasicSwap(BaseApp, BSXNetwork, UIApp): self.check_delayed_auto_accept_seconds = self.get_int_setting( "check_delayed_auto_accept_seconds", 60, 1, 20 * 60 ) - self.startup_tries = self.get_int_setting( - "startup_tries", 15, 1, 100 - ) # Seconds waited for will be (x(1 + x+1) / 2 self.debug_ui = self.settings.get("debug_ui", False) self._debug_cases = [] self._last_checked_actions = 0 @@ -1617,13 +1614,22 @@ class BasicSwap(BaseApp, BSXNetwork, UIApp): # systemd will try to restart the process if fail_code != 0 self.stopRunning(1) - startup_tries = self.startup_tries chain_client_settings = self.getChainClientSettings(coin_type) - if "startup_tries" in chain_client_settings: - startup_tries = chain_client_settings["startup_tries"] - if startup_tries < 1: - self.log.warning('"startup_tries" can\'t be less than 1.') - startup_tries = 1 + # Total seconds waited for will be ((startup_tries(1 + startup_tries) / 2) * startup_delay + startup_tries: int = self.get_clamped_int_from( + chain_client_settings, + "startup_tries", + self.get_int_setting("startup_tries", 15, 1, 100), + 1, + 100, + ) + startup_delay: int = self.get_clamped_int_from( + chain_client_settings, + "startup_delay", + self.get_int_setting("startup_delay", 5, 1, 100), + 1, + 100, + ) for i in range(startup_tries): if self.delay_event.is_set(): return @@ -1631,6 +1637,7 @@ class BasicSwap(BaseApp, BSXNetwork, UIApp): self.coin_clients[coin_type]["interface"].testDaemonRPC(with_wallet) return except Exception as ex: + wait_for: int = startup_delay * (1 + i) if any( log in str(ex) for log in [ @@ -1643,13 +1650,13 @@ class BasicSwap(BaseApp, BSXNetwork, UIApp): ] ): self.log.info( - f"Waiting for {Coins(coin_type).name} RPC. Trying again in {5 * (1 + i)} seconds, {1 + i}/{startup_tries}." + f"Waiting for {Coins(coin_type).name} RPC. Trying again in {wait_for} seconds, {1 + i}/{startup_tries}." ) else: self.log.warning( - f"Can't connect to {Coins(coin_type).name} RPC: {ex}. Trying again in {5 * (1 + i)} seconds, {1 + i}/{startup_tries}." + f"Can't connect to {Coins(coin_type).name} RPC: {ex}. Trying again in {wait_for} seconds, {1 + i}/{startup_tries}." ) - self.delay_event.wait(5 * (1 + i)) + self.delay_event.wait(wait_for) self.log.error(f"Can't connect to {Coins(coin_type).name} RPC, exiting.") self.stopRunning(1) # systemd will try to restart the process if fail_code != 0 diff --git a/tests/basicswap/common_xmr.py b/tests/basicswap/common_xmr.py index 52ab89d..f7e2c80 100644 --- a/tests/basicswap/common_xmr.py +++ b/tests/basicswap/common_xmr.py @@ -531,9 +531,7 @@ def run_prepare( for opt in EXTRA_CONFIG_JSON.get("doge{}".format(node_id), []): fp.write(opt + "\n") - with open(config_path) as fs: - settings = json.load(fs) - + settings["startup_delay"] = 1 settings["min_delay_event"] = 1 settings["max_delay_event"] = 4 settings["min_delay_event_short"] = 1 @@ -623,7 +621,7 @@ class TestBase(unittest.TestCase): def run_process(client_id): - client_path = os.path.join(TEST_PATH, "client{}".format(client_id)) + client_path = os.path.join(TEST_PATH, f"client{client_id}") testargs = [ "basicswap-run", "-datadir=" + client_path, @@ -654,7 +652,7 @@ class XmrTestBase(TestBase): ) self.processes[-1].start() - waitForServer(self.delay_event, 12701) + waitForServer(self.delay_event, 12701, 60) def waitForMainAddress(): for i in range(20): @@ -666,13 +664,12 @@ class XmrTestBase(TestBase): ) return wallets["XMR"]["main_address"] except Exception as e: - print("Waiting for main address {}".format(str(e))) + print(f"Waiting for main address {e}") self.delay_event.wait(1) raise ValueError("waitForMainAddress timedout") xmr_addr1 = waitForMainAddress() - - num_blocks = 100 + num_blocks: int = 100 xmr_auth = None if os.getenv("XMR_RPC_USER", "") != "": @@ -684,7 +681,7 @@ class XmrTestBase(TestBase): ] < num_blocks ): - logging.info("Mining {} Monero blocks to {}.".format(num_blocks, xmr_addr1)) + logging.info(f"Mining {num_blocks} Monero blocks to {xmr_addr1}.") callrpc_xmr( XMR_BASE_RPC_PORT + 1, "generateblocks", diff --git a/tests/basicswap/util.py b/tests/basicswap/util.py index 04948d1..a8e0bb1 100644 --- a/tests/basicswap/util.py +++ b/tests/basicswap/util.py @@ -2,7 +2,7 @@ # -*- coding: utf-8 -*- # Copyright (c) 2022-2024 tecnovert -# Copyright (c) 2024 The Basicswap developers +# Copyright (c) 2024-2026 The Basicswap developers # Distributed under the MIT software license, see the accompanying # file LICENSE.txt or http://www.opensource.org/licenses/mit-license.php. @@ -63,7 +63,7 @@ def waitForServer(delay_event, port, wait_for=20): if delay_event.is_set(): raise ValueError("Test stopped.") try: - delay_event.wait(1) + delay_event.wait(1.0) _ = read_json_api(port) return except Exception as e: From 27f9f8c13a1e18d1a6385111f3135b76fc7f726e Mon Sep 17 00:00:00 2001 From: tecnovert Date: Fri, 29 May 2026 14:22:05 +0200 Subject: [PATCH 5/5] doc: update release notes --- doc/release-notes.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/doc/release-notes.md b/doc/release-notes.md index 9e9278b..cba6eaf 100644 --- a/doc/release-notes.md +++ b/doc/release-notes.md @@ -1,3 +1,12 @@ +0.16.3 +============== + +- New setting "startup_delay" + - Adjusts the time waited for coin daemons to start between "startup_tries". + - Valid as a base setting and can be overridden per coin with chainclients settings. + + + 0.14.5 ==============