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(rbuilder): Add op-rbuilder as exectuion layer builder option #169

Draft
wants to merge 10 commits into
base: main
Choose a base branch
from
8 changes: 7 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -273,14 +273,20 @@ optimism_package:
# Valid values are:
# op-geth
# op-reth
# op-rbuilder
el_builder_type: ""

# The Docker image that should be used for the builder EL client; leave blank to use the default for the client type
# Defaults by client:
# - op-geth: us-docker.pkg.dev/oplabs-tools-artifacts/images/op-geth:latest
# - op-reth: parithoshj/op-reth:latest
# - op-rbuilder: ghcr.io/flashbots/op-rbuilder:latest
el_builder_image: ""

# Builder secret key used by op-rbuilder to sign transactions
# Defaults to None - not used
el_builder_key: ""

# The type of builder CL client that should be started
# Valid values are:
# op-node
Expand Down Expand Up @@ -609,7 +615,7 @@ To use rollup boost, you can add `rollup-boost` as an additional service and con
optimism_package:
chains:
- participants:
- el_builder_type: op-geth
- el_builder_type: op-rbuilder
cl_builder_type: op-node
mev_params:
rollup_boost_image: "flashbots/rollup-boost:latest"
Expand Down
291 changes: 291 additions & 0 deletions src/builder/op-rbuilder/op_rbuilder_launcher.star
Original file line number Diff line number Diff line change
@@ -0,0 +1,291 @@
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")
observability = import_module("../../observability/observability.star")
util = import_module("../../util.star")
interop_constants = import_module("../../interop/constants.star")

RPC_PORT_NUM = 8545
WS_PORT_NUM = 8546
DISCOVERY_PORT_NUM = 30303
ENGINE_RPC_PORT_NUM = 9551

# 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"

# 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
),
}
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,
observability_helper,
interop_params,
):
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,
observability_helper,
interop_params,
)

service = plan.add_service(service_name, config)

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

http_url = "http://{0}:{1}".format(service.ip_address, RPC_PORT_NUM)

metrics_info = observability.new_metrics_info(
observability_helper, service, METRICS_PATH
)

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=[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,
observability_helper,
interop_params,
):
discovery_port = DISCOVERY_PORT_NUM
ports = dict(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",
"--discovery.port={0}".format(discovery_port),
"--port={0}".format(discovery_port),
"--rpc.eth-proof-window=302400",
]

# configure files

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"
],
)

# configure environment variables

env_vars = participant.el_builder_extra_env_vars

# apply customizations

if observability_helper.enabled:
cmd.append("--metrics=0.0.0.0:{0}".format(observability.METRICS_PORT_NUM))

observability.expose_metrics_port(ports)

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
]
]
)
)

cmd += participant.el_builder_extra_params

builder_secret_key = participant.el_builder_key
if builder_secret_key != "":
cmd.append("--rollup.builder-secret-key={0}".format(builder_secret_key))

if interop_params.enabled:
cmd.append(
"--rollup.supervisor-url={0}".format(interop_constants.SUPERVISOR_ENDPOINT)
)

config_args = {
"image": participant.el_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.EL_TYPE.op_reth,
client_type=constants.CLIENT_TYPES.el,
image=util.label_from_image(participant.el_builder_image),
connected_client=cl_client_name,
extra_labels=participant.el_builder_extra_labels,
),
"tolerations": tolerations,
"node_selectors": node_selectors,
}

# configure resources

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_rbuilder_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,
)
19 changes: 17 additions & 2 deletions src/el_cl_launcher.star
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,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_geth_builder = import_module("./builder/op-geth/op_geth_launcher.star")
op_reth_builder = import_module("./builder/op-reth/op_reth_launcher.star")
op_rbuilder_builder = import_module("./builder/op-rbuilder/op_rbuilder_launcher.star")
op_node_builder = import_module("./cl/op-node/op_node_builder_launcher.star")


Expand Down Expand Up @@ -113,6 +114,15 @@ def launch(
),
"launch_method": op_reth_builder.launch,
},
"op-rbuilder": {
"launcher": op_rbuilder_builder.new_op_rbuilder_builder_launcher(
deployment_output,
jwt_file,
network_params.network,
network_params.network_id,
),
"launch_method": op_rbuilder_builder.launch,
},
}

cl_launchers = {
Expand Down Expand Up @@ -404,5 +414,10 @@ def launch(
)
all_cl_contexts.append(cl_builder_context)

# We need to make sure that el_context and cl_context are first in the list, as down the line all_el_contexts[0]
# and all_cl_contexts[0] are used
all_el_contexts.insert(0, el_context)
all_cl_contexts.insert(0, cl_context)

plan.print("Successfully added {0} EL/CL participants".format(num_participants))
return all_el_contexts, all_cl_contexts
3 changes: 3 additions & 0 deletions src/package_io/input_parser.star
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ DEFAULT_EL_IMAGES = {
"op-erigon": "testinprod/op-erigon:latest",
"op-nethermind": "nethermind/nethermind:latest",
"op-besu": "ghcr.io/optimism-java/op-besu:latest",
"op-rbuilder": "ghcr.io/flashbots/op-rbuilder:latest",
}

DEFAULT_CL_IMAGES = {
Expand Down Expand Up @@ -154,6 +155,7 @@ 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_key=participant["el_builder_key"],
el_builder_log_level=participant["el_builder_log_level"],
el_builder_extra_env_vars=participant[
"el_builder_extra_env_vars"
Expand Down Expand Up @@ -573,6 +575,7 @@ def default_participant():
"cl_max_mem": 0,
"el_builder_type": "op-geth",
"el_builder_image": "",
"el_builder_key": "",
"el_builder_log_level": "",
"el_builder_extra_env_vars": {},
"el_builder_extra_labels": {},
Expand Down
1 change: 1 addition & 0 deletions src/package_io/sanity_check.star
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ PARTICIPANT_CATEGORIES = {
"cl_max_mem",
"el_builder_type",
"el_builder_image",
"el_builder_key",
"cl_builder_type",
"cl_builder_image",
"node_selectors",
Expand Down
Loading