diff --git a/.github/tests/op-besu.yaml b/.github/tests/op-besu.yaml new file mode 100644 index 0000000..da0d16c --- /dev/null +++ b/.github/tests/op-besu.yaml @@ -0,0 +1,4 @@ +optimism_package: + participants: + - el_type: op-besu + cl_type: op-node diff --git a/README.md b/README.md index bf0f8cc..cec1c20 100644 --- a/README.md +++ b/README.md @@ -57,6 +57,7 @@ optimism_package: # op-reth # op-erigon # op-nethermind + # op-besu - el_type: geth # The Docker image that should be used for the EL client; leave blank to use the default for the client type @@ -65,6 +66,7 @@ optimism_package: # - op-reth: parithoshj/op-reth:latest # - op-erigon: testinprod/op-erigon:latest # - op-nethermind: nethermindeth/nethermind:op-c482d56 + # - op-besu: ghcr.io/optimism-java/op-besu:latest el_image: "" # CL(Consensus Layer) Specific flags diff --git a/network_params.yaml b/network_params.yaml index 8f88ec8..90c67b8 100644 --- a/network_params.yaml +++ b/network_params.yaml @@ -4,5 +4,6 @@ optimism_package: - el_type: op-reth - el_type: op-erigon - el_type: op-nethermind + - el_type: op-besu additional_services: - blockscout diff --git a/src/el/op-besu/op_besu_launcher.star b/src/el/op-besu/op_besu_launcher.star new file mode 100644 index 0000000..f51f57b --- /dev/null +++ b/src/el/op-besu/op_besu_launcher.star @@ -0,0 +1,229 @@ +shared_utils = import_module( + "github.com/ethpandaops/ethereum-package/src/shared_utils/shared_utils.star" +) + +el_context = import_module( + "github.com/ethpandaops/ethereum-package/src/el/el_context.star" +) +el_admin_node_info = import_module( + "github.com/ethpandaops/ethereum-package/src/el/el_admin_node_info.star" +) + +node_metrics = import_module( + "github.com/ethpandaops/ethereum-package/src/node_metrics_info.star" +) +constants = import_module( + "github.com/ethpandaops/ethereum-package/src/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/besu/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", +} + +BUILDER_IMAGE_STR = "builder" +SUAVE_ENABLED_GETH_IMAGE_STR = "suave" + + +def launch( + plan, + launcher, + service_name, + image, + existing_el_clients, + sequencer_enabled, + sequencer_context, +): + network_name = shared_utils.get_network_name(launcher.network) + + config = get_config( + plan, + launcher.el_cl_genesis_data, + launcher.jwt_file, + launcher.network, + launcher.network_id, + image, + service_name, + existing_el_clients, + sequencer_enabled, + sequencer_context, + ) + + service = plan.add_service(service_name, config) + + enode = el_admin_node_info.get_enode_for_node(plan, service_name, RPC_PORT_ID) + + metrics_url = "{0}:{1}".format(service.ip_address, METRICS_PORT_NUM) + besu_metrics_info = 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 el_context.new_el_context( + "op-besu", + "", # besu has no ENR + enode, + service.ip_address, + RPC_PORT_NUM, + WS_PORT_NUM, + ENGINE_RPC_PORT_NUM, + http_url, + service_name, + [besu_metrics_info], + ) + + +def get_config( + plan, + el_cl_genesis_data, + jwt_file, + network, + network_id, + image, + service_name, + existing_el_clients, + sequencer_enabled, + sequencer_context, +): + discovery_port = DISCOVERY_PORT_NUM + used_ports = get_used_ports(discovery_port) + + cmd = [ + "besu", + "--genesis-file=" + + constants.GENESIS_CONFIG_MOUNT_PATH_ON_CONTAINER + + "/genesis.json", + "--network-id={0}".format(network_id), + # "--logging=" + log_level, + "--data-path=" + EXECUTION_DATA_DIRPATH_ON_CLIENT_CONTAINER, + "--host-allowlist=*", + "--rpc-http-enabled=true", + "--rpc-http-host=0.0.0.0", + "--rpc-http-port={0}".format(RPC_PORT_NUM), + "--rpc-http-api=ADMIN,CLIQUE,ETH,NET,DEBUG,TXPOOL,ENGINE,TRACE,WEB3", + "--rpc-http-cors-origins=*", + "--rpc-http-max-active-connections=300", + "--rpc-ws-enabled=true", + "--rpc-ws-host=0.0.0.0", + "--rpc-ws-port={0}".format(WS_PORT_NUM), + "--rpc-ws-api=ADMIN,CLIQUE,ETH,NET,DEBUG,TXPOOL,ENGINE,TRACE,WEB3", + "--p2p-enabled=true", + "--p2p-host=" + constants.PRIVATE_IP_ADDRESS_PLACEHOLDER, + "--p2p-port={0}".format(discovery_port), + "--engine-rpc-enabled=true", + "--engine-jwt-secret=" + constants.JWT_MOUNT_PATH_ON_CONTAINER, + "--engine-host-allowlist=*", + "--engine-rpc-port={0}".format(ENGINE_RPC_PORT_NUM), + "--sync-mode=FULL", + "--metrics-enabled=true", + "--metrics-host=0.0.0.0", + "--metrics-port={0}".format(METRICS_PORT_NUM), + "--bonsai-limit-trie-logs-enabled=false", + "--version-compatibility-protection=false", + ] + + # if not sequencer_enabled: + # cmd.append( + # "--rollup.sequencerhttp={0}".format(sequencer_context.beacon_http_url) + # ) + + if len(existing_el_clients) > 0: + cmd.append( + "--bootnodes=" + + ",".join( + [ + ctx.enode + for ctx in existing_el_clients[: constants.MAX_ENODE_ENTRIES] + ] + ) + ) + + cmd_str = " ".join(cmd) + + files = { + constants.GENESIS_DATA_MOUNTPOINT_ON_CLIENTS: el_cl_genesis_data, + constants.JWT_MOUNTPOINT_ON_CLIENTS: jwt_file, + } + + return ServiceConfig( + image=image, + ports=used_ports, + cmd=[cmd_str], + files=files, + entrypoint=ENTRYPOINT_ARGS, + private_ip_address_placeholder=constants.PRIVATE_IP_ADDRESS_PLACEHOLDER, + user=User(uid=0, gid=0), + ) + + +def new_op_besu_launcher( + el_cl_genesis_data, + jwt_file, + network, + network_id, +): + return struct( + el_cl_genesis_data=el_cl_genesis_data, + jwt_file=jwt_file, + network=network, + network_id=network_id, + ) diff --git a/src/el_cl_launcher.star b/src/el_cl_launcher.star index d04f13e..88ede09 100644 --- a/src/el_cl_launcher.star +++ b/src/el_cl_launcher.star @@ -9,6 +9,7 @@ op_geth = import_module("./el/op-geth/op_geth_launcher.star") op_reth = import_module("./el/op-reth/op_reth_launcher.star") op_erigon = import_module("./el/op-erigon/op_erigon_launcher.star") op_nethermind = import_module("./el/op-nethermind/op_nethermind_launcher.star") +op_besu = import_module("./el/op-besu/op_besu_launcher.star") # CL op_node = import_module("./cl/op-node/op_node_launcher.star") hildr = import_module("./cl/hildr/hildr_launcher.star") @@ -62,6 +63,15 @@ def launch( ), "launch_method": op_nethermind.launch, }, + "op-besu": { + "launcher": op_besu.new_op_besu_launcher( + el_cl_data, + jwt_file, + network_params.network, + network_params.network_id, + ), + "launch_method": op_besu.launch, + }, } cl_launchers = { diff --git a/src/package_io/input_parser.star b/src/package_io/input_parser.star index 90d9e52..c273ad1 100644 --- a/src/package_io/input_parser.star +++ b/src/package_io/input_parser.star @@ -9,6 +9,7 @@ DEFAULT_EL_IMAGES = { "op-reth": "ghcr.io/paradigmxyz/op-reth:latest", "op-erigon": "testinprod/op-erigon:latest", "op-nethermind": "nethermindeth/nethermind:op-c482d56", + "op-besu": "ghcr.io/optimism-java/op-besu:latest", } DEFAULT_CL_IMAGES = {