diff --git a/src/cl/op-node/op_node_builder_launcher.star b/src/cl/op-node/op_node_builder_launcher.star new file mode 100644 index 0000000..079607d --- /dev/null +++ b/src/cl/op-node/op_node_builder_launcher.star @@ -0,0 +1,270 @@ +ethereum_package_shared_utils = import_module( + "github.com/ethpandaops/ethereum-package/src/shared_utils/shared_utils.star" +) + +ethereum_package_cl_context = import_module( + "github.com/ethpandaops/ethereum-package/src/cl/cl_context.star" +) + +ethereum_package_constants = import_module( + "github.com/ethpandaops/ethereum-package/src/package_io/constants.star" +) + +ethereum_package_input_parser = import_module( + "github.com/ethpandaops/ethereum-package/src/package_io/input_parser.star" +) + +constants = import_module("../../package_io/constants.star") + +util = import_module("../../util.star") + +# ---------------------------------- Beacon client ------------------------------------- + +# The Docker container runs as the "op-node" user so we can't write to root +BEACON_DATA_DIRPATH_ON_SERVICE_CONTAINER = "/data/op-node/op-node-beacon-data" +# Port IDs +BEACON_TCP_DISCOVERY_PORT_ID = "tcp-discovery" +BEACON_UDP_DISCOVERY_PORT_ID = "udp-discovery" +BEACON_HTTP_PORT_ID = "http" + +# Port nums +BEACON_DISCOVERY_PORT_NUM = 9003 +BEACON_HTTP_PORT_NUM = 8547 + + +def get_used_ports(discovery_port): + used_ports = { + BEACON_TCP_DISCOVERY_PORT_ID: ethereum_package_shared_utils.new_port_spec( + discovery_port, ethereum_package_shared_utils.TCP_PROTOCOL, wait=None + ), + BEACON_UDP_DISCOVERY_PORT_ID: ethereum_package_shared_utils.new_port_spec( + discovery_port, ethereum_package_shared_utils.UDP_PROTOCOL, wait=None + ), + BEACON_HTTP_PORT_ID: ethereum_package_shared_utils.new_port_spec( + BEACON_HTTP_PORT_NUM, + ethereum_package_shared_utils.TCP_PROTOCOL, + ethereum_package_shared_utils.HTTP_APPLICATION_PROTOCOL, + ), + } + return used_ports + + +ENTRYPOINT_ARGS = ["sh", "-c"] + +VERBOSITY_LEVELS = { + ethereum_package_constants.GLOBAL_LOG_LEVEL.error: "ERROR", + ethereum_package_constants.GLOBAL_LOG_LEVEL.warn: "WARN", + ethereum_package_constants.GLOBAL_LOG_LEVEL.info: "INFO", + ethereum_package_constants.GLOBAL_LOG_LEVEL.debug: "DEBUG", + ethereum_package_constants.GLOBAL_LOG_LEVEL.trace: "TRACE", +} + + +def launch( + plan, + launcher, + service_name, + participant, + global_log_level, + persistent, + tolerations, + node_selectors, + el_context, + existing_cl_clients, + l1_config_env_vars, + sequencer_enabled, +): + beacon_node_identity_recipe = PostHttpRequestRecipe( + endpoint="/", + content_type="application/json", + body='{"jsonrpc":"2.0","method":"opp2p_self","params":[],"id":1}', + port_id=BEACON_HTTP_PORT_ID, + extract={ + "enr": ".result.ENR", + "multiaddr": ".result.addresses[0]", + "peer_id": ".result.peerID", + }, + ) + + log_level = ethereum_package_input_parser.get_client_log_level_or_default( + participant.cl_builder_log_level, global_log_level, VERBOSITY_LEVELS + ) + + config = get_beacon_config( + plan, + launcher, + service_name, + participant, + log_level, + persistent, + tolerations, + node_selectors, + el_context, + existing_cl_clients, + l1_config_env_vars, + beacon_node_identity_recipe, + sequencer_enabled, + ) + + beacon_service = plan.add_service(service_name, config) + + beacon_http_port = beacon_service.ports[BEACON_HTTP_PORT_ID] + beacon_http_url = "http://{0}:{1}".format( + beacon_service.ip_address, beacon_http_port.number + ) + + response = plan.request( + recipe=beacon_node_identity_recipe, service_name=service_name + ) + + beacon_node_enr = response["extract.enr"] + beacon_multiaddr = response["extract.multiaddr"] + beacon_peer_id = response["extract.peer_id"] + + return ethereum_package_cl_context.new_cl_context( + client_name="op-node", + enr=beacon_node_enr, + ip_addr=beacon_service.ip_address, + http_port=beacon_http_port.number, + beacon_http_url=beacon_http_url, + cl_nodes_metrics_info=None, + beacon_service_name=service_name, + multiaddr=beacon_multiaddr, + peer_id=beacon_peer_id, + ) + + +def get_beacon_config( + plan, + launcher, + service_name, + participant, + log_level, + persistent, + tolerations, + node_selectors, + el_context, + existing_cl_clients, + l1_config_env_vars, + beacon_node_identity_recipe, + sequencer_enabled, +): + EXECUTION_ENGINE_ENDPOINT = "http://{0}:{1}".format( + el_context.ip_addr, + el_context.engine_rpc_port_num, + ) + + used_ports = get_used_ports(BEACON_DISCOVERY_PORT_NUM) + + cmd = [ + "op-node", + "--l2={0}".format(EXECUTION_ENGINE_ENDPOINT), + "--l2.jwt-secret=" + ethereum_package_constants.JWT_MOUNT_PATH_ON_CONTAINER, + "--verifier.l1-confs=4", + "--rollup.config=" + + ethereum_package_constants.GENESIS_DATA_MOUNTPOINT_ON_CLIENTS + + "/rollup-{0}.json".format(launcher.network_params.network_id), + "--rpc.addr=0.0.0.0", + "--rpc.port={0}".format(BEACON_HTTP_PORT_NUM), + "--rpc.enable-admin", + "--l1={0}".format(l1_config_env_vars["L1_RPC_URL"]), + "--l1.rpckind={0}".format(l1_config_env_vars["L1_RPC_KIND"]), + "--l1.beacon={0}".format(l1_config_env_vars["CL_RPC_URL"]), + "--l1.trustrpc", + "--p2p.advertise.ip=" + + ethereum_package_constants.PRIVATE_IP_ADDRESS_PLACEHOLDER, + "--p2p.advertise.tcp={0}".format(BEACON_DISCOVERY_PORT_NUM), + "--p2p.advertise.udp={0}".format(BEACON_DISCOVERY_PORT_NUM), + "--p2p.listen.ip=0.0.0.0", + "--p2p.listen.tcp={0}".format(BEACON_DISCOVERY_PORT_NUM), + "--p2p.listen.udp={0}".format(BEACON_DISCOVERY_PORT_NUM), + ] + + sequencer_private_key = util.read_network_config_value( + plan, + launcher.deployment_output, + "sequencer-{0}".format(launcher.network_params.network_id), + ".privateKey", + ) + + if sequencer_enabled: + cmd.append("--p2p.sequencer.key=" + sequencer_private_key) + cmd.append("--sequencer.enabled") + cmd.append("--sequencer.l1-confs=5") + + if len(existing_cl_clients) > 0: + cmd.append( + "--p2p.bootnodes=" + + ",".join( + [ + ctx.enr + for ctx in existing_cl_clients[ + : ethereum_package_constants.MAX_ENR_ENTRIES + ] + ] + ) + ) + + cmd += participant.cl_builder_extra_params + + files = { + ethereum_package_constants.GENESIS_DATA_MOUNTPOINT_ON_CLIENTS: launcher.deployment_output, + ethereum_package_constants.JWT_MOUNTPOINT_ON_CLIENTS: launcher.jwt_file, + } + + if persistent: + files[BEACON_DATA_DIRPATH_ON_SERVICE_CONTAINER] = Directory( + persistent_key="data-{0}".format(service_name), + size=int(participant.cl_builder_volume_size) + if int(participant.cl_builder_volume_size) > 0 + else constants.VOLUME_SIZE[launcher.network][ + constants.CL_TYPE.hildr + "_volume_size" + ], + ) + + ports = {} + ports.update(used_ports) + + env_vars = participant.cl_builder_extra_env_vars + config_args = { + "image": participant.cl_builder_image, + "ports": ports, + "cmd": cmd, + "files": files, + "private_ip_address_placeholder": ethereum_package_constants.PRIVATE_IP_ADDRESS_PLACEHOLDER, + "env_vars": env_vars, + "labels": ethereum_package_shared_utils.label_maker( + client=constants.CL_TYPE.op_node, + client_type=constants.CLIENT_TYPES.cl, + image=participant.cl_builder_image[-constants.MAX_LABEL_LENGTH :], + connected_client=el_context.client_name, + extra_labels=participant.cl_builder_extra_labels, + ), + "ready_conditions": ReadyCondition( + recipe=beacon_node_identity_recipe, + field="code", + assertion="==", + target_value=200, + timeout="1m", + ), + "tolerations": tolerations, + "node_selectors": node_selectors, + } + + if participant.cl_builder_min_cpu > 0: + config_args["min_cpu"] = participant.cl_builder_min_cpu + if participant.cl_builder_max_cpu > 0: + config_args["max_cpu"] = participant.cl_builder_max_cpu + if participant.cl_builder_min_mem > 0: + config_args["min_memory"] = participant.cl_builder_min_mem + if participant.cl_builder_max_mem > 0: + config_args["max_memory"] = participant.cl_builder_max_mem + return ServiceConfig(**config_args) + + +def new_op_node_builder_launcher(deployment_output, jwt_file, network_params): + return struct( + deployment_output=deployment_output, + jwt_file=jwt_file, + network_params=network_params, + ) diff --git a/src/el/op-geth/op_geth_builder_launcher.star b/src/el/op-geth/op_geth_builder_launcher.star new file mode 100644 index 0000000..8ad447f --- /dev/null +++ b/src/el/op-geth/op_geth_builder_launcher.star @@ -0,0 +1,293 @@ +ethereum_package_shared_utils = import_module( + "github.com/ethpandaops/ethereum-package/src/shared_utils/shared_utils.star" +) + +ethereum_package_el_context = import_module( + "github.com/ethpandaops/ethereum-package/src/el/el_context.star" +) +ethereum_package_el_admin_node_info = import_module( + "github.com/ethpandaops/ethereum-package/src/el/el_admin_node_info.star" +) + +ethereum_package_node_metrics = import_module( + "github.com/ethpandaops/ethereum-package/src/node_metrics_info.star" +) + +ethereum_package_input_parser = import_module( + "github.com/ethpandaops/ethereum-package/src/package_io/input_parser.star" +) + +ethereum_package_constants = import_module( + "github.com/ethpandaops/ethereum-package/src/package_io/constants.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 = 300 +EXECUTION_MIN_MEMORY = 512 + +# 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" +ENGINE_WS_PORT_ID = "engineWs" +METRICS_PORT_ID = "metrics" + +# TODO(old) Scale this dynamically based on CPUs available and Geth nodes mining +NUM_MINING_THREADS = 1 + +METRICS_PATH = "/debug/metrics/prometheus" + +# The dirpath of the execution data directory on the client container +EXECUTION_DATA_DIRPATH_ON_CLIENT_CONTAINER = "/data/geth/execution-data" + + +def get_used_ports(discovery_port=DISCOVERY_PORT_NUM): + used_ports = { + RPC_PORT_ID: ethereum_package_shared_utils.new_port_spec( + RPC_PORT_NUM, + ethereum_package_shared_utils.TCP_PROTOCOL, + ethereum_package_shared_utils.HTTP_APPLICATION_PROTOCOL, + ), + WS_PORT_ID: ethereum_package_shared_utils.new_port_spec( + WS_PORT_NUM, ethereum_package_shared_utils.TCP_PROTOCOL + ), + TCP_DISCOVERY_PORT_ID: ethereum_package_shared_utils.new_port_spec( + discovery_port, ethereum_package_shared_utils.TCP_PROTOCOL + ), + UDP_DISCOVERY_PORT_ID: ethereum_package_shared_utils.new_port_spec( + discovery_port, ethereum_package_shared_utils.UDP_PROTOCOL + ), + ENGINE_RPC_PORT_ID: ethereum_package_shared_utils.new_port_spec( + ENGINE_RPC_PORT_NUM, + ethereum_package_shared_utils.TCP_PROTOCOL, + ), + METRICS_PORT_ID: ethereum_package_shared_utils.new_port_spec( + METRICS_PORT_NUM, ethereum_package_shared_utils.TCP_PROTOCOL + ), + } + return used_ports + + +ENTRYPOINT_ARGS = ["sh", "-c"] + +VERBOSITY_LEVELS = { + ethereum_package_constants.GLOBAL_LOG_LEVEL.error: "1", + ethereum_package_constants.GLOBAL_LOG_LEVEL.warn: "2", + ethereum_package_constants.GLOBAL_LOG_LEVEL.info: "3", + ethereum_package_constants.GLOBAL_LOG_LEVEL.debug: "4", + ethereum_package_constants.GLOBAL_LOG_LEVEL.trace: "5", +} + +BUILDER_IMAGE_STR = "builder" +SUAVE_ENABLED_GETH_IMAGE_STR = "suave" + + +def launch( + plan, + launcher, + service_name, + participant, + global_log_level, + persistent, + tolerations, + node_selectors, + existing_el_clients, + sequencer_enabled, + sequencer_context, +): + log_level = ethereum_package_input_parser.get_client_log_level_or_default( + participant.el_builder_log_level, global_log_level, VERBOSITY_LEVELS + ) + + cl_client_name = service_name.split("-")[4] + + config = get_config( + plan, + launcher, + service_name, + participant, + log_level, + persistent, + tolerations, + node_selectors, + existing_el_clients, + cl_client_name, + sequencer_enabled, + sequencer_context, + ) + + service = plan.add_service(service_name, config) + + enode, enr = ethereum_package_el_admin_node_info.get_enode_enr_for_node( + plan, service_name, RPC_PORT_ID + ) + + metrics_url = "{0}:{1}".format(service.ip_address, METRICS_PORT_NUM) + geth_metrics_info = ethereum_package_node_metrics.new_node_metrics_info( + service_name, METRICS_PATH, metrics_url + ) + + http_url = "http://{0}:{1}".format(service.ip_address, RPC_PORT_NUM) + + return ethereum_package_el_context.new_el_context( + client_name="op-geth", + enode=enode, + ip_addr=service.ip_address, + rpc_port_num=RPC_PORT_NUM, + ws_port_num=WS_PORT_NUM, + engine_rpc_port_num=ENGINE_RPC_PORT_NUM, + rpc_http_url=http_url, + enr=enr, + service_name=service_name, + el_metrics_info=[geth_metrics_info], + ) + + +def get_config( + plan, + launcher, + service_name, + participant, + log_level, + persistent, + tolerations, + node_selectors, + existing_el_clients, + cl_client_name, + sequencer_enabled, + sequencer_context, +): + init_datadir_cmd_str = "geth init --datadir={0} --state.scheme=hash {1}".format( + EXECUTION_DATA_DIRPATH_ON_CLIENT_CONTAINER, + ethereum_package_constants.GENESIS_DATA_MOUNTPOINT_ON_CLIENTS + + "/genesis-{0}.json".format(launcher.network_id), + ) + + discovery_port = DISCOVERY_PORT_NUM + used_ports = get_used_ports(discovery_port) + + cmd = [ + "geth", + "--networkid={0}".format(launcher.network_id), + # "--verbosity=" + verbosity_level, + "--datadir=" + EXECUTION_DATA_DIRPATH_ON_CLIENT_CONTAINER, + "--gcmode=archive", + "--state.scheme=hash", + "--http", + "--http.addr=0.0.0.0", + "--http.vhosts=*", + "--http.corsdomain=*", + "--http.api=admin,engine,net,eth,web3,debug,miner", + "--ws", + "--ws.addr=0.0.0.0", + "--ws.port={0}".format(WS_PORT_NUM), + "--ws.api=admin,engine,net,eth,web3,debug,miner", + "--ws.origins=*", + "--allow-insecure-unlock", + "--authrpc.port={0}".format(ENGINE_RPC_PORT_NUM), + "--authrpc.addr=0.0.0.0", + "--authrpc.vhosts=*", + "--authrpc.jwtsecret=" + ethereum_package_constants.JWT_MOUNT_PATH_ON_CONTAINER, + "--syncmode=full", + "--nat=extip:" + ethereum_package_constants.PRIVATE_IP_ADDRESS_PLACEHOLDER, + "--rpc.allow-unprotected-txs", + "--metrics", + "--metrics.addr=0.0.0.0", + "--metrics.port={0}".format(METRICS_PORT_NUM), + "--discovery.port={0}".format(discovery_port), + "--port={0}".format(discovery_port), + ] + + if not sequencer_enabled: + cmd.append("--rollup.sequencerhttp={0}".format(sequencer_context.rpc_http_url)) + + if len(existing_el_clients) > 0: + cmd.append( + "--bootnodes=" + + ",".join( + [ + ctx.enode + for ctx in existing_el_clients[ + : ethereum_package_constants.MAX_ENODE_ENTRIES + ] + ] + ) + ) + + cmd += participant.el_builder_extra_params + cmd_str = " ".join(cmd) + if launcher.network not in ethereum_package_constants.PUBLIC_NETWORKS: + subcommand_strs = [ + init_datadir_cmd_str, + cmd_str, + ] + command_str = " && ".join(subcommand_strs) + else: + command_str = cmd_str + + files = { + ethereum_package_constants.GENESIS_DATA_MOUNTPOINT_ON_CLIENTS: launcher.deployment_output, + ethereum_package_constants.JWT_MOUNTPOINT_ON_CLIENTS: launcher.jwt_file, + } + if persistent: + files[EXECUTION_DATA_DIRPATH_ON_CLIENT_CONTAINER] = Directory( + persistent_key="data-{0}".format(service_name), + size=int(participant.el_builder_volume_size) + if int(participant.el_builder_volume_size) > 0 + else constants.VOLUME_SIZE[launcher.network][ + constants.EL_TYPE.op_geth + "_volume_size" + ], + ) + env_vars = participant.el_builder_extra_env_vars + config_args = { + "image": participant.el_builder_image, + "ports": used_ports, + "cmd": [command_str], + "files": files, + "entrypoint": ENTRYPOINT_ARGS, + "private_ip_address_placeholder": ethereum_package_constants.PRIVATE_IP_ADDRESS_PLACEHOLDER, + "env_vars": env_vars, + "labels": ethereum_package_shared_utils.label_maker( + client=constants.EL_TYPE.op_geth, + client_type=constants.CLIENT_TYPES.el, + image=participant.el_builder_image[-constants.MAX_LABEL_LENGTH :], + connected_client=cl_client_name, + extra_labels=participant.el_builder_extra_labels, + ), + "tolerations": tolerations, + "node_selectors": node_selectors, + } + + if participant.el_builder_min_cpu > 0: + config_args["min_cpu"] = participant.el_builder_min_cpu + if participant.el_builder_max_cpu > 0: + config_args["max_cpu"] = participant.el_builder_max_cpu + if participant.el_builder_min_mem > 0: + config_args["min_memory"] = participant.el_builder_min_mem + if participant.el_builder_max_mem > 0: + config_args["max_memory"] = participant.el_builder_max_mem + return ServiceConfig(**config_args) + + +def new_op_geth_builder_launcher( + deployment_output, + jwt_file, + network, + network_id, +): + return struct( + deployment_output=deployment_output, + jwt_file=jwt_file, + network=network, + network_id=network_id, + ) diff --git a/src/el/op-reth/op_reth_builder_launcher.star b/src/el/op-reth/op_reth_builder_launcher.star new file mode 100644 index 0000000..3cd906f --- /dev/null +++ b/src/el/op-reth/op_reth_builder_launcher.star @@ -0,0 +1,266 @@ +ethereum_package_shared_utils = import_module( + "github.com/ethpandaops/ethereum-package/src/shared_utils/shared_utils.star" +) + +ethereum_package_el_context = import_module( + "github.com/ethpandaops/ethereum-package/src/el/el_context.star" +) +ethereum_package_el_admin_node_info = import_module( + "github.com/ethpandaops/ethereum-package/src/el/el_admin_node_info.star" +) + +ethereum_package_node_metrics = import_module( + "github.com/ethpandaops/ethereum-package/src/node_metrics_info.star" +) +ethereum_package_constants = import_module( + "github.com/ethpandaops/ethereum-package/src/package_io/constants.star" +) + +ethereum_package_input_parser = import_module( + "github.com/ethpandaops/ethereum-package/src/package_io/input_parser.star" +) + +constants = import_module("../../package_io/constants.star") + +RPC_PORT_NUM = 8545 +WS_PORT_NUM = 8546 +DISCOVERY_PORT_NUM = 30303 +ENGINE_RPC_PORT_NUM = 9551 +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" + +# The dirpath of the execution data directory on the client container +EXECUTION_DATA_DIRPATH_ON_CLIENT_CONTAINER = "/data/op-reth/execution-data" + + +def get_used_ports(discovery_port=DISCOVERY_PORT_NUM): + used_ports = { + RPC_PORT_ID: ethereum_package_shared_utils.new_port_spec( + RPC_PORT_NUM, + ethereum_package_shared_utils.TCP_PROTOCOL, + ethereum_package_shared_utils.HTTP_APPLICATION_PROTOCOL, + ), + WS_PORT_ID: ethereum_package_shared_utils.new_port_spec( + WS_PORT_NUM, ethereum_package_shared_utils.TCP_PROTOCOL + ), + TCP_DISCOVERY_PORT_ID: ethereum_package_shared_utils.new_port_spec( + discovery_port, ethereum_package_shared_utils.TCP_PROTOCOL + ), + UDP_DISCOVERY_PORT_ID: ethereum_package_shared_utils.new_port_spec( + discovery_port, ethereum_package_shared_utils.UDP_PROTOCOL + ), + ENGINE_RPC_PORT_ID: ethereum_package_shared_utils.new_port_spec( + ENGINE_RPC_PORT_NUM, ethereum_package_shared_utils.TCP_PROTOCOL + ), + METRICS_PORT_ID: ethereum_package_shared_utils.new_port_spec( + METRICS_PORT_NUM, ethereum_package_shared_utils.TCP_PROTOCOL + ), + } + return used_ports + + +VERBOSITY_LEVELS = { + ethereum_package_constants.GLOBAL_LOG_LEVEL.error: "v", + ethereum_package_constants.GLOBAL_LOG_LEVEL.warn: "vv", + ethereum_package_constants.GLOBAL_LOG_LEVEL.info: "vvv", + ethereum_package_constants.GLOBAL_LOG_LEVEL.debug: "vvvv", + ethereum_package_constants.GLOBAL_LOG_LEVEL.trace: "vvvvv", +} + + +def launch( + plan, + launcher, + service_name, + participant, + global_log_level, + persistent, + tolerations, + node_selectors, + existing_el_clients, + sequencer_enabled, + sequencer_context, +): + log_level = ethereum_package_input_parser.get_client_log_level_or_default( + participant.el_builder_log_level, global_log_level, VERBOSITY_LEVELS + ) + + cl_client_name = service_name.split("-")[4] + + config = get_config( + plan, + launcher, + service_name, + participant, + log_level, + persistent, + tolerations, + node_selectors, + existing_el_clients, + cl_client_name, + sequencer_enabled, + sequencer_context, + ) + + service = plan.add_service(service_name, config) + + enode = ethereum_package_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) + op_reth_metrics_info = ethereum_package_node_metrics.new_node_metrics_info( + service_name, METRICS_PATH, metric_url + ) + + http_url = "http://{0}:{1}".format(service.ip_address, RPC_PORT_NUM) + + return ethereum_package_el_context.new_el_context( + client_name="reth", + enode=enode, + ip_addr=service.ip_address, + rpc_port_num=RPC_PORT_NUM, + ws_port_num=WS_PORT_NUM, + engine_rpc_port_num=ENGINE_RPC_PORT_NUM, + rpc_http_url=http_url, + service_name=service_name, + el_metrics_info=[op_reth_metrics_info], + ) + + +def get_config( + plan, + launcher, + service_name, + participant, + log_level, + persistent, + tolerations, + node_selectors, + existing_el_clients, + cl_client_name, + sequencer_enabled, + sequencer_context, +): + public_ports = {} + discovery_port = DISCOVERY_PORT_NUM + used_ports = get_used_ports(discovery_port) + + cmd = [ + "node", + "--datadir=" + EXECUTION_DATA_DIRPATH_ON_CLIENT_CONTAINER, + "--chain={0}".format( + launcher.network + if launcher.network in ethereum_package_constants.PUBLIC_NETWORKS + else ethereum_package_constants.GENESIS_CONFIG_MOUNT_PATH_ON_CONTAINER + + "/genesis-{0}.json".format(launcher.network_id) + ), + "--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:" + ethereum_package_constants.PRIVATE_IP_ADDRESS_PLACEHOLDER, + "--authrpc.port={0}".format(ENGINE_RPC_PORT_NUM), + "--authrpc.jwtsecret=" + ethereum_package_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), + "--port={0}".format(discovery_port), + "--rpc.eth-proof-window=302400", + ] + + if not sequencer_enabled: + cmd.append("--rollup.sequencer-http={0}".format(sequencer_context.rpc_http_url)) + + if len(existing_el_clients) > 0: + cmd.append( + "--bootnodes=" + + ",".join( + [ + ctx.enode + for ctx in existing_el_clients[ + : ethereum_package_constants.MAX_ENODE_ENTRIES + ] + ] + ) + ) + + files = { + ethereum_package_constants.GENESIS_DATA_MOUNTPOINT_ON_CLIENTS: launcher.deployment_output, + ethereum_package_constants.JWT_MOUNTPOINT_ON_CLIENTS: launcher.jwt_file, + } + if persistent: + files[EXECUTION_DATA_DIRPATH_ON_CLIENT_CONTAINER] = Directory( + persistent_key="data-{0}".format(service_name), + size=int(participant.el_builder_volume_size) + if int(participant.el_builder_volume_size) > 0 + else constants.VOLUME_SIZE[launcher.network][ + constants.EL_TYPE.op_reth + "_volume_size" + ], + ) + + cmd += participant.el_builder_extra_params + env_vars = participant.el_builder_extra_env_vars + config_args = { + "image": participant.el_builder_image, + "ports": used_ports, + "cmd": cmd, + "files": files, + "private_ip_address_placeholder": ethereum_package_constants.PRIVATE_IP_ADDRESS_PLACEHOLDER, + "env_vars": env_vars, + "labels": ethereum_package_shared_utils.label_maker( + client=constants.EL_TYPE.op_reth, + client_type=constants.CLIENT_TYPES.el, + image=participant.el_builder_image[-constants.MAX_LABEL_LENGTH :], + connected_client=cl_client_name, + extra_labels=participant.el_builder_extra_labels, + ), + "tolerations": tolerations, + "node_selectors": node_selectors, + } + + if participant.el_min_cpu > 0: + config_args["min_cpu"] = participant.el_builder_min_cpu + if participant.el_builder_max_cpu > 0: + config_args["max_cpu"] = participant.el_builder_max_cpu + if participant.el_builder_min_mem > 0: + config_args["min_memory"] = participant.el_builder_min_mem + if participant.el_builder_max_mem > 0: + config_args["max_memory"] = participant.el_builder_max_mem + return ServiceConfig(**config_args) + + +def new_op_reth_builder_launcher( + deployment_output, + jwt_file, + network, + network_id, +): + return struct( + deployment_output=deployment_output, + jwt_file=jwt_file, + network=network, + network_id=network_id, + ) diff --git a/src/el/op-reth/op_reth_launcher.star b/src/el/op-reth/op_reth_launcher.star index 7021192..386d7d8 100644 --- a/src/el/op-reth/op_reth_launcher.star +++ b/src/el/op-reth/op_reth_launcher.star @@ -176,11 +176,11 @@ def get_config( "--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,miner", + "--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,miner", + "--ws.api=net,eth", "--ws.origins=*", "--nat=extip:" + ethereum_package_constants.PRIVATE_IP_ADDRESS_PLACEHOLDER, "--authrpc.port={0}".format(ENGINE_RPC_PORT_NUM), diff --git a/src/el_cl_launcher.star b/src/el_cl_launcher.star index 36588f3..3cde474 100644 --- a/src/el_cl_launcher.star +++ b/src/el_cl_launcher.star @@ -20,7 +20,9 @@ hildr = import_module("./cl/hildr/hildr_launcher.star") # MEV rollup_boost = import_module("./mev/rollup-boost/rollup_boost_launcher.star") - +op_geth_builder = import_module("./el/op-geth/op_geth_builder_launcher.star") +op_reth_builder = import_module("./el/op-reth/op_reth_builder_launcher.star") +op_node_builder = import_module("./cl/op-node/op_node_builder_launcher.star") def launch( plan, @@ -92,6 +94,27 @@ def launch( }, } + el_builder_launchers = { + "op-geth": { + "launcher": op_geth_builder.new_op_geth_builder_launcher( + deployment_output, + jwt_file, + network_params.network, + network_params.network_id, + ), + "launch_method": op_geth_builder.launch, + }, + "op-reth": { + "launcher": op_reth_builder.new_op_reth_builder_launcher( + deployment_output, + jwt_file, + network_params.network, + network_params.network_id, + ), + "launch_method": op_reth_builder.launch, + }, + } + cl_launchers = { "op-node": { "launcher": op_node.new_op_node_launcher( @@ -107,6 +130,15 @@ def launch( }, } + cl_builder_launchers = { + "op-node": { + "launcher": op_node_builder.new_op_node_builder_launcher( + deployment_output, jwt_file, network_params + ), + "launch_method": op_node_builder.launch, + }, + } + sidecar_launchers = { "rollup-boost": { "launcher": rollup_boost.new_rollup_boost_launcher( @@ -156,17 +188,17 @@ def launch( ) ) - if el_builder_type not in el_launchers: + if el_builder_type not in el_builder_launchers: fail( "Unsupported launcher '{0}', need one of '{1}'".format( - el_builder_type, ",".join(el_launchers.keys()) + el_builder_type, ",".join(el_builder_launchers.keys()) ) ) - if cl_builder_type not in cl_launchers: + if cl_builder_type not in cl_builder_launchers: fail( "Unsupported launcher '{0}', need one of '{1}'".format( - cl_builder_type, ",".join(cl_launchers.keys()) + cl_builder_type, ",".join(cl_builder_launchers.keys()) ) ) @@ -181,13 +213,13 @@ def launch( ) el_builder_launcher, el_builder_launch_method = ( - el_launchers[el_builder_type]["launcher"], - el_launchers[el_builder_type]["launch_method"], + el_builder_launchers[el_builder_type]["launcher"], + el_builder_launchers[el_builder_type]["launch_method"], ) cl_builder_launcher, cl_builder_launch_method = ( - cl_launchers[cl_builder_type]["launcher"], - cl_launchers[cl_builder_type]["launch_method"], + cl_builder_launchers[cl_builder_type]["launcher"], + cl_builder_launchers[cl_builder_type]["launch_method"], ) sidecar_launcher, sidecar_launch_method = ( @@ -232,8 +264,8 @@ def launch( interop_params, ) - if rollup_boost_enabled: - plan.print("Rollup boost enabled") + if rollup_boost_enabled and sequencer_enabled: + plan.print("Starting rollup boost") if mev_params.builder_host == "" or mev_params.builder_port == "": el_builder_context = el_builder_launch_method( @@ -254,6 +286,12 @@ def launch( el_builder_context = struct( ip_addr=mev_params.builder_host, engine_rpc_port_num=mev_params.builder_port, + rpc_port_num=mev_params.builder_port, + rpc_http_url="http://{0}:{1}".format( + mev_params.builder_host, mev_params.builder_port + ), + + client_name="external-builder", ) rollup_boost_image = ( @@ -273,7 +311,6 @@ def launch( ) all_el_contexts.append(el_builder_context) - all_el_contexts.append(sidecar_context) else: sidecar_context = None @@ -286,7 +323,7 @@ def launch( persistent, cl_tolerations, node_selectors, - sidecar_context if rollup_boost_enabled else el_context, + sidecar_context if rollup_boost_enabled and sequencer_enabled else el_context, all_cl_contexts, l1_config_env_vars, sequencer_enabled, @@ -298,7 +335,7 @@ def launch( all_el_contexts.append(el_context) all_cl_contexts.append(cl_context) - if rollup_boost_enabled: + if rollup_boost_enabled and sequencer_enabled: cl_builder_context = cl_builder_launch_method( plan, cl_builder_launcher, diff --git a/src/package_io/input_parser.star b/src/package_io/input_parser.star index 4a09d05..c7d148f 100644 --- a/src/package_io/input_parser.star +++ b/src/package_io/input_parser.star @@ -102,8 +102,28 @@ def input_parser(plan, input_args): cl_max_mem=participant["cl_max_mem"], el_builder_type=participant["el_builder_type"], el_builder_image=participant["el_builder_image"], + el_builder_log_level=participant["el_builder_log_level"], + el_builder_extra_env_vars=participant["el_builder_extra_env_vars"], + el_builder_extra_labels=participant["el_builder_extra_labels"], + el_builder_extra_params=participant["el_builder_extra_params"], + el_builder_tolerations=participant["el_builder_tolerations"], + el_builder_volume_size=participant["el_builder_volume_size"], + el_builder_min_cpu=participant["el_builder_min_cpu"], + el_builder_max_cpu=participant["el_builder_max_cpu"], + el_builder_min_mem=participant["el_builder_min_mem"], + el_builder_max_mem=participant["el_builder_max_mem"], cl_builder_type=participant["cl_builder_type"], cl_builder_image=participant["cl_builder_image"], + cl_builder_log_level=participant["cl_builder_log_level"], + cl_builder_extra_env_vars=participant["cl_builder_extra_env_vars"], + cl_builder_extra_labels=participant["cl_builder_extra_labels"], + cl_builder_extra_params=participant["cl_builder_extra_params"], + cl_builder_tolerations=participant["cl_builder_tolerations"], + cl_builder_volume_size=participant["cl_builder_volume_size"], + cl_builder_min_cpu=participant["cl_builder_min_cpu"], + cl_builder_max_cpu=participant["cl_builder_max_cpu"], + cl_builder_min_mem=participant["cl_builder_min_mem"], + cl_builder_max_mem=participant["cl_builder_max_mem"], node_selectors=participant["node_selectors"], tolerations=participant["tolerations"], count=participant["count"], @@ -415,8 +435,28 @@ def default_participant(): "cl_max_mem": 0, "el_builder_type": "op-geth", "el_builder_image": "", + "el_builder_log_level": "", + "el_builder_extra_env_vars": {}, + "el_builder_extra_labels": {}, + "el_builder_extra_params": [], + "el_builder_tolerations": [], + "el_builder_volume_size": 0, + "el_builder_min_cpu": 0, + "el_builder_max_cpu": 0, + "el_builder_min_mem": 0, + "el_builder_max_mem": 0, "cl_builder_type": "op-node", "cl_builder_image": "", + "cl_builder_log_level": "", + "cl_builder_extra_env_vars": {}, + "cl_builder_extra_labels": {}, + "cl_builder_extra_params": [], + "cl_builder_tolerations": [], + "cl_builder_volume_size": 0, + "cl_builder_min_cpu": 0, + "cl_builder_max_cpu": 0, + "cl_builder_min_mem": 0, + "cl_builder_max_mem": 0, "node_selectors": {}, "tolerations": [], "count": 1,