Skip to content

Commit

Permalink
feat: add nimbus-eth1 (#496)
Browse files Browse the repository at this point in the history
  • Loading branch information
barnabasbusa authored Feb 27, 2024
1 parent 90da2c3 commit d599729
Show file tree
Hide file tree
Showing 6 changed files with 318 additions and 1 deletion.
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

0 comments on commit d599729

Please sign in to comment.