Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add nimbus-eth1 #496

Merged
merged 9 commits into from
Feb 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions .github/tests/nimbus-eth1-all.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
participants:
- el_client_type: geth
cl_client_type: teku
- el_client_type: nimbus
cl_client_type: teku
- el_client_type: nimbus
cl_client_type: prysm
- el_client_type: nimbus
cl_client_type: nimbus
- el_client_type: nimbus
cl_client_type: lighthouse
- el_client_type: nimbus
cl_client_type: lodestar
additional_services: []
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ To configure the package behaviour, you can modify your `network_params.yaml` fi
# Specification of the participants in the network
participants:
# The type of EL client that should be started
# Valid values are geth, nethermind, erigon, besu, ethereumjs, reth
# Valid values are geth, nethermind, erigon, besu, ethereumjs, reth, nimbus-eth1
- el_client_type: geth

# The Docker image that should be used for the EL client; leave blank to use the default for the client type
Expand All @@ -164,6 +164,7 @@ participants:
# - besu: hyperledger/besu:develop
# - reth: ghcr.io/paradigmxyz/reth
# - ethereumjs: ethpandaops/ethereumjs:master
# - nimbus-eth1: ethpandaops/nimbus-eth1:master
el_client_image: ""

# The log level string that this participant's EL client should log at
Expand Down
270 changes: 270 additions & 0 deletions src/el/nimbus-eth1/nimbus_launcher.star
Original file line number Diff line number Diff line change
@@ -0,0 +1,270 @@
shared_utils = import_module("../../shared_utils/shared_utils.star")
input_parser = import_module("../../package_io/input_parser.star")
el_client_context = import_module("../../el/el_client_context.star")
el_admin_node_info = import_module("../../el/el_admin_node_info.star")
node_metrics = import_module("../../node_metrics_info.star")
constants = import_module("../../package_io/constants.star")

WS_RPC_PORT_NUM = 8545
DISCOVERY_PORT_NUM = 30303
ENGINE_RPC_PORT_NUM = 8551
METRICS_PORT_NUM = 9001

# The min/max CPU/memory that the execution node can use
EXECUTION_MIN_CPU = 100
EXECUTION_MIN_MEMORY = 256

# Port IDs
WS_RPC_PORT_ID = "ws-rpc"
TCP_DISCOVERY_PORT_ID = "tcp-discovery"
UDP_DISCOVERY_PORT_ID = "udp-discovery"
ENGINE_RPC_PORT_ID = "engine-rpc"
METRICS_PORT_ID = "metrics"

# Paths
METRICS_PATH = "/metrics"

# The dirpath of the execution data directory on the client container
EXECUTION_DATA_DIRPATH_ON_CLIENT_CONTAINER = "/data/nimbus/execution-data"

PRIVATE_IP_ADDRESS_PLACEHOLDER = "KURTOSIS_IP_ADDR_PLACEHOLDER"

USED_PORTS = {
WS_RPC_PORT_ID: shared_utils.new_port_spec(
WS_RPC_PORT_NUM,
shared_utils.TCP_PROTOCOL,
),
TCP_DISCOVERY_PORT_ID: shared_utils.new_port_spec(
DISCOVERY_PORT_NUM,
shared_utils.TCP_PROTOCOL,
),
UDP_DISCOVERY_PORT_ID: shared_utils.new_port_spec(
DISCOVERY_PORT_NUM,
shared_utils.UDP_PROTOCOL,
),
ENGINE_RPC_PORT_ID: shared_utils.new_port_spec(
ENGINE_RPC_PORT_NUM,
shared_utils.TCP_PROTOCOL,
),
METRICS_PORT_ID: shared_utils.new_port_spec(
METRICS_PORT_NUM,
shared_utils.TCP_PROTOCOL,
),
}

VERBOSITY_LEVELS = {
constants.GLOBAL_CLIENT_LOG_LEVEL.error: "ERROR",
constants.GLOBAL_CLIENT_LOG_LEVEL.warn: "WARN",
constants.GLOBAL_CLIENT_LOG_LEVEL.info: "INFO",
constants.GLOBAL_CLIENT_LOG_LEVEL.debug: "DEBUG",
constants.GLOBAL_CLIENT_LOG_LEVEL.trace: "TRACE",
}


def launch(
plan,
launcher,
service_name,
image,
participant_log_level,
global_log_level,
# If empty then the node will be launched as a bootnode
existing_el_clients,
el_min_cpu,
el_max_cpu,
el_min_mem,
el_max_mem,
extra_params,
extra_env_vars,
extra_labels,
persistent,
el_volume_size,
tolerations,
node_selectors,
):
log_level = input_parser.get_client_log_level_or_default(
participant_log_level, global_log_level, VERBOSITY_LEVELS
)

network_name = shared_utils.get_network_name(launcher.network)

