diff --git a/main.star b/main.star index 6f26999a..303f1278 100644 --- a/main.star +++ b/main.star @@ -2,7 +2,7 @@ ethereum_package = import_module("github.com/ethpandaops/ethereum-package/main.s contract_deployer = import_module("./src/contracts/contract_deployer.star") l2_launcher = import_module("./src/l2.star") superchain_launcher = import_module("./src/superchain/launcher.star") -op_supervisor_launcher = import_module("./src/supervisor/op-supervisor/launcher.star") +supervisor_launcher = import_module("./src/supervisor/launcher.star") op_challenger_launcher = import_module("./src/challenger/op-challenger/launcher.star") faucet = import_module("./src/faucet/op-faucet/op_faucet_launcher.star") @@ -150,7 +150,7 @@ def run(plan, args={}): ) for supervisor_params in optimism_args.supervisors: - op_supervisor_launcher.launch( + supervisor_launcher.launch( plan=plan, params=supervisor_params, l1_config_env_vars=l1_config_env_vars, diff --git a/src/observability/observability.star b/src/observability/observability.star index d684716f..a70374ee 100644 --- a/src/observability/observability.star +++ b/src/observability/observability.star @@ -46,7 +46,8 @@ def expose_metrics_port(ports, port_id=METRICS_PORT_ID, port_num=METRICS_PORT_NU ) -# configures the CLI flags and ports for a service using the standard op-service setup +# configures the CLI flags and ports for a service using the standard op-service setup. +# Note: kona services use identical metrics args. def configure_op_service_metrics(cmd, ports): cmd += [ "--metrics.enabled", @@ -85,6 +86,7 @@ def new_metrics_job( } +# Note: kona services use identical metrics registration. def register_op_service_metrics_job(helper, service, network_name=None): register_service_metrics_job( helper, diff --git a/src/package_io/registry.star b/src/package_io/registry.star index 6e95953a..b585d2fa 100644 --- a/src/package_io/registry.star +++ b/src/package_io/registry.star @@ -12,9 +12,11 @@ OP_NODE = "op-node" KONA_NODE = "kona-node" HILDR = "hildr" +OP_SUPERVISOR = "op-supervisor" +KONA_SUPERVISOR = "kona-supervisor" + OP_BATCHER = "op-batcher" OP_CHALLENGER = "op-challenger" -OP_SUPERVISOR = "op-supervisor" OP_PROPOSER = "op-proposer" OP_CONDUCTOR = "op-conductor" OP_DEPLOYER = "op-deployer" @@ -50,8 +52,10 @@ _DEFAULT_IMAGES = { OP_BATCHER: "us-docker.pkg.dev/oplabs-tools-artifacts/images/op-batcher:develop", # Challenger OP_CHALLENGER: "us-docker.pkg.dev/oplabs-tools-artifacts/images/op-challenger:develop", - # Supervisor + # op-supervisor OP_SUPERVISOR: "us-docker.pkg.dev/oplabs-tools-artifacts/images/op-supervisor:develop", + # kona-supervisor + KONA_SUPERVISOR: "ghcr.io/op-rs/kona/kona-supervisor:latest", # Proposer OP_PROPOSER: "us-docker.pkg.dev/oplabs-tools-artifacts/images/op-proposer:develop", # Conductor diff --git a/src/supervisor/input_parser.star b/src/supervisor/input_parser.star index 7ccfbccd..3696425f 100644 --- a/src/supervisor/input_parser.star +++ b/src/supervisor/input_parser.star @@ -4,12 +4,18 @@ _id = import_module("/src/util/id.star") _registry = import_module("/src/package_io/registry.star") _DEFAULT_ARGS = { + "type": "op-supervisor", "enabled": True, "superchain": None, "image": None, "extra_params": [], } +_IMAGE_IDS = { + "op-supervisor": _registry.OP_SUPERVISOR, + "kona-supervisor": _registry.KONA_SUPERVISOR, +} + def parse(args, superchains, registry): return _filter.remove_none( @@ -58,18 +64,19 @@ def _parse_instance(supervisor_args, supervisor_name, superchains, registry): # in the parsed config, but this is a tradeoff that we are willing to make supervisor_params["superchain"] = superchain + # And default the image to the one in the registry + supervisor_params["image"] = supervisor_params["image"] or _default_image( + supervisor_params["type"], registry + ) + # We add name & service name supervisor_params["name"] = supervisor_name - supervisor_params["service_name"] = "op-supervisor-{}-{}".format( + supervisor_params["service_name"] = "{}-{}-{}".format( + supervisor_params["type"], supervisor_name, superchain_name, ) - # And default the image to the one in the registry - supervisor_params["image"] = supervisor_params["image"] or registry.get( - _registry.OP_SUPERVISOR - ) - # We'll also define the ports that this supervisor will expose # # This is so that we can reference them before the service is created @@ -80,3 +87,10 @@ def _parse_instance(supervisor_args, supervisor_name, superchains, registry): } return struct(**supervisor_params) + + +def _default_image(participant_type, registry): + if participant_type in _IMAGE_IDS: + return registry.get(_IMAGE_IDS[participant_type]) + else: + fail("Invalid supervisor type: {}".format(participant_type)) diff --git a/src/supervisor/kona-supervisor/launcher.star b/src/supervisor/kona-supervisor/launcher.star new file mode 100644 index 00000000..020a0a03 --- /dev/null +++ b/src/supervisor/kona-supervisor/launcher.star @@ -0,0 +1,101 @@ +_file = import_module("/src/util/file.star") +_net = import_module("/src/util/net.star") + +_ethereum_package_constants = import_module( + "github.com/ethpandaops/ethereum-package/src/package_io/constants.star" +) + +_observability = import_module("/src/observability/observability.star") +_prometheus = import_module("/src/observability/prometheus/prometheus_launcher.star") + + +DATA_DIR = "/etc/kona-supervisor" +DEPENDENCY_SET_FILE_NAME = "dependency_set.json" + + +def launch( + plan, + params, + l1_config_env_vars, + l2s, + jwt_file, + deployment_output, + observability_helper, +): + supervisor_l2s = [ + l2 for l2 in l2s if l2.network_id in params.superchain.participants + ] + + config = _get_config( + plan=plan, + params=params, + l1_config_env_vars=l1_config_env_vars, + l2s=supervisor_l2s, + jwt_file=jwt_file, + deployment_output=deployment_output, + observability_helper=observability_helper, + ) + + service = plan.add_service(params.service_name, config) + + _observability.register_op_service_metrics_job( + observability_helper, + service, + ) + + return struct(service=service, l2s=supervisor_l2s) + + +def _get_config( + plan, + params, + l1_config_env_vars, + l2s, + jwt_file, + deployment_output, + observability_helper, +): + ports = _net.ports_to_port_specs(params.ports) + datadir = params.superchain.dependency_set.name + + cmd = ["kona-supervisor"] + params.extra_params + + # apply customizations + + if observability_helper.enabled: + _observability.configure_op_service_metrics(cmd, ports) + + return ServiceConfig( + image=params.image, + ports=ports, + files={ + DATA_DIR: params.superchain.dependency_set.name, + _ethereum_package_constants.GENESIS_DATA_MOUNTPOINT_ON_CLIENTS: deployment_output, + _ethereum_package_constants.JWT_MOUNTPOINT_ON_CLIENTS: jwt_file, + }, + env_vars={ + "DATADIR": "/db", + "DEPENDENCY_SET": "{0}/{1}".format( + DATA_DIR, params.superchain.dependency_set.path + ), + "ROLLUP_CONFIG_PATHS": _ethereum_package_constants.GENESIS_DATA_MOUNTPOINT_ON_CLIENTS + + "/rollup-*.json", + "L1_RPC": l1_config_env_vars["L1_RPC_URL"], + "L2_CONSENSUS_NODES": ",".join( + [ + _net.service_url( + participant.cl_context.ip_addr, + params.superchain.ports[_net.INTEROP_RPC_PORT_NAME], + ) + for l2 in l2s + for participant in l2.participants + ] + ), + "L2_CONSENSUS_JWT_SECRET": _ethereum_package_constants.JWT_MOUNT_PATH_ON_CONTAINER, + "RPC_ADDR": "0.0.0.0", + "RPC_PORT": str(params.ports[_net.RPC_PORT_NAME].number), + "RPC_ENABLE_ADMIN": "true", + }, + cmd=cmd, + private_ip_address_placeholder=_ethereum_package_constants.PRIVATE_IP_ADDRESS_PLACEHOLDER, + ) diff --git a/src/supervisor/launcher.star b/src/supervisor/launcher.star new file mode 100644 index 00000000..86996121 --- /dev/null +++ b/src/supervisor/launcher.star @@ -0,0 +1,37 @@ +op_supervisor_launcher = import_module("./op-supervisor/launcher.star") +kona_supervisor_launcher = import_module("./kona-supervisor/launcher.star") + + +def launch( + plan, + params, + l1_config_env_vars, + l2s, + jwt_file, + deployment_output, + observability_helper, +): + supervisor_type = params.type + + if supervisor_type == "op-supervisor": + return op_supervisor_launcher.launch( + plan=plan, + params=params, + l1_config_env_vars=l1_config_env_vars, + l2s=l2s, + jwt_file=jwt_file, + deployment_output=deployment_output, + observability_helper=observability_helper, + ) + elif supervisor_type == "kona-supervisor": + return kona_supervisor_launcher.launch( + plan=plan, + params=params, + l1_config_env_vars=l1_config_env_vars, + l2s=l2s, + jwt_file=jwt_file, + deployment_output=deployment_output, + observability_helper=observability_helper, + ) + else: + fail("Unsupported supervisor implementation {}".format(supervisor_type)) diff --git a/test/supervisor/input_parser_test.star b/test/supervisor/input_parser_test.star index 078b8058..d41398db 100644 --- a/test/supervisor/input_parser_test.star +++ b/test/supervisor/input_parser_test.star @@ -95,6 +95,7 @@ def test_supervisor_input_parser_default_args(plan): }, service_name="op-supervisor-supervisor0-superchain0", superchain=_superchains[0], + type="op-supervisor", ), ], ) diff --git a/test/supervisor/kona-supervisor.star/launcher_test.star b/test/supervisor/kona-supervisor.star/launcher_test.star new file mode 100644 index 00000000..ee5c553d --- /dev/null +++ b/test/supervisor/kona-supervisor.star/launcher_test.star @@ -0,0 +1,86 @@ +_kona_supervisor_launcher = import_module( + "/src/supervisor/kona-supervisor/launcher.star" +) + +_input_parser = import_module("/src/package_io/input_parser.star") +_observability = import_module("/src/observability/observability.star") +_ethereum_package_constants = import_module( + "github.com/ethpandaops/ethereum-package/src/package_io/constants.star" +) + + +def test_interop_kona_supervisor_ports(plan): + parsed_input_args = _input_parser.input_parser( + plan, + { + "chains": [ + { + "network_params": { + "network_id": 1000, + }, + "participants": [ + { + "el_type": "op-reth", + "el_image": "op-reth:latest", + "cl_type": "op-node", + "cl_image": "op-node:latest", + } + ], + } + ], + "superchains": {"superchain0": {}}, + "supervisors": { + "supervisor0": { + "superchain": "superchain0", + "type": "kona-supervisor", + } + }, + }, + ) + + # Just to make sure + expect.ne(parsed_input_args.supervisors, None) + + supervisor_params = parsed_input_args.supervisors[0] + expect.ne(supervisor_params, None) + + observability_helper = _observability.make_helper(parsed_input_args.observability) + + result = _kona_supervisor_launcher.launch( + plan=plan, + l1_config_env_vars={"L1_RPC_URL": "http://l1.rpc"}, + l2s=[], + jwt_file="/jwt_file", + params=supervisor_params, + deployment_output="/deployment_output", + observability_helper=observability_helper, + ) + + service = plan.get_service(supervisor_params.service_name) + expect.ne(service, None) + + expect.eq(service.ports["rpc"].number, 8545) + expect.eq(service.ports["rpc"].application_protocol, "http") + + service_config = kurtosistest.get_service_config(supervisor_params.service_name) + expect.ne(service_config, None) + + expect.eq(service_config.env_vars["RPC_ADDR"], "0.0.0.0") + expect.eq(service_config.env_vars["RPC_PORT"], "8545") + + expect.eq( + supervisor_params.superchain.dependency_set.name, + "superchain-depset-superchain0", + ) + expect.eq( + supervisor_params.superchain.dependency_set.path, + "superchain-depset-superchain0.json", + ) + expect.eq( + service_config.env_vars["DEPENDENCY_SET"], + "/etc/kona-supervisor/superchain-depset-superchain0.json", + ) + expect.eq( + service_config.files["/etc/kona-supervisor"].artifact_names, + ["superchain-depset-superchain0"], + )