diff --git a/kurtosis.yml b/kurtosis.yml index c34fd2c49..0dfc6084d 100644 --- a/kurtosis.yml +++ b/kurtosis.yml @@ -1 +1 @@ -name: "github.com/kurtosis-tech/ethereum-package" +name: "github.com/lambdaclass/ethereum-package" diff --git a/src/el/el_launcher.star b/src/el/el_launcher.star index f08a4379f..23d6d07b5 100644 --- a/src/el/el_launcher.star +++ b/src/el/el_launcher.star @@ -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") - +ethereum_rust = import_module("./ethereum_rust/ethereum_rust_launcher.star") def launch( plan, @@ -98,6 +98,14 @@ def launch( ), "launch_method": nimbus_eth1.launch, }, + constants.EL_TYPE.ethereumrust: { + "launcher": ethereum_rust.new_ethereum_rust_launcher( + el_cl_data, + jwt_file, + network_params.network, + ), + "launch_method": ethereum_rust.launch, + }, } all_el_contexts = [] diff --git a/src/el/ethereum_rust/ethereum_rust_launcher.star b/src/el/ethereum_rust/ethereum_rust_launcher.star new file mode 100644 index 000000000..1c3c59448 --- /dev/null +++ b/src/el/ethereum_rust/ethereum_rust_launcher.star @@ -0,0 +1,301 @@ +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" +EXECUTION_DATA_DIRPATH_ON_CLIENT_CONTAINER = "/data/ethereum_rust/execution-data" + +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]["ethereum_rust_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]["ethereum_rust_max_mem"] + ) + + el_volume_size = ( + el_volume_size + if int(el_volume_size) > 0 + else constants.VOLUME_SIZE[network_name]["ethereum_rust_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( + "ethereum_rust", + "", # ethereum_rust 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 = [ + "ethereum_rust", + # "-{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, 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.ethereumrust, + constants.CLIENT_TYPES.el, + image, + cl_client_name, + extra_labels, + ), + tolerations=tolerations, + node_selectors=node_selectors, + ) + + +def new_ethereum_rust_launcher(el_cl_genesis_data, jwt_file, network): + return struct( + el_cl_genesis_data=el_cl_genesis_data, + jwt_file=jwt_file, + network=network, + ) diff --git a/src/package_io/constants.star b/src/package_io/constants.star index 8573d7aaf..bbe19f1ae 100644 --- a/src/package_io/constants.star +++ b/src/package_io/constants.star @@ -7,6 +7,7 @@ EL_TYPE = struct( reth="reth", ethereumjs="ethereumjs", nimbus="nimbus", + ethereumrust="ethereumrust", ) CL_TYPE = struct( @@ -144,7 +145,8 @@ VOLUME_SIZE = { "teku_volume_size": 500000, # 500GB "nimbus_volume_size": 500000, # 500GB "lodestar_volume_size": 500000, # 500GB - "grandine_volume_size": 500000, # 500GB + "grandine_volume_size": 500000, # 500GB, + "ethereum_rust_volume_size": 500000, # 500GB }, "sepolia": { "geth_volume_size": 300000, # 300GB @@ -159,7 +161,8 @@ VOLUME_SIZE = { "teku_volume_size": 150000, # 150GB "nimbus_volume_size": 150000, # 150GB "lodestar_volume_size": 150000, # 150GB - "grandine_volume_size": 150000, # 150GB + "grandine_volume_size": 150000, # 150GB, + "ethereum_rust_volume_size": 150000, # 150GB }, "holesky": { "geth_volume_size": 100000, # 100GB @@ -174,7 +177,8 @@ VOLUME_SIZE = { "teku_volume_size": 100000, # 100GB "nimbus_volume_size": 100000, # 100GB "lodestar_volume_size": 100000, # 100GB - "grandine_volume_size": 100000, # 100GB + "grandine_volume_size": 100000, # 100GB, + "ethereum_rust_volume_size": 100000, # 100GB }, "devnets": { "geth_volume_size": 100000, # 100GB @@ -189,7 +193,8 @@ VOLUME_SIZE = { "teku_volume_size": 100000, # 100GB "nimbus_volume_size": 100000, # 100GB "lodestar_volume_size": 100000, # 100GB - "grandine_volume_size": 100000, # 100GB + "grandine_volume_size": 100000, # 100GB, + "ethereum_rust_volume_size": 100000, # 100GB }, "ephemery": { "geth_volume_size": 5000, # 5GB @@ -205,6 +210,7 @@ VOLUME_SIZE = { "nimbus_volume_size": 1000, # 1GB "lodestar_volume_size": 1000, # 1GB "grandine_volume_size": 1000, # 1GB + "ethereum_rust_volume_size": 1000, # 1GB }, "kurtosis": { "geth_volume_size": 5000, # 5GB @@ -220,6 +226,7 @@ VOLUME_SIZE = { "nimbus_volume_size": 1000, # 1GB "lodestar_volume_size": 1000, # 1GB "grandine_volume_size": 1000, # 1GB + "ethereum_rust_volume_size": 1000, # 1GB }, } @@ -251,6 +258,8 @@ RAM_CPU_OVERRIDES = { "lodestar_max_cpu": 4000, # 4 cores "grandine_max_mem": 16384, # 16GB "grandine_max_cpu": 4000, # 4 cores + "ethereum_rust_max_mem": 16384, # 16GB + "ethereum_rust_max_cpu": 4000, # 4 cores }, "sepolia": { "geth_max_mem": 4096, # 4GB @@ -279,6 +288,8 @@ RAM_CPU_OVERRIDES = { "lodestar_max_cpu": 1000, # 1 core "grandine_max_mem": 4096, # 4GB "grandine_max_cpu": 1000, # 1 core + "ethereum_rust_max_mem": 4096, # 4GB + "ethereum_rust_max_cpu": 1000, # 1 core }, "holesky": { "geth_max_mem": 8192, # 8GB @@ -307,6 +318,8 @@ RAM_CPU_OVERRIDES = { "lodestar_max_cpu": 2000, # 2 cores "grandine_max_mem": 8192, # 8GB "grandine_max_cpu": 2000, # 2 cores + "ethereum_rust_max_mem": 8192, # 8GB + "ethereum_rust_max_cpu": 2000, # 2 cores }, "devnets": { "geth_max_mem": 4096, # 4GB @@ -335,6 +348,8 @@ RAM_CPU_OVERRIDES = { "lodestar_max_cpu": 1000, # 1 core "grandine_max_mem": 4096, # 4GB "grandine_max_cpu": 1000, # 1 core + "ethereum_rust_max_mem": 4096, # 4GB + "ethereum_rust_max_cpu": 1000, # 1 core }, "ephemery": { "geth_max_mem": 1024, # 1GB @@ -363,6 +378,8 @@ RAM_CPU_OVERRIDES = { "lodestar_max_cpu": 1000, # 1 core "grandine_max_mem": 1024, # 1GB "grandine_max_cpu": 1000, # 1 core + "ethereum_rust_max_mem": 1024, # 1GB + "ethereum_rust_max_cpu": 1000, # 1 core }, "kurtosis": { "geth_max_mem": 1024, # 1GB @@ -391,5 +408,7 @@ RAM_CPU_OVERRIDES = { "lodestar_max_cpu": 1000, # 1 core "grandine_max_mem": 2048, # 2GB "grandine_max_cpu": 1000, # 1 core + "ethereum_rust_max_mem": 1024, # 1GB + "ethereum_rust_max_cpu": 1000, # 1 core }, } diff --git a/src/package_io/input_parser.star b/src/package_io/input_parser.star index 99c3baa5a..299872d0f 100644 --- a/src/package_io/input_parser.star +++ b/src/package_io/input_parser.star @@ -12,6 +12,7 @@ DEFAULT_EL_IMAGES = { "reth": "ghcr.io/paradigmxyz/reth", "ethereumjs": "ethpandaops/ethereumjs:master", "nimbus": "ethpandaops/nimbus-eth1:master", + "ethereumrust": "ethereum_rust:latest", } DEFAULT_CL_IMAGES = {