el_min_cpu = int(el_min_cpu) if int(el_min_cpu) > 0 else EXECUTION_MIN_CPU
el_max_cpu = (
int(el_max_cpu)
if int(el_max_cpu) > 0
else constants.RAM_CPU_OVERRIDES[network_name]["nimbus_eth1_max_cpu"]
)
el_min_mem = int(el_min_mem) if int(el_min_mem) > 0 else EXECUTION_MIN_MEMORY
el_max_mem = (
int(el_max_mem)
if int(el_max_mem) > 0
else constants.RAM_CPU_OVERRIDES[network_name]["nimbus_eth1_max_mem"]
)

el_volume_size = (
el_volume_size
if int(el_volume_size) > 0
else constants.VOLUME_SIZE[network_name]["nimbus_eth1_volume_size"]
)

cl_client_name = service_name.split("-")[3]

config = get_config(
plan,
launcher.el_cl_genesis_data,
launcher.jwt_file,
launcher.network,
image,
service_name,
existing_el_clients,
cl_client_name,
log_level,
el_min_cpu,
el_max_cpu,
el_min_mem,
el_max_mem,
extra_params,
extra_env_vars,
extra_labels,
persistent,
el_volume_size,
tolerations,
node_selectors,
)

service = plan.add_service(service_name, config)

enode = el_admin_node_info.get_enode_for_node(plan, service_name, WS_RPC_PORT_ID)

metric_url = "{0}:{1}".format(service.ip_address, METRICS_PORT_NUM)
nimbus_metrics_info = node_metrics.new_node_metrics_info(
service_name, METRICS_PATH, metric_url
)

return el_client_context.new_el_client_context(
"nimbus",
"", # nimbus has no enr
enode,
service.ip_address,
WS_RPC_PORT_NUM,
WS_RPC_PORT_NUM,
ENGINE_RPC_PORT_NUM,
service_name,
[nimbus_metrics_info],
)


def get_config(
plan,
el_cl_genesis_data,
jwt_file,
network,
image,
service_name,
existing_el_clients,
cl_client_name,
verbosity_level,
el_min_cpu,
el_max_cpu,
el_min_mem,
el_max_mem,
extra_params,
extra_env_vars,
extra_labels,
persistent,
el_volume_size,
tolerations,
node_selectors,
):
cmd = [
"--log-level={0}".format(verbosity_level),
"--data-dir=" + EXECUTION_DATA_DIRPATH_ON_CLIENT_CONTAINER,
"--http-port={0}".format(WS_RPC_PORT_NUM),
"--http-address=0.0.0.0",
"--rpc",
"--rpc-api=eth,debug,exp",
"--ws",
"--ws-api=eth,debug,exp",
"--engine-api",
"--engine-api-address=0.0.0.0",
"--engine-api-port={0}".format(ENGINE_RPC_PORT_NUM),
"--jwt-secret=" + constants.JWT_MOUNT_PATH_ON_CONTAINER,
"--metrics",
"--metrics-address=0.0.0.0",
"--metrics-port={0}".format(METRICS_PORT_NUM),
]
if (
network not in constants.PUBLIC_NETWORKS
or constants.NETWORK_NAME.shadowfork in network
):
cmd.append(
"--custom-network="
+ constants.GENESIS_CONFIG_MOUNT_PATH_ON_CONTAINER
+ "/genesis.json"
)
else:
cmd.append("--network=" + network)

if network == constants.NETWORK_NAME.kurtosis:
if len(existing_el_clients) > 0:
cmd.append(
"--bootstrap-node="
+ ",".join(
[
ctx.enode
for ctx in existing_el_clients[: constants.MAX_ENODE_ENTRIES]
]
)
)
elif network not in constants.PUBLIC_NETWORKS:
cmd.append(
"--bootstrap-node="
+ shared_utils.get_devnet_enodes(
plan, el_cl_genesis_data.files_artifact_uuid
)
)

if len(extra_params) > 0:
# this is a repeated<proto type>, we convert it into Starlark
cmd.extend([param for param in extra_params])

files = {
constants.GENESIS_DATA_MOUNTPOINT_ON_CLIENTS: el_cl_genesis_data.files_artifact_uuid,
constants.JWT_MOUNTPOINT_ON_CLIENTS: jwt_file,
}

if persistent:
files[EXECUTION_DATA_DIRPATH_ON_CLIENT_CONTAINER] = Directory(
persistent_key="data-{0}".format(service_name),
size=el_volume_size,
)

return ServiceConfig(
image=image,
ports=USED_PORTS,
cmd=cmd,
files=files,
private_ip_address_placeholder=PRIVATE_IP_ADDRESS_PLACEHOLDER,
min_cpu=el_min_cpu,
max_cpu=el_max_cpu,
min_memory=el_min_mem,
max_memory=el_max_mem,
env_vars=extra_env_vars,
labels=shared_utils.label_maker(
constants.EL_CLIENT_TYPE.nimbus,
constants.CLIENT_TYPES.el,
image,
cl_client_name,
extra_labels,
),
tolerations=tolerations,
node_selectors=node_selectors,
)


def new_nimbus_launcher(el_cl_genesis_data, jwt_file, network):
return struct(
el_cl_genesis_data=el_cl_genesis_data,
jwt_file=jwt_file,
network=network,
)
Loading