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 support for ethereum_rust #1

Draft
wants to merge 14 commits into
base: main
Choose a base branch
from
10 changes: 9 additions & 1 deletion src/el/el_launcher.star
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ nethermind = import_module("./nethermind/nethermind_launcher.star")
reth = import_module("./reth/reth_launcher.star")
ethereumjs = import_module("./ethereumjs/ethereumjs_launcher.star")
nimbus_eth1 = import_module("./nimbus-eth1/nimbus_launcher.star")

ethrex = import_module("./ethrex/ethrex_launcher.star")

def launch(
plan,
Expand Down Expand Up @@ -98,6 +98,14 @@ def launch(
),
"launch_method": nimbus_eth1.launch,
},
constants.EL_TYPE.ethrex: {
"launcher": ethrex.new_ethrex_launcher(
el_cl_data,
jwt_file,
network_params.network,
),
"launch_method": ethrex.launch,
},
}

all_el_contexts = []
Expand Down
300 changes: 300 additions & 0 deletions src/el/ethrex/ethrex_launcher.star
Original file line number Diff line number Diff line change
@@ -0,0 +1,300 @@
shared_utils = import_module("../../shared_utils/shared_utils.star")
input_parser = import_module("../../package_io/input_parser.star")
el_context = import_module("../../el/el_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")

RPC_PORT_NUM = 8545
WS_PORT_NUM = 8546
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
RPC_PORT_ID = "rpc"
WS_PORT_ID = "ws"
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"

def get_used_ports(discovery_port=DISCOVERY_PORT_NUM):
used_ports = {
RPC_PORT_ID: shared_utils.new_port_spec(
RPC_PORT_NUM,
shared_utils.TCP_PROTOCOL,
shared_utils.HTTP_APPLICATION_PROTOCOL,
),
# WS_PORT_ID: shared_utils.new_port_spec(WS_PORT_NUM, shared_utils.TCP_PROTOCOL),
# TCP_DISCOVERY_PORT_ID: shared_utils.new_port_spec(
# discovery_port, shared_utils.TCP_PROTOCOL
# ),
# UDP_DISCOVERY_PORT_ID: shared_utils.new_port_spec(
# discovery_port, 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
# ),
}
return used_ports


ENTRYPOINT_ARGS = ["sh", "-c"]

VERBOSITY_LEVELS = {
constants.GLOBAL_LOG_LEVEL.error: "1",
constants.GLOBAL_LOG_LEVEL.warn: "2",
constants.GLOBAL_LOG_LEVEL.info: "3",
constants.GLOBAL_LOG_LEVEL.debug: "4",
constants.GLOBAL_LOG_LEVEL.trace: "5",
}


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,
port_publisher,
):
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]["ethrex_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]["ethrex_max_mem"]
)

el_volume_size = (
el_volume_size
if int(el_volume_size) > 0
else constants.VOLUME_SIZE[network_name]["ethrex_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,
port_publisher,
)

service = plan.add_service(service_name, config)

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

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

return el_context.new_el_context(
"ethrex",
"", # ethrex has no enr?
enode,
service.ip_address,
RPC_PORT_NUM,
WS_PORT_NUM,
ENGINE_RPC_PORT_NUM,
service_name,
[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,
port_publisher,
):
public_ports = {}
discovery_port = DISCOVERY_PORT_NUM
if port_publisher.public_port_start:
discovery_port = port_publisher.el_start + len(existing_el_clients)
public_ports = {
TCP_DISCOVERY_PORT_ID: shared_utils.new_port_spec(
discovery_port, shared_utils.TCP_PROTOCOL
),
UDP_DISCOVERY_PORT_ID: shared_utils.new_port_spec(
discovery_port, shared_utils.UDP_PROTOCOL
),
}
used_ports = get_used_ports(discovery_port)

cmd = [
"ethrex",
# "-{0}".format(verbosity_level),
# "--datadir=" + EXECUTION_DATA_DIRPATH_ON_CLIENT_CONTAINER,
# "--network={0}".format(
# network
# if network in constants.PUBLIC_NETWORKS
# else constants.GENESIS_CONFIG_MOUNT_PATH_ON_CONTAINER + "/genesis.json"
# ),
# "--http",
"--http.port={0}".format(RPC_PORT_NUM),
"--http.addr=0.0.0.0",
# "--http.corsdomain=*",
# # WARNING: The admin info endpoint is enabled so that we can easily get ENR/enode, which means
# # that users should NOT store private information in these Kurtosis nodes!
# "--http.api=admin,net,eth,web3,debug,trace",
# "--ws",
# "--ws.addr=0.0.0.0",
# "--ws.port={0}".format(WS_PORT_NUM),
# "--ws.api=net,eth",
# "--ws.origins=*",
# "--nat=extip:" + port_publisher.nat_exit_ip,
"--authrpc.port={0}".format(ENGINE_RPC_PORT_NUM),
# "--authrpc.jwtsecret=" + constants.JWT_MOUNT_PATH_ON_CONTAINER,
"--authrpc.addr=0.0.0.0",
# "--metrics=0.0.0.0:{0}".format(METRICS_PORT_NUM),
# "--discovery.port={0}".format(discovery_port),
]
# if network == constants.NETWORK_NAME.kurtosis:
# if len(existing_el_clients) > 0:
# cmd.append(
# "--bootnodes="
# + ",".join(
# [
# ctx.enode
# for ctx in existing_el_clients[: constants.MAX_ENODE_ENTRIES]
# ]
# )
# )
# elif network not in constants.PUBLIC_NETWORKS:
# cmd.append(
# "--bootnodes="
# + 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])

cmd_str = " ".join(cmd)
if network not in constants.PUBLIC_NETWORKS:
# subcommand_strs = [
# init_datadir_cmd_str,
# cmd_str,
# ]
subcommand_strs = [cmd_str]
else:
subcommand_strs = [cmd_str]

command_str = " && ".join(subcommand_strs)

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,
public_ports=public_ports,
cmd=[command_str],
files=files,
entrypoint=ENTRYPOINT_ARGS,
private_ip_address_placeholder=constants.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_TYPE.ethrex,
constants.CLIENT_TYPES.el,
image,
cl_client_name,
extra_labels,
),
tolerations=tolerations,
node_selectors=node_selectors,
)


def new_ethrex_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