Nomos testing in master (#141)

* Changed gennet to generate simple nomos topology

* Added nomos node to build.sh

* Updated nomos yaml trait

* Added nomos variables to system_variables.star

* Prepared nomos_builder.star

* Modify gennet to work with nomos topology and traits

* Gennet currently doesn't support mixed topologies between waku and nomos nodes.

* Restructured config.json to add separated testing and simulation functionalities

* Added assertions.star file

* Modified wakurtosis to set up integration tests

* Updated kurtosis version in README.md
This commit is contained in:
Alberto Soutullo
2023-07-30 13:42:18 +02:00
committed by GitHub
parent be18041437
commit ceab94f247
11 changed files with 184 additions and 28 deletions

View File

@@ -8,7 +8,7 @@ More info about Kurtosis: https://docs.kurtosis.com/
#### Before using this repository note that:
- **You are using Kurtosis version 0.77.0**. This is important, as they are working on it and changes can be huge depending on different versions. You can find all Kurtosis versions [here](https://github.com/kurtosis-tech/kurtosis-cli-release-artifacts/releases).
- **You are using Kurtosis version 0.70.2**. This is important, as they are working on it and changes can be huge depending on different versions. You can find all Kurtosis versions [here](https://github.com/kurtosis-tech/kurtosis-cli-release-artifacts/releases).
- The topology files that will be used by default are defined in `config/topology_generated/`. This topology is created with the [gennet](gennet-module/Readme.md) module.
- Kurtosis can set up services in a parallel manner, defined in the `config.json` file (see below).
- Only `kurtosis` and `docker` are needed to run this.

View File

@@ -53,3 +53,7 @@ cd ..
#docker build -t gowaku .
#cd ..
#rm -rf go-waku
git clone git@github.com:logos-co/nomos-node.git
docker build -t nomos-node nomos-node
rm -rf nomos-node

View File

@@ -6,19 +6,32 @@
"enclave_name": "wakurtosis",
"topology_path": "./config/topology_generated/",
"jobs": 4,
"interconnect_nodes": false,
"interconnection_batch": 10
"interconnect_nodes": true,
"interconnection_batch": 10,
"monitoring": false,
"injection": false,
"testing": true,
"assertions": {
"nomos": {
"waiting": 60,
"nodes_to_check": 1,
"endpoint": "/carnot/info",
"jq_extract": ".current_view",
"expected_value": 10.0
}
}
},
"gennet": {
"num_nodes": 9,
"num_nodes": 5,
"fanout": 3,
"num_topics": 1,
"num_partitions": 1,
"num_subnets": 1,
"container_size": "1",
"node_type_distribution": {
"nwaku:relay:rpc:metrics:discv5": 100,
"gowaku:rln:dnsdisc:dns": 0
"nwaku:relay:rpc:metrics:discv5": 0,
"gowaku:rln:dnsdisc:dns": 0,
"nomos": 100
},
"network_type": "newmanwattsstrogatz",
"output_dir": "network_data",
@@ -26,7 +39,7 @@
},
"wls": {
"debug_level": "DEBUG",
"simulation_time": 60,
"simulation_time": 20,
"message_rate": 10,
"min_packet_size": 2,
"max_packet_size": 1024,

25
config/traits/nomos.yml Normal file
View File

@@ -0,0 +1,25 @@
log:
backend: "Stdout"
format: "Json"
level: "debug"
consensus:
private_key: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
fountain_settings: null
overlay_settings:
nodes: [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]]
leader:
cur: 0
leader_super_majority_threshold: null
network:
backend:
host: 0.0.0.0
port: 3000
log_level: "fatal"
nodeKey: null
discV5BootstrapNodes: []
initial_peers: []
relayTopics: []
http:
backend:
address: 0.0.0.0:8080
cors_origins: []

View File

@@ -14,9 +14,13 @@ from pathlib import Path
import time, tracemalloc
import string
import typer
import yaml
import hashlib
from enum import Enum, EnumMeta
from blspy import PrivateKey, Util, BasicSchemeMPL, G2Element, G1Element
# Enums & Consts
class MetaEnum(EnumMeta):
@@ -49,15 +53,19 @@ class Trait(BaseEnum):
STORE = "store"
SWAP = "swap"
WEBSOCKET = "websocket"
NOMOS = "nomos"
# To add a new node type, add appropriate entries to the nodeType and nodeTypeToDocker
class nodeType(BaseEnum):
NWAKU = "nwaku" # waku desktop config
GOWAKU = "gowaku" # waku mobile config
NOMOS = "nomos"
nodeTypeToDocker = {
nodeType.NWAKU: "nim-waku",
nodeType.GOWAKU: "go-waku"
nodeType.GOWAKU: "go-waku",
nodeType.NOMOS: "nomos"
}
# To add a new network type, add appropriate entries to the networkType and networkTypeSwitch
@@ -332,7 +340,7 @@ def validate_traits_distribution(traits_dir, traits_distribution):
if traits_list[0] not in nodeType:
raise ValueError(f"{traits_distribution} : unknown node type {traits_list[0]} in {s}")
for t in traits_list[1:]:
if t not in Trait and not os.path.exists(f"{traits_dir}/{t}.toml"):
if t not in Trait and not (os.path.exists(f"{traits_dir}/{t}.toml") or os.path.exists(f"{traits_dir}/{t}.yml")):
raise ValueError(f"{traits_distribution} : unknown trait {t} in {s}")
@@ -406,6 +414,63 @@ def generate_and_write_files(ctx: typer, G):
write_json(ctx.params["output_dir"], json_dump) # network wide json
def generate_and_write_files_nomos(ctx: typer, G):
node2subnet = generate_subnets(G, ctx.params["num_subnets"])
node2container = pack_nodes(ctx.params["container_size"], node2subnet)
container2nodes = invert_dict_of_list(node2container, 1)
json_dump, json_dump[CONTAINERS_JSON], json_dump[NODES_JSON] = {}, {}, {}
for container, nodes in container2nodes.items():
json_dump[CONTAINERS_JSON][container] = nodes
# TODO Put in json_dump[PUBLIC_KEYS] all public keys
json_dump["all_public_keys"] = []
for node in G.nodes:
json_dump[NODES_JSON][node] = {}
json_dump[NODES_JSON][node]["static_nodes"] = []
for edge in G.edges(node):
json_dump[NODES_JSON][node]["static_nodes"].append(edge[1])
json_dump[NODES_JSON][node][SUBNET_PREFIX] = node2subnet[node]
json_dump[NODES_JSON][node]["image"] = nodeTypeToDocker.get(nodeType.NOMOS)
# the per node tomls will continue for now as they include topics
json_dump[NODES_JSON][node]["node_config"] = f"{node}.yml"
# logs ought to continue as they need to be unique
json_dump[NODES_JSON][node]["node_log"] = f"{node}.log"
port_shift, cid = node2container[node]
json_dump[NODES_JSON][node]["container_id"] = cid
# TODO put in json_dump[NODES_JSON]
seed = bytes([random.randint(0, 255) for _ in range(32)])
privatekey = BasicSchemeMPL.key_gen(seed)
json_dump[NODES_JSON][node]["private_key"] = list(bytes(privatekey))
#publickey = privatekey.get_g1()
#hashed_publickey = hashlib.blake2b(bytes(publickey), digest_size=32).digest()
#json_dump[NODES_JSON][node]["public_key"] = list(hashed_publickey)
#json_dump["all_public_keys"].append(list(hashed_publickey))
json_dump[NODES_JSON][node]["public_key"] = list(bytes(privatekey))
json_dump["all_public_keys"].append(list(bytes(privatekey)))
write_ymls(json_dump)
# TODO modificar yml para cada nodo con las claves.
write_json(ctx.params["output_dir"], json_dump) # network wide json
# shutil.copy2("/config/traits/nomos.yml", "/gennet/network_data/nomos.yml")
def write_ymls(json_dump):
with open("/config/traits/nomos.yml", "r") as stream:
try:
nomos_yml_template = yaml.safe_load(stream)
except yaml.YAMLError as exc:
print(exc)
for node_name, node_info in json_dump[NODES_JSON].items():
nomos_yml_template['consensus']['private_key'] = node_info["private_key"]
nomos_yml_template['consensus']['overlay_settings']['nodes'] = json_dump["all_public_keys"]
with open(f'/gennet/network_data/{node_name}.yml', 'w') as f:
yaml.dump(nomos_yml_template, f)
# sanity check : valid json with "gennet" config
def _config_file_callback(ctx: typer.Context, param: typer.CallbackParam, cfile: str):
if cfile:
@@ -498,7 +563,10 @@ def main(ctx: typer.Context,
make_empty_dir(output_dir)
# Generate file format specific data structs and write the files
generate_and_write_files(ctx, G)
if node_type_distribution["nomos"] > 0:
generate_and_write_files_nomos(ctx, G)
else:
generate_and_write_files(ctx, G)
# Draw the graph if need be
if draw:
@@ -517,3 +585,5 @@ def main(ctx: typer.Context,
if __name__ == "__main__":
typer.run(main)

View File

@@ -9,3 +9,5 @@ pyparsing==3.0.9
python-dateutil==2.8.2
six==1.16.0
typer==0.7.0
blspy~=1.0.16
pyyaml

View File

@@ -7,6 +7,7 @@ grafana = import_module(vars.GRAFANA_MODULE)
args_parser = import_module(vars.ARGUMENT_PARSER_MODULE)
wls = import_module(vars.WLS_MODULE)
nodes = import_module(vars.NODE_BUILDERS_MODULE)
assertions = import_module(vars.ASSERTIONS_MODULE)
def run(plan, args):
@@ -24,16 +25,21 @@ def run(plan, args):
network_topology = json.decode(network_topology)
# Set up nodes
nodes.instantiate_services(plan, network_topology, True, False)
nodes.instantiate_services(plan, network_topology, not kurtosis_config["interconnect_nodes"], False)
# Set up prometheus + grafana
prometheus_service = prometheus.set_up_prometheus(plan, network_topology)
grafana_service = grafana.set_up_grafana(plan, prometheus_service)
if kurtosis_config["monitoring"]:
prometheus_service = prometheus.set_up_prometheus(plan, network_topology)
grafana_service = grafana.set_up_grafana(plan, prometheus_service)
# Interconnect nodes if needed
if kurtosis_config[vars.INTERCONNECT_NODES]:
nodes.interconnect_nodes(plan, network_topology, interconnection_batch)
# Setup WLS & Start the Simulation
wls_service = wls.init(plan, network_topology, config_file, prometheus_service)
if kurtosis_config["injection"]:
wls_service = wls.init(plan, network_topology, config_file, prometheus_service)
# Tests
if kurtosis_config["testing"]:
assertions.start_test(plan, kurtosis_config, network_topology)

28
src/assertions.star Normal file
View File

@@ -0,0 +1,28 @@
# System Imports
vars = import_module("github.com/logos-co/wakurtosis/src/system_variables.star")
# Module Imports
call_protocols = import_module(vars.CALL_PROTOCOLS)
def start_test(plan, kurtosis_config, network_topology):
for name, values in kurtosis_config["assertions"].items():
exec_recipe = ExecRecipe(
command=["sleep", str(values["waiting"])]
)
plan.exec(
service_name=network_topology["nodes"].values()[0]["container_id"],
recipe=exec_recipe)
for service_name, service_info in network_topology["nodes"].items():
extract = {"jq_extract": values["jq_extract"]}
response = call_protocols.send_http_get_req(plan, service_info["container_id"],
vars.WAKU_RPC_PORT_ID + vars.ID_STR_SEPARATOR + service_name,
values["endpoint"], extract)
plan.assert(value=response["code"], assertion="==", target_value = 200)
plan.assert(value=response["extract.jq_extract"], assertion=">",
target_value=values["expected_value"])
plan.remove_service(service_info["container_id"])

View File

@@ -54,6 +54,8 @@ def instantiate_services(plan, network_topology, discovery, testing):
_add_service_info_to_topology(plan, all_services_information, network_topology, discovery)
return all_services_information
def interconnect_nodes(plan, topology_information, interconnection_batch):
# Interconnect them

View File

@@ -2,10 +2,11 @@
vars = import_module("github.com/logos-co/wakurtosis/src/system_variables.star")
def prepare_nomos_service(node_name, all_services, config_files, artifact_ids, service_id):
prepared_ports = _prepare_nomos_ports_in_service(node_name)
prepared_files = _prepare_nomos_config_files_in_service(node_name, artifact_ids)
prepared_cmd = _prepare_nomos_cmd_in_service(node_name, config_files)
def prepare_nomos_service(node_names, all_services, config_files, artifact_ids, run_artifact_id,
service_id, network_topology, discovery):
prepared_ports = _prepare_nomos_ports_in_service(node_names)
prepared_files = _prepare_nomos_config_files_in_service(node_names, artifact_ids)
prepared_cmd = _prepare_nomos_cmd_in_service(node_names, config_files)
add_service_config = ServiceConfig(
image=vars.NOMOS_IMAGE,
@@ -22,7 +23,8 @@ def _prepare_nomos_cmd_in_service(nomos_names, config_files):
prepared_cmd = ""
for i in range(len(nomos_names)):
prepared_cmd += vars.NOMOS_ENTRYPOINT + " "
prepared_cmd += vars.NOMOS_CONTAINER_CONFIG_FILE_LOCATION + " "
# prepared_cmd += vars.NOMOS_CONTAINER_CONFIG_FILE_LOCATION + " "
prepared_cmd += vars.CONTAINER_NODE_CONFIG_FILE_LOCATION + nomos_names[i] + "/" + config_files[i] + " "
# prepared_cmd += vars.NOMOS_PORT_SHIFT_FLAG + str(i)
if i != len(nomos_names) - 1:
prepared_cmd += " & "
@@ -37,9 +39,9 @@ def _prepare_nomos_ports_in_service(node_names):
PortSpec(number=vars.NOMOS_RPC_PORT_NUMBER + i,
transport_protocol=vars.NOMOS_RPC_PORT_PROTOCOL)
prepared_ports[vars.PROMETHEUS_PORT_ID + vars.ID_STR_SEPARATOR + node_names[i]] = \
PortSpec(number=vars.PROMETHEUS_PORT_NUMBER + i,
transport_protocol=vars.PROMETHEUS_PORT_PROTOCOL)
#prepared_ports[vars.PROMETHEUS_PORT_ID + vars.ID_STR_SEPARATOR + node_names[i]] = \
# PortSpec(number=vars.NOMOS_PROMETHEUS_PORT_NUMBER + i,
# transport_protocol=vars.PROMETHEUS_PORT_PROTOCOL)
prepared_ports[vars.NOMOS_LIBP2P_PORT_ID + vars.ID_STR_SEPARATOR + node_names[i]] = \
PortSpec(number=vars.NOMOS_LIBP2P_PORT + i,
@@ -57,7 +59,8 @@ def _prepare_nomos_config_files_in_service(node_names, artifact_ids):
return prepared_files
def add_nomos_ports_info_to_topology(network_topology, all_services_information, node_info, node_id):
def add_nomos_ports_info_to_topology(network_topology, all_services_information, node_info, node_id,
discovery):
nomos_rpc_port_id = vars.WAKU_RPC_PORT_ID + vars.ID_STR_SEPARATOR + node_id
libp2p_port_id = vars.NOMOS_LIBP2P_PORT_ID + vars.ID_STR_SEPARATOR + node_id
prometheus_port_id = vars.PROMETHEUS_PORT_ID + vars.ID_STR_SEPARATOR + node_id
@@ -65,7 +68,7 @@ def add_nomos_ports_info_to_topology(network_topology, all_services_information,
network_topology[vars.GENNET_NODES_KEY][node_id][vars.PORTS_KEY] = {}
_add_nomos_port(network_topology, all_services_information, node_id, node_info, nomos_rpc_port_id)
_add_nomos_port(network_topology, all_services_information, node_id, node_info, libp2p_port_id)
_add_nomos_port(network_topology, all_services_information, node_id, node_info, prometheus_port_id)
#_add_nomos_port(network_topology, all_services_information, node_id, node_info, prometheus_port_id)
def _add_nomos_port(network_topology, all_services_information, node_id, node_info, port_id):

View File

@@ -1,6 +1,7 @@
# Waku Configuration
# IMAGES
NWAKU_IMAGE = "statusteam/nim-waku:nwaku-trace3"
GOWAKU_IMAGE = "gowaku"
NOMOS_IMAGE = "nomos-node"
# If changing this, you'll likely need to change it as well in gennet
ID_STR_SEPARATOR = "-"
@@ -37,10 +38,9 @@ NWAKU_SCRIPT_ENTRYPOINT = "run_waku_node.sh"
GOWAKU_ENTRYPOINT = "/usr/bin/waku --rpc-address=0.0.0.0 --metrics-server-address=0.0.0.0"
NOMOS_ENTRYPOINT = "/usr/bin/nomos-node"
NOMOS_PORT_SHIFT_FLAG = "--ports-shift="
NOMOS_CONTAINER_CONFIG_FILE_LOCATION = '/etc/nomos/config.yml'
NOMOS_CONTAINER_CONFIG_FILE_LOCATION = '/etc/nomos/config.yaml'
# Nomos Configuration
NOMOS_IMAGE = "nomos"
NOMOS_RPC_PORT_PROTOCOL = "TCP"
NOMOS_RPC_PORT_NUMBER = 8080
NOMOS_LIBP2P_PORT_PROTOCOL = "TCP"
@@ -48,6 +48,8 @@ NOMOS_LIBP2P_PORT_ID = "libp2p"
NOMOS_LIBP2P_PORT = 3000
NOMOS_NET_INFO_URL = "/network/info"
NOMOS_NET_CONN_URL = "/network/conn"
NOMOS_CARNOT_INFO = "/carnot/info"
NOMOS_PROMETHEUS_PORT_NUMBER = 8080
# Prometheus Configuration
PROMETHEUS_IMAGE = "prom/prometheus:latest"
@@ -141,6 +143,7 @@ TEMPLATES_MODULE = "github.com/logos-co/wakurtosis/src/templates.star"
WLS_MODULE = "github.com/logos-co/wakurtosis/src/wls.star"
CALL_PROTOCOLS = "github.com/logos-co/wakurtosis/src/call_protocols.star"
NOMOS_MODULE = "github.com/logos-co/wakurtosis/src/nomos.star"
ASSERTIONS_MODULE = "github.com/logos-co/wakurtosis/src/assertions.star"
TEST_ARGUMENTS_MODULE = "github.com/logos-co/wakurtosis/src/tests/test_arguments_parser.star"