diff --git a/src/env_vars.py b/src/env_vars.py index 2277b6fa7..4985a6f17 100644 --- a/src/env_vars.py +++ b/src/env_vars.py @@ -32,11 +32,6 @@ RLN_CREDENTIALS = get_env_var("RLN_CREDENTIALS") PG_USER = get_env_var("POSTGRES_USER", "postgres") PG_PASS = get_env_var("POSTGRES_PASSWORD", "test123") -# --------------------------------------------------------------------------- -# waku.test fleet node configuration - local+fleet -# --------------------------------------------------------------------------- -# Activate fleet bootstrap by passing --fleet to pytest or setting -# FLEET_BOOTSTRAP=true. See tests/conftest.py for details. FLEET_NODES = [ # Amsterdam "/dns4/node-01.do-ams3.waku.test.status.im/tcp/30303/p2p/16Uiu2HAkykgaECHswi3YKJ5dMLbq2kPVCo89fcyTd38UcQD6ej5W", @@ -48,9 +43,6 @@ FLEET_NODES = [ FLEET_PRIMARY_MULTIADDR = FLEET_NODES[0] FLEET_DNS_DISCOVERY_URL = "enrtree://AOGYWMBYOUIMOENHXCHILPKY3ZRFEULMFI4DOM442QSZ73TT2A7VI@test.waku.nodes.status.im" -# Per-node bootstrap multiaddrs that mirror the on-disk config-n*.toml files: -# config-n1.toml → node-01.do-ams3.waku.test.status.im (Amsterdam) -# config-n2.toml → node-01.gc-us-central1-a.waku.test.status.im (US Central) FLEET_N1_MULTIADDR = FLEET_NODES[0] # node-01.do-ams3 – used by NODE1 in --fleet mode FLEET_N2_MULTIADDR = FLEET_NODES[1] # node-01.gc-us-central1-a – used by NODE2 in --fleet mode diff --git a/src/node/fleet_waku_node.py b/src/node/fleet_waku_node.py index 650c159b3..6a604340e 100644 --- a/src/node/fleet_waku_node.py +++ b/src/node/fleet_waku_node.py @@ -2,13 +2,7 @@ When fleet bootstrap is active (``--fleet`` CLI flag or ``FLEET_BOOTSTRAP=true`` env var), an instance of :class:`FleetBootstrapConfig` is assigned to -``WakuNode._pre_start_hook``. ``WakuNode.start()`` calls this hook before -processing any start arguments, injecting fleet-specific bootstrap parameters -into every local Docker node. - -This module encapsulates all fleet injection logic that was previously an -ad-hoc closure inside ``tests/conftest.py``, making it independently testable -and reusable. +``WakuNode._pre_start_hook``. """ from __future__ import annotations @@ -57,39 +51,13 @@ class FleetBootstrapConfig: - NODE1 (1st started) → FLEET_N1_MULTIADDR (node-01.do-ams3) - NODE2 (2nd started) → FLEET_N2_MULTIADDR (node-01.gc-us-central1-a) - additional nodes → FLEET_PRIMARY_MULTIADDR (Amsterdam, same as NODE1) - - Direct bootstrap coupling between NODE1 and NODE2 is suppressed: any - ``discv5_bootstrap_node`` kwarg pointing to a local node ENR is removed; - fleet DNS discovery (``dns_discovery_url``) replaces it. - - Attributes: - fleet_rln_state: Dict with keys ``keystore_prefixes`` and - ``rln_membership_indexes`` populated by the ``fleet_rln_state`` - session fixture. """ fleet_rln_state: dict def prepare_start_kwargs(self, node: "WakuNode", kwargs: dict) -> dict: - """Inject fleet bootstrap arguments into *kwargs* before node start. + """Inject fleet bootstrap arguments into *kwargs* before node start.""" - Transparent to callers: - - - Existing ``staticnode`` entries are preserved; the fleet multiaddr is - *appended* as an additional entry. - - ``dns_discovery`` / ``dns_discovery_url`` use ``setdefault`` semantics. - - RLN credentials are injected only when not already present and relay - is enabled. - - ``discv5_bootstrap_node`` pointing to a local ENR is removed so each - node bootstraps independently from its assigned fleet peer. - - The ``skip_fleet_peering`` kwarg (not a real nwaku flag) acts as an - escape-hatch: when ``True``, only ``discv5_bootstrap_node`` removal - happens; all other fleet injection is skipped. - - Returns: - The (possibly modified) *kwargs* dict. - """ logger.debug("FleetBootstrapConfig.prepare_start_kwargs: injecting waku.test bootstrap args") if kwargs.pop("skip_fleet_peering", False): @@ -101,9 +69,6 @@ class FleetBootstrapConfig: # Determine which fleet peer to connect to based on node creation order # within the current test (DS.waku_nodes is reset to [] before each test). - # The append to DS.waku_nodes happens inside _start_docker/_start_wrapper, - # *after* start() returns, so len() here reflects the count of nodes - # already fully started. node_index = len(DS.waku_nodes) if node_index == 0: fleet_multiaddr = FLEET_N1_MULTIADDR @@ -128,16 +93,11 @@ class FleetBootstrapConfig: _append_fleet_kwarg(kwargs, "staticnode", fleet_multiaddr) kwargs.setdefault("dns_discovery", "true") kwargs.setdefault("dns_discovery_url", FLEET_DNS_DISCOVERY_URL) - # Align local node cluster and shards with the fleet node configs - # (config-n1.toml / config-n2.toml both use cluster-id=1, shards 0-7). kwargs.setdefault("cluster_id", FLEET_CLUSTER_ID) kwargs.setdefault("shard", list(range(8))) - # Inject session-level RLN credentials into nodes that don't already - # carry explicit RLN args. Uses the same node_index as the fleet - # multiaddr assignment so NODE1 gets creds-id=1 and NODE2 gets creds-id=2. - # Only inject into nodes with relay enabled – filter/lightpush/store service - # nodes run without relay and nwaku rejects rln-relay when WakuRelay is not mounted. + # Inject session-level RLN credentials into relay enabled nodes that + # don't already carry explicit RLN args. rln_prefixes = self.fleet_rln_state.get("keystore_prefixes", []) if rln_prefixes and kwargs.get("rln_creds_source") is None: if str(kwargs.get("relay", "")).lower() == "true": diff --git a/src/node/waku_node.py b/src/node/waku_node.py index bb085e8ce..1fa71dd2e 100644 --- a/src/node/waku_node.py +++ b/src/node/waku_node.py @@ -96,10 +96,7 @@ def resolve_sharding_flags(kwargs): class WakuNode: - # Optional pre-start hook: when set to a callable, it is invoked at the - # beginning of every start() call with (self, kwargs_dict) and must return - # the (possibly modified) kwargs dict. Set by tests/conftest.py when - # fleet bootstrap is active; None by default so all normal tests are unaffected. + # Optional pre-start hook to allow modifications for fleet tests _pre_start_hook = None def __init__(self, docker_image, docker_log_prefix=""): diff --git a/src/steps/light_push.py b/src/steps/light_push.py index 94d2410b0..9761c2db3 100644 --- a/src/steps/light_push.py +++ b/src/steps/light_push.py @@ -124,9 +124,6 @@ class StepsLightPush(StepsCommon): for index, peer in enumerate(peer_list): logger.debug(f"Checking that peer NODE_{index + 1}:{peer.image} can find the lightpushed message") get_messages_response = peer.get_relay_messages(pubsub_topic) - # In fleet mode the relay cache may contain background messages from other - # fleet participants. Filter to only messages whose contentTopic matches - # the test message so that fleet noise does not break the count assertion. test_messages = [m for m in get_messages_response if m.get("contentTopic") == payload["message"]["contentTopic"]] assert test_messages, f"Peer NODE_{index + 1}:{peer.image} couldn't find any messages" assert len(test_messages) == 1, ( diff --git a/src/test_config.py b/src/test_config.py index 121c59e1e..11f098d48 100644 --- a/src/test_config.py +++ b/src/test_config.py @@ -1,10 +1,7 @@ """Test session configuration objects. These dataclasses carry configuration that varies between fleet and -non-fleet test runs. Fixtures in ``tests/conftest.py`` build and -provide the appropriate instance; step classes and tests consume them -via fixture injection rather than through hardcoded class attributes or -``monkeypatch``. +non-fleet test runs. """ from __future__ import annotations @@ -19,16 +16,6 @@ class PubsubConfig: A *default* instance uses ``VALID_PUBSUB_TOPICS`` / ``PUBSUB_TOPICS_RLN`` (cluster-id 198). A *fleet* instance uses ``FLEET_PUBSUB_TOPICS`` (cluster-id 1, shards 0-7). - - Attributes: - relay_test_topic: Primary topic used by ``StepsRelay`` tests. - filter_test_topic: Primary topic used by ``StepsFilter`` tests. - filter_second_topic: Secondary topic used by multi-topic filter tests. - lightpush_test_topic: Topic used by ``StepsLightPush`` tests. - store_test_topic: Topic used by ``StepsStore`` tests. - rln_test_topic: Topic used by ``StepsRLN`` tests. - all_topics: Full ordered topic list (used where a module-level - ``VALID_PUBSUB_TOPICS`` reference is iterated). """ relay_test_topic: str diff --git a/tests/conftest.py b/tests/conftest.py index 847c8e43e..48cd71446 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,37 +1,4 @@ # -*- coding: utf-8 -*- -""" -Root pytest configuration for the logos-delivery interop test suite. - -Fleet bootstrap – hybrid local+fleet --------------------------------------------------- -Every local Docker node spawned by a test is configured at start() time so -that it connects to a live waku.test fleet peer as a static peer, and -discovers all remaining fleet peers through the published ENR DNS tree. - -Bootstrap assignment by node creation order (mirrors config-n*.toml files): - NODE1 (1st started) → config-n1.toml → node-01.do-ams3.waku.test.status.im - NODE2 (2nd started) → config-n2.toml → node-01.gc-us-central1-a.waku.test.status.im - additional nodes → FLEET_PRIMARY_MULTIADDR (Amsterdam, same as NODE1) - -Direct bootstrap coupling between NODE1 and NODE2 is suppressed: - * ``discv5_bootstrap_node`` kwargs that point to a local node's ENR are - stripped; fleet DNS discovery (dns_discovery_url) replaces them so that - each node bootstraps independently from its assigned fleet peer rather - than from another local container. - -Tests still retain full access to local nodes (REST API calls, add_peers, -store/filter/lightpush service calls) – only the initial discv5 bootstrap -link between local nodes is removed. - -Fleet node information (addresses, peer IDs, ENR tree URL) is stored in -``src/env_vars.py`` (FLEET_NODES, FLEET_N1_MULTIADDR, FLEET_N2_MULTIADDR, -FLEET_PRIMARY_MULTIADDR, FLEET_DNS_DISCOVERY_URL) - -Activation (opt-in, disabled by default): - pytest --fleet -v - FLEET_BOOTSTRAP=true pytest -v - -""" import inspect import glob import random @@ -68,12 +35,8 @@ def pytest_addoption(parser): def _fleet_bootstrap_enabled(config) -> bool: - """Return True when fleet bootstrap should be activated. + """Return True when fleet bootstrap should be activated.""" - Activation priority (first match wins): - 1. ``--fleet`` CLI flag passed to pytest - 2. ``FLEET_BOOTSTRAP=true`` environment variable - """ if config.getoption("--fleet", default=False): return True return os.getenv("FLEET_BOOTSTRAP", "false").lower() == "true" @@ -81,18 +44,7 @@ def _fleet_bootstrap_enabled(config) -> bool: @pytest.fixture(scope="session") def fleet_rln_state(request): - """Register 2 RLN memberships once per test session when ``--fleet`` is active. - - The on-disk keystore directories created here are reused by every test in - the session so that the expensive blockchain registration only happens once. - - Yields a dict with keys: - ``keystore_prefixes`` – list[str] of random 4-char directory prefixes - ``rln_membership_indexes`` – list[int | None] returned by register_rln() - - An empty dict (both lists empty) is yielded when fleet bootstrap is not - active or when ``RLN_CREDENTIALS`` is not set. - """ + """Register 2 RLN memberships once per test session when ``--fleet`` is active.""" if not _fleet_bootstrap_enabled(request.config): yield {"keystore_prefixes": [], "rln_membership_indexes": []} return @@ -132,11 +84,8 @@ def fleet_rln_state(request): @pytest.fixture(scope="session") def pubsub_cfg(request) -> PubsubConfig: - """Return the pubsub-topic configuration for the current session. + """Return the pubsub-topic configuration for the current session.""" - Fleet mode (``--fleet`` / ``FLEET_BOOTSTRAP=true``) → cluster-id 1, shards 0-7. - Default mode → cluster-id 198 (``VALID_PUBSUB_TOPICS`` / ``PUBSUB_TOPICS_RLN``). - """ if _fleet_bootstrap_enabled(request.config): return PubsubConfig( relay_test_topic=FLEET_PUBSUB_TOPICS[1], @@ -160,23 +109,8 @@ def pubsub_cfg(request) -> PubsubConfig: @pytest.fixture(scope="session", autouse=True) def configure_fleet_bootstrap(request, fleet_rln_state): - """Register ``FleetBootstrapConfig`` as ``WakuNode._pre_start_hook`` for the session. + """Register ``FleetBootstrapConfig`` as ``WakuNode._pre_start_hook`` for the session.""" - Active only when ``--fleet`` is passed or ``FLEET_BOOTSTRAP=true`` is set. - The hook is cleared at session teardown so it does not leak across test - collection runs. - - Replaces the former per-test ``monkeypatch``-based ``patch_waku_node_start`` - fixture. Benefits of this approach: - - - **Session-scoped** – the hook is registered once, not reinstalled before - every test function. - - **Encapsulated** – all fleet injection logic lives in - :class:`src.node.fleet_waku_node.FleetBootstrapConfig`, making it - independently testable. - - **No closure over ``original_start``** – ``WakuNode.start`` is not - replaced; the hook is called from within it via a class variable. - """ if not _fleet_bootstrap_enabled(request.config): logger.info("Fleet bootstrap inactive – pass --fleet (or set FLEET_BOOTSTRAP=true) " "to connect local nodes to the waku.test fleet") yield @@ -202,11 +136,6 @@ def configure_fleet_bootstrap(request, fleet_rln_state): def skip_fleet_test_without_rln(request, fleet_rln_state): """Skip tests marked @pytest.mark.waku_test_fleet when no RLN keystore is available for the current session. - - When fleet bootstrap is active but RLN credentials were not set (or - on-chain registration failed), local nodes cannot join the fleet relay mesh - (which enforces RLN), so every fleet-marked test would ERROR instead of - giving useful signal. An explicit skip with a clear reason is cleaner. """ if not _fleet_bootstrap_enabled(request.config): return @@ -218,23 +147,8 @@ def skip_fleet_test_without_rln(request, fleet_rln_state): @pytest.fixture(scope="session", autouse=True) def configure_fleet_cluster(request, pubsub_cfg): - """Apply fleet cluster configuration to step classes when ``--fleet`` is active. + """Apply fleet cluster configuration to step classes when ``--fleet`` is active.""" - Sets step-class pubsub-topic attributes and overrides - ``StepsLightPush.setup_lightpush_node`` **once** at session start from the - ``pubsub_cfg`` configuration object. - - Replaces the former per-test ``monkeypatch``-based ``patch_fleet_cluster_config`` - fixture. Benefits: - - - **Session-scoped** – class attributes are set once, not re-patched on - every test function. - - **Config-object driven** – topic values come from :class:`PubsubConfig` - rather than scattered inline constants; changing the mapping requires - editing one place. - - **No ``monkeypatch``** – direct class-attribute assignment; restoring - original values is unnecessary because the entire session uses fleet topics. - """ if not _fleet_bootstrap_enabled(request.config): yield return @@ -258,43 +172,17 @@ def configure_fleet_cluster(request, pubsub_cfg): # over the module-level VALID_PUBSUB_TOPICS import directly; rebind it. _relay_publish_mod.VALID_PUBSUB_TOPICS = pubsub_cfg.all_topics - # ── Light-push client topology fix ────────────────────────────────────────── - # In fleet mode the 3rd node started by light-push tests (light_push_node1, - # node_index=2) has relay=true but NO RLN membership (only 2 memberships are - # registered in fleet_rln_state). Connecting to a fleet peer that enforces - # rln-relay with no credentials causes nwaku to crash. - # - # Fix: replace setup_lightpush_node with a fleet-aware version that - # 1. routes lightpush requests to receiving_node1 (self.multiaddr_list[0]), - # which has RLN membership #1 and is fleet-peered. nwaku injects an RLN - # proof when the lightpush server relays the message, so gossipsub carries - # the message through the fleet mesh to receiving_node2. - # NOTE: routing directly to FLEET_N1_MULTIADDR does NOT work because - # nwaku's lightpush service does not inject RLN proofs – the fleet relay - # layer then rejects the proof-less message and it never propagates. - # 2. starts the client with relay=false so no RLN membership is needed. - # 3. does NOT add the client to main_receiving_nodes; assertion peers - # remain receiving_node1 and receiving_node2 only. def _fleet_setup_lightpush_node(self, image, node_index, **kwargs): from src.node.waku_node import WakuNode node = WakuNode(image, f"lightpush_node{node_index}_{self.test_id}") fleet_kwargs = dict(kwargs) - # Force relay=false and lightpush=false – pure lightpush *client*, no - # RLN membership required and no server-side lightpush protocol mounted. - # nwaku v0.38+ refuses to mount lightpush (server) when relay is not - # mounted, so both flags must be false together. - # skip_fleet_peering prevents the bootstrap hook from injecting a fleet - # staticnode + RLN creds (which would fail for the same reason). fleet_kwargs["relay"] = "false" fleet_kwargs["lightpush"] = "false" fleet_kwargs["skip_fleet_peering"] = True fleet_kwargs.setdefault("cluster_id", FLEET_CLUSTER_ID) fleet_kwargs.setdefault("shard", list(range(8))) - # Use receiving_node1 (self.multiaddr_list[0]) as the lightpush service - # node. receiving_node1 holds RLN membership #1 and is fleet-peered, so - # it generates a valid RLN proof when relaying – the message then flows - # through the fleet gossipsub mesh and reaches receiving_node2. + lightpush_service_addr = self.multiaddr_list[0] node.start(lightpushnode=lightpush_service_addr, **fleet_kwargs) self.add_node_peer(node, self.multiaddr_list)