mirror of
https://github.com/logos-messaging/logos-messaging-interop-tests.git
synced 2026-05-18 16:29:59 +00:00
chore: Refactor RLN tests (#164)
* test: uncomment RLN tests * test: single node registration * test: demo could not generate rln-v2 proof * fix: update env file example * fix: update images * fix: temp pr for testing * fix: chain id optional and lock v0.38.0 * feat: fix automatic chain ID * fix: uncomment on chain tests 3208 resolved * fix: improve assertions * fix: RLN ready guard * fix: workaround to wait for RLN * fix: lightpush test assertion * fix: reuse creds for the second test * chore: delay for removing flaky behaviuor * WIP on chore-refactor-rln-tests fix: revert changes to docker manager * fix: undo chore: delay for removing flaky behaviuor * fix: check for RLN state only when required * chore: test workflow for RLN * fix: open permissions * fix: silent chmod by default * fix: remove unnecessary code * fix: reduce CI script to RLN only * fix: add missing fi * fix: sync wf with master * fix: test wf file * fix: undefined rln creds set * fix: run together with other tests * fix: remove test workflows - reset env file * fix: sync wrappers manager * fix: clean up redundant debug lines --------- Co-authored-by: Darshan <35736874+darshankabariya@users.noreply.github.com> Co-authored-by: darshankabariya <darshan@status.im>
This commit is contained in:
parent
5ca3ec6fe9
commit
44dbf628e4
@ -33,4 +33,4 @@ PG_USER = get_env_var("POSTGRES_USER", "postgres")
|
|||||||
PG_PASS = get_env_var("POSTGRES_PASSWORD", "test123")
|
PG_PASS = get_env_var("POSTGRES_PASSWORD", "test123")
|
||||||
|
|
||||||
# example for .env file
|
# example for .env file
|
||||||
# RLN_CREDENTIALS = {"rln-relay-cred-password": "password", "rln-relay-eth-client-address": "wss://sepolia.infura.io/ws/v3/api_key", "rln-relay-eth-contract-address": "0xF471d71E9b1455bBF4b85d475afb9BB0954A29c4", "rln-relay-eth-private-key-1": "1111111111111111111111111111111111111111111111111111111111111111", "rln-relay-eth-private-key-2": "1111111111111111111111111111111111111111111111111111111111111111"}
|
# RLN_CREDENTIALS = {"rln-relay-cred-password": "password", "rln-relay-eth-client-address": "https://rpc.sepolia.linea.build", "rln-relay-eth-contract-address": "0xB9cd878C90E49F797B4431fBF4fb333108CB90e6", "rln-relay-eth-private-key-1": "", "rln-relay-eth-private-key-2": "", "rln-relay-eth-private-key-3": "", "rln-relay-eth-private-key-4": "", "rln-relay-eth-private-key-5": ""}
|
||||||
|
|||||||
@ -5,11 +5,13 @@ import random
|
|||||||
import re
|
import re
|
||||||
import shutil
|
import shutil
|
||||||
import string
|
import string
|
||||||
|
import subprocess
|
||||||
import pytest
|
import pytest
|
||||||
import requests
|
import requests
|
||||||
from src.libs.common import delay
|
from src.libs.common import delay
|
||||||
from src.libs.custom_logger import get_custom_logger
|
from src.libs.custom_logger import get_custom_logger
|
||||||
from tenacity import retry, stop_after_delay, wait_fixed
|
from tenacity import retry, stop_after_delay, wait_fixed, sleep
|
||||||
|
from docker.errors import NotFound as DockerNotFound
|
||||||
from src.node.api_clients.rest import REST
|
from src.node.api_clients.rest import REST
|
||||||
from src.node.docker_mananger import DockerManager
|
from src.node.docker_mananger import DockerManager
|
||||||
from src.env_vars import DOCKER_LOG_DIR
|
from src.env_vars import DOCKER_LOG_DIR
|
||||||
@ -38,8 +40,24 @@ def sanitize_docker_flags(input_flags):
|
|||||||
|
|
||||||
|
|
||||||
@retry(stop=stop_after_delay(180), wait=wait_fixed(0.5), reraise=True)
|
@retry(stop=stop_after_delay(180), wait=wait_fixed(0.5), reraise=True)
|
||||||
def rln_credential_store_ready(creds_file_path, single_check=False):
|
def rln_credential_store_ready(creds_file_path, single_check=False, require_credentials=False):
|
||||||
if os.path.exists(creds_file_path):
|
if os.path.exists(creds_file_path):
|
||||||
|
subprocess.run(["sudo", "-n", "chmod", "a+r", creds_file_path], check=False)
|
||||||
|
if require_credentials:
|
||||||
|
try:
|
||||||
|
with open(creds_file_path, "r", encoding="utf-8") as creds_file:
|
||||||
|
keystore_data = json.load(creds_file)
|
||||||
|
except (OSError, json.JSONDecodeError) as ex:
|
||||||
|
if single_check:
|
||||||
|
return False
|
||||||
|
raise ValueError(f"Failed to parse RLN keystore at {creds_file_path}: {ex}")
|
||||||
|
|
||||||
|
credentials = keystore_data.get("credentials", {}) if isinstance(keystore_data, dict) else {}
|
||||||
|
if not credentials:
|
||||||
|
if single_check:
|
||||||
|
return False
|
||||||
|
raise ValueError(f"RLN keystore exists but has no credentials yet: {creds_file_path}")
|
||||||
|
|
||||||
return True
|
return True
|
||||||
elif not single_check:
|
elif not single_check:
|
||||||
raise FileNotFoundError(errno.ENOENT, os.strerror(errno.ENOENT), creds_file_path)
|
raise FileNotFoundError(errno.ENOENT, os.strerror(errno.ENOENT), creds_file_path)
|
||||||
@ -83,8 +101,10 @@ class WakuNode:
|
|||||||
self._log_path = os.path.join(DOCKER_LOG_DIR, f"{docker_log_prefix}__{self._image_name.replace('/', '_')}.log")
|
self._log_path = os.path.join(DOCKER_LOG_DIR, f"{docker_log_prefix}__{self._image_name.replace('/', '_')}.log")
|
||||||
self._docker_manager = DockerManager(self._image_name)
|
self._docker_manager = DockerManager(self._image_name)
|
||||||
self._container = None
|
self._container = None
|
||||||
|
self.rln_membership_index = None
|
||||||
self.start_args = {}
|
self.start_args = {}
|
||||||
self._wrapper_node = None
|
self._wrapper_node = None
|
||||||
|
self._rln_creds_set = False
|
||||||
logger.debug(f"WakuNode instance initialized with log path {self._log_path}")
|
logger.debug(f"WakuNode instance initialized with log path {self._log_path}")
|
||||||
|
|
||||||
@property
|
@property
|
||||||
@ -178,13 +198,14 @@ class WakuNode:
|
|||||||
del default_args["pubsub-topic"]
|
del default_args["pubsub-topic"]
|
||||||
|
|
||||||
rln_args, rln_creds_set, keystore_path = self.parse_rln_credentials(default_args, False)
|
rln_args, rln_creds_set, keystore_path = self.parse_rln_credentials(default_args, False)
|
||||||
|
self._rln_creds_set = rln_creds_set
|
||||||
|
|
||||||
default_args.pop("rln-creds-id", None)
|
default_args.pop("rln-creds-id", None)
|
||||||
default_args.pop("rln-creds-source", None)
|
default_args.pop("rln-creds-source", None)
|
||||||
default_args.pop("rln-keystore-prefix", None)
|
default_args.pop("rln-keystore-prefix", None)
|
||||||
|
|
||||||
if rln_creds_set:
|
if rln_creds_set:
|
||||||
rln_credential_store_ready(keystore_path)
|
rln_credential_store_ready(keystore_path, require_credentials=True)
|
||||||
default_args.update(rln_args)
|
default_args.update(rln_args)
|
||||||
else:
|
else:
|
||||||
logger.info(f"RLN credentials not set or credential store not available, starting without RLN")
|
logger.info(f"RLN credentials not set or credential store not available, starting without RLN")
|
||||||
@ -208,7 +229,7 @@ class WakuNode:
|
|||||||
DS.waku_nodes.append(self)
|
DS.waku_nodes.append(self)
|
||||||
delay(1)
|
delay(1)
|
||||||
try:
|
try:
|
||||||
self.ensure_ready(timeout_duration=wait_for_node_sec)
|
self.ensure_ready(timeout_duration=wait_for_node_sec, rln_required=self._rln_creds_set)
|
||||||
except Exception as ex:
|
except Exception as ex:
|
||||||
logger.error(f"REST service did not become ready in time: {ex}")
|
logger.error(f"REST service did not become ready in time: {ex}")
|
||||||
raise
|
raise
|
||||||
@ -284,13 +305,32 @@ class WakuNode:
|
|||||||
|
|
||||||
logger.debug(f"Waiting for keystore {keystore_path}")
|
logger.debug(f"Waiting for keystore {keystore_path}")
|
||||||
try:
|
try:
|
||||||
rln_credential_store_ready(keystore_path)
|
rln_credential_store_ready(keystore_path, require_credentials=True)
|
||||||
|
self.rln_membership_index = str(self.get_rln_membership_index_from_log())
|
||||||
|
logger.debug(f"Detected RLN membership index from registration logs: {self.rln_membership_index}")
|
||||||
|
self.stop()
|
||||||
except Exception as ex:
|
except Exception as ex:
|
||||||
logger.error(f"File {keystore_path} with RLN credentials did not become available in time {ex}")
|
logger.error(f"File {keystore_path} with RLN credentials did not become available in time {ex}")
|
||||||
raise
|
raise
|
||||||
else:
|
else:
|
||||||
logger.warn("RLN credentials not set, no action performed")
|
logger.warn("RLN credentials not set, no action performed")
|
||||||
|
|
||||||
|
return self.rln_membership_index
|
||||||
|
|
||||||
|
@retry(stop=stop_after_delay(10), wait=wait_fixed(0.2), reraise=True)
|
||||||
|
def get_rln_membership_index_from_log(self):
|
||||||
|
if not os.path.exists(self._log_path):
|
||||||
|
raise FileNotFoundError(errno.ENOENT, os.strerror(errno.ENOENT), self._log_path)
|
||||||
|
|
||||||
|
with open(self._log_path, "r", encoding="utf-8", errors="ignore") as log_file:
|
||||||
|
log_data = log_file.read()
|
||||||
|
|
||||||
|
matches = re.findall(r"membershipIndex=(\d+)", log_data)
|
||||||
|
if not matches:
|
||||||
|
raise ValueError("Could not infer RLN membership index from registration logs")
|
||||||
|
|
||||||
|
return int(matches[-1])
|
||||||
|
|
||||||
@retry(stop=stop_after_delay(5), wait=wait_fixed(0.1), reraise=True)
|
@retry(stop=stop_after_delay(5), wait=wait_fixed(0.1), reraise=True)
|
||||||
def stop(self):
|
def stop(self):
|
||||||
if self._is_wrapper:
|
if self._is_wrapper:
|
||||||
@ -301,7 +341,12 @@ class WakuNode:
|
|||||||
def _stop_docker(self):
|
def _stop_docker(self):
|
||||||
if self._container:
|
if self._container:
|
||||||
logger.debug(f"Stopping container with id {self._container.short_id}")
|
logger.debug(f"Stopping container with id {self._container.short_id}")
|
||||||
self._container.stop()
|
try:
|
||||||
|
self._container.stop()
|
||||||
|
except DockerNotFound:
|
||||||
|
logger.debug(f"Container {self._container.short_id} already exited and removed, treating as stopped.")
|
||||||
|
self._container = None
|
||||||
|
return
|
||||||
try:
|
try:
|
||||||
self._container.remove()
|
self._container.remove()
|
||||||
except:
|
except:
|
||||||
@ -344,7 +389,7 @@ class WakuNode:
|
|||||||
logger.debug(f"Unpause container with id {self._container.short_id}")
|
logger.debug(f"Unpause container with id {self._container.short_id}")
|
||||||
self._container.unpause()
|
self._container.unpause()
|
||||||
|
|
||||||
def ensure_ready(self, timeout_duration=10):
|
def ensure_ready(self, timeout_duration=10, rln_required=False):
|
||||||
@retry(stop=stop_after_delay(timeout_duration), wait=wait_fixed(0.1), reraise=True)
|
@retry(stop=stop_after_delay(timeout_duration), wait=wait_fixed(0.1), reraise=True)
|
||||||
def check_healthy(node=self):
|
def check_healthy(node=self):
|
||||||
self.health_response = node.health()
|
self.health_response = node.health()
|
||||||
@ -357,9 +402,12 @@ class WakuNode:
|
|||||||
if self.health_response.get("nodeHealth") != "READY":
|
if self.health_response.get("nodeHealth") != "READY":
|
||||||
raise AssertionError("Waiting for the node health status: READY")
|
raise AssertionError("Waiting for the node health status: READY")
|
||||||
|
|
||||||
# for p in self.health_response.get("protocolsHealth"):
|
for p in self.health_response.get("protocolsHealth"):
|
||||||
# if p.get("Rln Relay") != "READY":
|
if rln_required and "Rln Relay" in p:
|
||||||
# raise AssertionError("Waiting for the Rln relay status: READY")
|
if p["Rln Relay"] != "READY":
|
||||||
|
raise AssertionError("Waiting for the Rln relay status: READY")
|
||||||
|
# TODO: Remove once Rln Relay reflects true RLN status
|
||||||
|
sleep(20)
|
||||||
|
|
||||||
logger.info("Node protocols are initialized !!")
|
logger.info("Node protocols are initialized !!")
|
||||||
|
|
||||||
@ -532,6 +580,21 @@ class WakuNode:
|
|||||||
def is_nwaku(self):
|
def is_nwaku(self):
|
||||||
return "nwaku" in self.image
|
return "nwaku" in self.image
|
||||||
|
|
||||||
|
def prepare_rln_storage_paths(self, cwd, keystore_prefix, selected_id, reset_existing=False):
|
||||||
|
keystore_dir = os.path.join(cwd, f"keystore_{keystore_prefix}_{selected_id}")
|
||||||
|
rln_tree_dir = os.path.join(cwd, f"rln_tree_{keystore_prefix}_{selected_id}")
|
||||||
|
|
||||||
|
if reset_existing:
|
||||||
|
for path, path_name in [(keystore_dir, "keystore"), (rln_tree_dir, "rln tree")]:
|
||||||
|
if os.path.exists(path):
|
||||||
|
logger.warning(f"Resetting existing RLN {path_name} directory before registration: {path}")
|
||||||
|
shutil.rmtree(path, ignore_errors=True)
|
||||||
|
|
||||||
|
os.makedirs(keystore_dir, exist_ok=True)
|
||||||
|
os.makedirs(rln_tree_dir, exist_ok=True)
|
||||||
|
|
||||||
|
return keystore_dir, rln_tree_dir
|
||||||
|
|
||||||
def parse_rln_credentials(self, default_args, is_registration):
|
def parse_rln_credentials(self, default_args, is_registration):
|
||||||
rln_args = {}
|
rln_args = {}
|
||||||
keystore_path = None
|
keystore_path = None
|
||||||
@ -544,6 +607,13 @@ class WakuNode:
|
|||||||
return rln_args, False, keystore_path
|
return rln_args, False, keystore_path
|
||||||
|
|
||||||
imported_creds = json.loads(rln_creds_source)
|
imported_creds = json.loads(rln_creds_source)
|
||||||
|
rln_chain_id = imported_creds.get("rln-relay-chain-id")
|
||||||
|
if rln_chain_id is None:
|
||||||
|
eth_client_address = imported_creds.get("rln-relay-eth-client-address", "")
|
||||||
|
if "linea" in eth_client_address:
|
||||||
|
rln_chain_id = "59141"
|
||||||
|
elif "sepolia" in eth_client_address:
|
||||||
|
rln_chain_id = "11155111"
|
||||||
|
|
||||||
if len(imported_creds) < 4 or any(value is None for value in imported_creds.values()):
|
if len(imported_creds) < 4 or any(value is None for value in imported_creds.values()):
|
||||||
logger.warn(f"One or more of required RLN credentials were not set properly")
|
logger.warn(f"One or more of required RLN credentials were not set properly")
|
||||||
@ -552,6 +622,13 @@ class WakuNode:
|
|||||||
eth_private_key = select_private_key(imported_creds, selected_id)
|
eth_private_key = select_private_key(imported_creds, selected_id)
|
||||||
|
|
||||||
cwd = os.getcwd()
|
cwd = os.getcwd()
|
||||||
|
keystore_prefix = default_args.get("rln-keystore-prefix")
|
||||||
|
|
||||||
|
if not keystore_prefix:
|
||||||
|
logger.warn("rln-keystore-prefix is missing, cannot mount RLN state and keystore")
|
||||||
|
return rln_args, False, keystore_path
|
||||||
|
|
||||||
|
keystore_dir, rln_tree_dir = self.prepare_rln_storage_paths(cwd, keystore_prefix, selected_id, reset_existing=is_registration)
|
||||||
|
|
||||||
if self.is_nwaku():
|
if self.is_nwaku():
|
||||||
if is_registration:
|
if is_registration:
|
||||||
@ -574,6 +651,8 @@ class WakuNode:
|
|||||||
{
|
{
|
||||||
"rln-relay-cred-path": "/keystore/keystore.json",
|
"rln-relay-cred-path": "/keystore/keystore.json",
|
||||||
"rln-relay-cred-password": imported_creds["rln-relay-cred-password"],
|
"rln-relay-cred-password": imported_creds["rln-relay-cred-password"],
|
||||||
|
"rln-relay-eth-client-address": imported_creds["rln-relay-eth-client-address"],
|
||||||
|
"rln-relay-eth-contract-address": imported_creds["rln-relay-eth-contract-address"],
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
@ -587,12 +666,15 @@ class WakuNode:
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
keystore_path = cwd + "/keystore_" + default_args["rln-keystore-prefix"] + "_" + selected_id + "/keystore.json"
|
if rln_chain_id is not None:
|
||||||
|
rln_args["rln-relay-chain-id"] = str(rln_chain_id)
|
||||||
|
|
||||||
|
keystore_path = os.path.join(keystore_dir, "keystore.json")
|
||||||
|
|
||||||
self._volumes.extend(
|
self._volumes.extend(
|
||||||
[
|
[
|
||||||
cwd + "/rln_tree_" + default_args["rln-keystore-prefix"] + "_" + selected_id + ":/etc/rln_tree",
|
f"{rln_tree_dir}:/etc/rln_tree",
|
||||||
cwd + "/keystore_" + default_args["rln-keystore-prefix"] + "_" + selected_id + ":/keystore",
|
f"{keystore_dir}:/keystore",
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@ -26,6 +26,7 @@ class StepsRLN(StepsCommon):
|
|||||||
multiaddr_list = []
|
multiaddr_list = []
|
||||||
lightpush_nodes = []
|
lightpush_nodes = []
|
||||||
keystore_prefixes = []
|
keystore_prefixes = []
|
||||||
|
rln_membership_indexes = []
|
||||||
|
|
||||||
@allure.step
|
@allure.step
|
||||||
def generate_keystore_prefixes(self, count=2):
|
def generate_keystore_prefixes(self, count=2):
|
||||||
@ -38,15 +39,19 @@ class StepsRLN(StepsCommon):
|
|||||||
@allure.step
|
@allure.step
|
||||||
def register_rln_relay_nodes(self, count, orig_prefixes):
|
def register_rln_relay_nodes(self, count, orig_prefixes):
|
||||||
if count > 0:
|
if count > 0:
|
||||||
logger.debug(111111111111111)
|
|
||||||
self.keystore_prefixes = self.generate_keystore_prefixes(count)
|
self.keystore_prefixes = self.generate_keystore_prefixes(count)
|
||||||
|
self.rln_membership_indexes = []
|
||||||
for i, prefix in enumerate(self.keystore_prefixes):
|
for i, prefix in enumerate(self.keystore_prefixes):
|
||||||
logger.debug(000000000000000000000)
|
membership_index = self.register_rln_single_node(prefix=prefix, rln_creds_source=RLN_CREDENTIALS, rln_creds_id=f"{i+1}")
|
||||||
self.register_rln_single_node(prefix=prefix, rln_creds_source=RLN_CREDENTIALS, rln_creds_id=f"{i+1}")
|
self.rln_membership_indexes.append(membership_index)
|
||||||
else:
|
else:
|
||||||
self.keystore_prefixes = orig_prefixes
|
self.keystore_prefixes = orig_prefixes.get("keystore_prefixes", [])
|
||||||
|
self.rln_membership_indexes = orig_prefixes.get("rln_membership_indexes", [])
|
||||||
|
|
||||||
return self.keystore_prefixes
|
return {
|
||||||
|
"keystore_prefixes": self.keystore_prefixes,
|
||||||
|
"rln_membership_indexes": self.rln_membership_indexes,
|
||||||
|
}
|
||||||
|
|
||||||
@allure.step
|
@allure.step
|
||||||
def setup_main_rln_relay_nodes(self, **kwargs):
|
def setup_main_rln_relay_nodes(self, **kwargs):
|
||||||
@ -60,7 +65,7 @@ class StepsRLN(StepsCommon):
|
|||||||
relay="true",
|
relay="true",
|
||||||
rln_creds_source=RLN_CREDENTIALS,
|
rln_creds_source=RLN_CREDENTIALS,
|
||||||
rln_creds_id="1",
|
rln_creds_id="1",
|
||||||
rln_relay_membership_index="1",
|
rln_relay_membership_index=self.resolve_rln_membership_index(0, **kwargs),
|
||||||
rln_keystore_prefix=self.keystore_prefixes[0],
|
rln_keystore_prefix=self.keystore_prefixes[0],
|
||||||
**kwargs,
|
**kwargs,
|
||||||
)
|
)
|
||||||
@ -78,7 +83,7 @@ class StepsRLN(StepsCommon):
|
|||||||
discv5_bootstrap_node=self.enr_uri,
|
discv5_bootstrap_node=self.enr_uri,
|
||||||
rln_creds_source=RLN_CREDENTIALS,
|
rln_creds_source=RLN_CREDENTIALS,
|
||||||
rln_creds_id="2",
|
rln_creds_id="2",
|
||||||
rln_relay_membership_index="1",
|
rln_relay_membership_index=self.resolve_rln_membership_index(1, **kwargs),
|
||||||
rln_keystore_prefix=self.keystore_prefixes[1],
|
rln_keystore_prefix=self.keystore_prefixes[1],
|
||||||
**kwargs,
|
**kwargs,
|
||||||
)
|
)
|
||||||
@ -101,7 +106,7 @@ class StepsRLN(StepsCommon):
|
|||||||
discv5_bootstrap_node=self.enr_uri,
|
discv5_bootstrap_node=self.enr_uri,
|
||||||
rln_creds_source=RLN_CREDENTIALS,
|
rln_creds_source=RLN_CREDENTIALS,
|
||||||
rln_creds_id=f"{index + 3}",
|
rln_creds_id=f"{index + 3}",
|
||||||
rln_relay_membership_index="1",
|
rln_relay_membership_index=self.resolve_rln_membership_index(index + 2, **kwargs),
|
||||||
rln_keystore_prefix=self.keystore_prefixes[index + 2],
|
rln_keystore_prefix=self.keystore_prefixes[index + 2],
|
||||||
**kwargs,
|
**kwargs,
|
||||||
)
|
)
|
||||||
@ -118,7 +123,7 @@ class StepsRLN(StepsCommon):
|
|||||||
lightpushnode=self.multiaddr_list[0],
|
lightpushnode=self.multiaddr_list[0],
|
||||||
rln_creds_source=RLN_CREDENTIALS,
|
rln_creds_source=RLN_CREDENTIALS,
|
||||||
rln_creds_id="2",
|
rln_creds_id="2",
|
||||||
rln_relay_membership_index="1",
|
rln_relay_membership_index=self.resolve_rln_membership_index(1, **kwargs),
|
||||||
rln_keystore_prefix=self.keystore_prefixes[1],
|
rln_keystore_prefix=self.keystore_prefixes[1],
|
||||||
**kwargs,
|
**kwargs,
|
||||||
)
|
)
|
||||||
@ -131,7 +136,23 @@ class StepsRLN(StepsCommon):
|
|||||||
def register_rln_single_node(self, prefix="", **kwargs):
|
def register_rln_single_node(self, prefix="", **kwargs):
|
||||||
logger.debug("Registering RLN credentials for single node")
|
logger.debug("Registering RLN credentials for single node")
|
||||||
self.node = WakuNode(DEFAULT_NWAKU, f"node_{gen_step_id()}")
|
self.node = WakuNode(DEFAULT_NWAKU, f"node_{gen_step_id()}")
|
||||||
self.node.register_rln(rln_keystore_prefix=prefix, rln_creds_source=kwargs["rln_creds_source"], rln_creds_id=kwargs["rln_creds_id"])
|
return self.node.register_rln(rln_keystore_prefix=prefix, rln_creds_source=kwargs["rln_creds_source"], rln_creds_id=kwargs["rln_creds_id"])
|
||||||
|
|
||||||
|
@allure.step
|
||||||
|
def resolve_rln_membership_index(self, index, **kwargs):
|
||||||
|
explicit_index = kwargs.get("rln_relay_membership_index")
|
||||||
|
if explicit_index is not None:
|
||||||
|
return str(explicit_index)
|
||||||
|
|
||||||
|
if len(self.rln_membership_indexes) > index and self.rln_membership_indexes[index] is not None:
|
||||||
|
inferred_index = str(self.rln_membership_indexes[index])
|
||||||
|
logger.debug(f"Using inferred RLN membership index for position {index}: {inferred_index}")
|
||||||
|
return inferred_index
|
||||||
|
|
||||||
|
raise ValueError(
|
||||||
|
f"RLN membership index for position {index} is not available. "
|
||||||
|
"Register credentials and persist rln_membership_indexes together with keystore_prefixes before node startup."
|
||||||
|
)
|
||||||
|
|
||||||
@allure.step
|
@allure.step
|
||||||
def check_rln_registration(self, prefix, key_id):
|
def check_rln_registration(self, prefix, key_id):
|
||||||
|
|||||||
@ -168,7 +168,7 @@ SAMPLE_TIMESTAMPS = [
|
|||||||
{"description": "Missing", "value": None, "valid_for": []},
|
{"description": "Missing", "value": None, "valid_for": []},
|
||||||
]
|
]
|
||||||
|
|
||||||
PUBSUB_TOPICS_RLN = ["/waku/2/rs/1/0"]
|
PUBSUB_TOPICS_RLN = [f"/waku/2/rs/{DEFAULT_CLUSTER_ID}/0"]
|
||||||
|
|
||||||
LOG_ERROR_KEYWORDS = [
|
LOG_ERROR_KEYWORDS = [
|
||||||
"crash",
|
"crash",
|
||||||
|
|||||||
@ -13,7 +13,6 @@ from src.test_data import SAMPLE_INPUTS
|
|||||||
logger = get_custom_logger(__name__)
|
logger = get_custom_logger(__name__)
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.skip(reason="RLN functional changes. To be updated by Roman Zajic")
|
|
||||||
@pytest.mark.xdist_group(name="RLN serial tests")
|
@pytest.mark.xdist_group(name="RLN serial tests")
|
||||||
class TestRelayRLN(StepsRLN, StepsRelay):
|
class TestRelayRLN(StepsRLN, StepsRelay):
|
||||||
SAMPLE_INPUTS_RLN = SAMPLE_INPUTS + SAMPLE_INPUTS + SAMPLE_INPUTS
|
SAMPLE_INPUTS_RLN = SAMPLE_INPUTS + SAMPLE_INPUTS + SAMPLE_INPUTS
|
||||||
@ -22,7 +21,14 @@ class TestRelayRLN(StepsRLN, StepsRelay):
|
|||||||
def test_valid_payloads_lightpush_at_spam_rate(self, pytestconfig):
|
def test_valid_payloads_lightpush_at_spam_rate(self, pytestconfig):
|
||||||
message_limit = 1
|
message_limit = 1
|
||||||
epoch_sec = 1
|
epoch_sec = 1
|
||||||
pytestconfig.cache.set("keystore-prefixes", self.register_rln_relay_nodes(2, []))
|
rln_state = self.register_rln_relay_nodes(2, [])
|
||||||
|
pytestconfig.cache.set(
|
||||||
|
"keystore-prefixes",
|
||||||
|
{
|
||||||
|
"keystore_prefixes": rln_state["keystore_prefixes"],
|
||||||
|
"rln_membership_indexes": rln_state["rln_membership_indexes"],
|
||||||
|
},
|
||||||
|
)
|
||||||
self.setup_first_rln_relay_node(lightpush="true", rln_relay_user_message_limit=message_limit, rln_relay_epoch_sec=epoch_sec)
|
self.setup_first_rln_relay_node(lightpush="true", rln_relay_user_message_limit=message_limit, rln_relay_epoch_sec=epoch_sec)
|
||||||
self.setup_second_rln_lightpush_node(rln_relay_user_message_limit=message_limit, rln_relay_epoch_sec=epoch_sec)
|
self.setup_second_rln_lightpush_node(rln_relay_user_message_limit=message_limit, rln_relay_epoch_sec=epoch_sec)
|
||||||
self.subscribe_main_relay_nodes()
|
self.subscribe_main_relay_nodes()
|
||||||
@ -37,11 +43,17 @@ class TestRelayRLN(StepsRLN, StepsRelay):
|
|||||||
if i > message_limit and (now - start) <= epoch_sec:
|
if i > message_limit and (now - start) <= epoch_sec:
|
||||||
raise AssertionError("Publish with RLN enabled at spam rate worked!!!")
|
raise AssertionError("Publish with RLN enabled at spam rate worked!!!")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
assert "RLN validation failed" or "NonceLimitReached" in str(e)
|
error_str = str(e)
|
||||||
|
assert "RLN validation failed" in error_str or "NonceLimitReached" in error_str
|
||||||
|
if "NonceLimitReached" in error_str:
|
||||||
|
assert "503" in error_str, f"Expected HTTP 503 for NonceLimitReached, got: {error_str}"
|
||||||
|
|
||||||
def test_valid_payloads_at_slow_rate(self, pytestconfig):
|
def test_valid_payloads_at_slow_rate(self, pytestconfig):
|
||||||
message_limit = 20
|
message_limit = 20
|
||||||
self.register_rln_relay_nodes(0, pytestconfig.cache.get("keystore-prefixes", []))
|
self.register_rln_relay_nodes(
|
||||||
|
0,
|
||||||
|
pytestconfig.cache.get("keystore-prefixes", {"keystore_prefixes": [], "rln_membership_indexes": []}),
|
||||||
|
)
|
||||||
self.setup_main_rln_relay_nodes(rln_relay_user_message_limit=message_limit, rln_relay_epoch_sec=600)
|
self.setup_main_rln_relay_nodes(rln_relay_user_message_limit=message_limit, rln_relay_epoch_sec=600)
|
||||||
self.subscribe_main_relay_nodes()
|
self.subscribe_main_relay_nodes()
|
||||||
failed_payloads = []
|
failed_payloads = []
|
||||||
@ -63,7 +75,10 @@ class TestRelayRLN(StepsRLN, StepsRelay):
|
|||||||
def test_valid_payloads_at_spam_rate(self, pytestconfig):
|
def test_valid_payloads_at_spam_rate(self, pytestconfig):
|
||||||
message_limit = 20
|
message_limit = 20
|
||||||
epoch_sec = 600
|
epoch_sec = 600
|
||||||
self.register_rln_relay_nodes(0, pytestconfig.cache.get("keystore-prefixes", []))
|
self.register_rln_relay_nodes(
|
||||||
|
0,
|
||||||
|
pytestconfig.cache.get("keystore-prefixes", {"keystore_prefixes": [], "rln_membership_indexes": []}),
|
||||||
|
)
|
||||||
self.setup_main_rln_relay_nodes(rln_relay_user_message_limit=message_limit, rln_relay_epoch_sec=epoch_sec)
|
self.setup_main_rln_relay_nodes(rln_relay_user_message_limit=message_limit, rln_relay_epoch_sec=epoch_sec)
|
||||||
self.subscribe_main_relay_nodes()
|
self.subscribe_main_relay_nodes()
|
||||||
start = math.trunc(time())
|
start = math.trunc(time())
|
||||||
@ -77,10 +92,16 @@ class TestRelayRLN(StepsRLN, StepsRelay):
|
|||||||
if i > message_limit and (now - start) <= epoch_sec:
|
if i > message_limit and (now - start) <= epoch_sec:
|
||||||
raise AssertionError("Publish with RLN enabled at spam rate worked!!!")
|
raise AssertionError("Publish with RLN enabled at spam rate worked!!!")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
assert "RLN validation failed" or "NonceLimitReached" in str(e)
|
error_str = str(e)
|
||||||
|
assert "RLN validation failed" in error_str or "NonceLimitReached" in error_str
|
||||||
|
if "NonceLimitReached" in error_str:
|
||||||
|
assert "500" in error_str, f"Expected HTTP 500 for NonceLimitReached, got: {error_str}"
|
||||||
|
|
||||||
def test_valid_payload_at_variable_rate(self, pytestconfig):
|
def test_valid_payload_at_variable_rate(self, pytestconfig):
|
||||||
self.register_rln_relay_nodes(0, pytestconfig.cache.get("keystore-prefixes", []))
|
self.register_rln_relay_nodes(
|
||||||
|
0,
|
||||||
|
pytestconfig.cache.get("keystore-prefixes", {"keystore_prefixes": [], "rln_membership_indexes": []}),
|
||||||
|
)
|
||||||
self.setup_main_rln_relay_nodes(rln_relay_user_message_limit=1, rln_relay_epoch_sec=1)
|
self.setup_main_rln_relay_nodes(rln_relay_user_message_limit=1, rln_relay_epoch_sec=1)
|
||||||
self.subscribe_main_relay_nodes()
|
self.subscribe_main_relay_nodes()
|
||||||
payload_desc = SAMPLE_INPUTS[0]["description"]
|
payload_desc = SAMPLE_INPUTS[0]["description"]
|
||||||
@ -101,11 +122,17 @@ class TestRelayRLN(StepsRLN, StepsRelay):
|
|||||||
else:
|
else:
|
||||||
previous = now
|
previous = now
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
assert "RLN validation failed" or "NonceLimitReached" in str(e)
|
error_str = str(e)
|
||||||
|
assert "RLN validation failed" in error_str or "NonceLimitReached" in error_str
|
||||||
|
if "NonceLimitReached" in error_str:
|
||||||
|
assert "500" in error_str, f"Expected HTTP 500 for NonceLimitReached, got: {error_str}"
|
||||||
|
|
||||||
def test_valid_payloads_random_epoch_at_slow_rate(self, pytestconfig):
|
def test_valid_payloads_random_epoch_at_slow_rate(self, pytestconfig):
|
||||||
epoch_sec = random.randint(2, 5)
|
epoch_sec = random.randint(2, 5)
|
||||||
self.register_rln_relay_nodes(0, pytestconfig.cache.get("keystore-prefixes", []))
|
self.register_rln_relay_nodes(
|
||||||
|
0,
|
||||||
|
pytestconfig.cache.get("keystore-prefixes", {"keystore_prefixes": [], "rln_membership_indexes": []}),
|
||||||
|
)
|
||||||
self.setup_main_rln_relay_nodes(rln_relay_user_message_limit=1, rln_relay_epoch_sec=epoch_sec)
|
self.setup_main_rln_relay_nodes(rln_relay_user_message_limit=1, rln_relay_epoch_sec=epoch_sec)
|
||||||
self.subscribe_main_relay_nodes()
|
self.subscribe_main_relay_nodes()
|
||||||
failed_payloads = []
|
failed_payloads = []
|
||||||
@ -122,7 +149,10 @@ class TestRelayRLN(StepsRLN, StepsRelay):
|
|||||||
|
|
||||||
def test_valid_payloads_random_user_message_limit(self, pytestconfig):
|
def test_valid_payloads_random_user_message_limit(self, pytestconfig):
|
||||||
user_message_limit = random.randint(2, 4)
|
user_message_limit = random.randint(2, 4)
|
||||||
self.register_rln_relay_nodes(0, pytestconfig.cache.get("keystore-prefixes", []))
|
self.register_rln_relay_nodes(
|
||||||
|
0,
|
||||||
|
pytestconfig.cache.get("keystore-prefixes", {"keystore_prefixes": [], "rln_membership_indexes": []}),
|
||||||
|
)
|
||||||
self.setup_main_rln_relay_nodes(rln_relay_user_message_limit=user_message_limit, rln_relay_epoch_sec=1)
|
self.setup_main_rln_relay_nodes(rln_relay_user_message_limit=user_message_limit, rln_relay_epoch_sec=1)
|
||||||
self.subscribe_main_relay_nodes()
|
self.subscribe_main_relay_nodes()
|
||||||
failed_payloads = []
|
failed_payloads = []
|
||||||
@ -136,12 +166,18 @@ class TestRelayRLN(StepsRLN, StepsRelay):
|
|||||||
failed_payloads.append(payload["description"])
|
failed_payloads.append(payload["description"])
|
||||||
assert not failed_payloads, f"Payloads failed: {failed_payloads}"
|
assert not failed_payloads, f"Payloads failed: {failed_payloads}"
|
||||||
|
|
||||||
@pytest.mark.skip(reason="Waiting for issue resolution https://github.com/waku-org/nwaku/issues/3208")
|
|
||||||
@pytest.mark.timeout(600)
|
@pytest.mark.timeout(600)
|
||||||
def test_valid_payloads_dynamic_at_spam_rate(self, pytestconfig):
|
def test_valid_payloads_dynamic_at_spam_rate(self, pytestconfig):
|
||||||
message_limit = 100
|
message_limit = 100
|
||||||
epoch_sec = 600
|
epoch_sec = 600
|
||||||
pytestconfig.cache.set("keystore-prefixes", self.register_rln_relay_nodes(2, []))
|
rln_state = self.register_rln_relay_nodes(2, [])
|
||||||
|
pytestconfig.cache.set(
|
||||||
|
"keystore-prefixes",
|
||||||
|
{
|
||||||
|
"keystore_prefixes": rln_state["keystore_prefixes"],
|
||||||
|
"rln_membership_indexes": rln_state["rln_membership_indexes"],
|
||||||
|
},
|
||||||
|
)
|
||||||
self.setup_main_rln_relay_nodes(
|
self.setup_main_rln_relay_nodes(
|
||||||
rln_relay_user_message_limit=message_limit,
|
rln_relay_user_message_limit=message_limit,
|
||||||
rln_relay_epoch_sec=epoch_sec,
|
rln_relay_epoch_sec=epoch_sec,
|
||||||
@ -160,13 +196,22 @@ class TestRelayRLN(StepsRLN, StepsRelay):
|
|||||||
if i > message_limit and (now - start) <= epoch_sec:
|
if i > message_limit and (now - start) <= epoch_sec:
|
||||||
raise AssertionError("Publish with RLN enabled at spam rate worked!!!")
|
raise AssertionError("Publish with RLN enabled at spam rate worked!!!")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
assert "RLN validation failed" or "NonceLimitReached" in str(e)
|
error_str = str(e)
|
||||||
|
assert "RLN validation failed" in error_str or "NonceLimitReached" in error_str
|
||||||
|
if "NonceLimitReached" in error_str:
|
||||||
|
assert "500" in error_str, f"Expected HTTP 500 for NonceLimitReached, got: {error_str}"
|
||||||
|
|
||||||
@pytest.mark.skip(reason="Waiting for issue resolution https://github.com/waku-org/nwaku/issues/3208")
|
|
||||||
@pytest.mark.timeout(600)
|
@pytest.mark.timeout(600)
|
||||||
def test_valid_payloads_dynamic_at_slow_rate(self, pytestconfig):
|
def test_valid_payloads_dynamic_at_slow_rate(self, pytestconfig):
|
||||||
message_limit = 100
|
message_limit = 100
|
||||||
pytestconfig.cache.set("keystore-prefixes", self.register_rln_relay_nodes(2, []))
|
rln_state = self.register_rln_relay_nodes(2, [])
|
||||||
|
pytestconfig.cache.set(
|
||||||
|
"keystore-prefixes",
|
||||||
|
{
|
||||||
|
"keystore_prefixes": rln_state["keystore_prefixes"],
|
||||||
|
"rln_membership_indexes": rln_state["rln_membership_indexes"],
|
||||||
|
},
|
||||||
|
)
|
||||||
self.setup_main_rln_relay_nodes(
|
self.setup_main_rln_relay_nodes(
|
||||||
rln_relay_user_message_limit=message_limit,
|
rln_relay_user_message_limit=message_limit,
|
||||||
rln_relay_epoch_sec=600,
|
rln_relay_epoch_sec=600,
|
||||||
@ -192,7 +237,10 @@ class TestRelayRLN(StepsRLN, StepsRelay):
|
|||||||
def test_valid_payloads_n1_with_rln_n2_without_rln_at_spam_rate(self, pytestconfig):
|
def test_valid_payloads_n1_with_rln_n2_without_rln_at_spam_rate(self, pytestconfig):
|
||||||
message_limit = 1
|
message_limit = 1
|
||||||
epoch_sec = 1
|
epoch_sec = 1
|
||||||
self.register_rln_relay_nodes(0, pytestconfig.cache.get("keystore-prefixes", []))
|
self.register_rln_relay_nodes(
|
||||||
|
0,
|
||||||
|
pytestconfig.cache.get("keystore-prefixes", {"keystore_prefixes": [], "rln_membership_indexes": []}),
|
||||||
|
)
|
||||||
self.setup_first_rln_relay_node(rln_relay_user_message_limit=message_limit, rln_relay_epoch_sec=epoch_sec)
|
self.setup_first_rln_relay_node(rln_relay_user_message_limit=message_limit, rln_relay_epoch_sec=epoch_sec)
|
||||||
self.setup_second_relay_node()
|
self.setup_second_relay_node()
|
||||||
self.subscribe_main_relay_nodes()
|
self.subscribe_main_relay_nodes()
|
||||||
@ -206,10 +254,20 @@ class TestRelayRLN(StepsRLN, StepsRelay):
|
|||||||
if i > message_limit and (now - start) <= epoch_sec:
|
if i > message_limit and (now - start) <= epoch_sec:
|
||||||
raise AssertionError("Publish with RLN enabled at spam rate worked!!!")
|
raise AssertionError("Publish with RLN enabled at spam rate worked!!!")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
assert "RLN validation failed" or "NonceLimitReached" in str(e)
|
error_str = str(e)
|
||||||
|
assert "RLN validation failed" in error_str or "NonceLimitReached" in error_str
|
||||||
|
if "NonceLimitReached" in error_str:
|
||||||
|
assert "500" in error_str, f"Expected HTTP 500 for NonceLimitReached, got: {error_str}"
|
||||||
|
|
||||||
def test_valid_payloads_with_optional_nodes_at_slow_rate(self, pytestconfig):
|
def test_valid_payloads_with_optional_nodes_at_slow_rate(self, pytestconfig):
|
||||||
pytestconfig.cache.set("keystore-prefixes", self.register_rln_relay_nodes(5, []))
|
rln_state = self.register_rln_relay_nodes(5, [])
|
||||||
|
pytestconfig.cache.set(
|
||||||
|
"keystore-prefixes",
|
||||||
|
{
|
||||||
|
"keystore_prefixes": rln_state["keystore_prefixes"],
|
||||||
|
"rln_membership_indexes": rln_state["rln_membership_indexes"],
|
||||||
|
},
|
||||||
|
)
|
||||||
self.setup_main_rln_relay_nodes(rln_relay_user_message_limit=1, rln_relay_epoch_sec=1)
|
self.setup_main_rln_relay_nodes(rln_relay_user_message_limit=1, rln_relay_epoch_sec=1)
|
||||||
self.setup_optional_rln_relay_nodes(rln_relay_user_message_limit=1, rln_relay_epoch_sec=1)
|
self.setup_optional_rln_relay_nodes(rln_relay_user_message_limit=1, rln_relay_epoch_sec=1)
|
||||||
self.subscribe_main_relay_nodes()
|
self.subscribe_main_relay_nodes()
|
||||||
@ -228,7 +286,10 @@ class TestRelayRLN(StepsRLN, StepsRelay):
|
|||||||
assert not failed_payloads, f"Payloads failed: {failed_payloads}"
|
assert not failed_payloads, f"Payloads failed: {failed_payloads}"
|
||||||
|
|
||||||
def test_valid_payloads_with_optional_nodes_at_spam_rate(self, pytestconfig):
|
def test_valid_payloads_with_optional_nodes_at_spam_rate(self, pytestconfig):
|
||||||
self.register_rln_relay_nodes(0, pytestconfig.cache.get("keystore-prefixes", []))
|
self.register_rln_relay_nodes(
|
||||||
|
0,
|
||||||
|
pytestconfig.cache.get("keystore-prefixes", {"keystore_prefixes": [], "rln_membership_indexes": []}),
|
||||||
|
)
|
||||||
self.setup_main_rln_relay_nodes(rln_relay_user_message_limit=1, rln_relay_epoch_sec=1)
|
self.setup_main_rln_relay_nodes(rln_relay_user_message_limit=1, rln_relay_epoch_sec=1)
|
||||||
self.setup_optional_rln_relay_nodes(rln_relay_user_message_limit=1, rln_relay_epoch_sec=1)
|
self.setup_optional_rln_relay_nodes(rln_relay_user_message_limit=1, rln_relay_epoch_sec=1)
|
||||||
self.subscribe_main_relay_nodes()
|
self.subscribe_main_relay_nodes()
|
||||||
@ -246,4 +307,7 @@ class TestRelayRLN(StepsRLN, StepsRelay):
|
|||||||
else:
|
else:
|
||||||
previous = now
|
previous = now
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
assert "RLN validation failed" or "NonceLimitReached" in str(e)
|
error_str = str(e)
|
||||||
|
assert "RLN validation failed" in error_str or "NonceLimitReached" in error_str
|
||||||
|
if "NonceLimitReached" in error_str:
|
||||||
|
assert "500" in error_str, f"Expected HTTP 500 for NonceLimitReached, got: {error_str}"
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user