diff --git a/.github/tests/mev-custom-helix-cb.yaml b/.github/tests/mev-custom-helix-cb.yaml new file mode 100644 index 000000000..3c16f6315 --- /dev/null +++ b/.github/tests/mev-custom-helix-cb.yaml @@ -0,0 +1,112 @@ +participants: + - el_type: geth + el_image: ethpandaops/geth:master + cl_type: lighthouse + cl_image: ethpandaops/lighthouse:unstable + vc_image: ethpandaops/lighthouse:unstable + supernode: true + count: 2 + +additional_services: + - dora + - spamoor + +# Custom MEV config: Helix relay + Commit-Boost sidecar + Flashbots builder +# Tests inline helix_relay_config override. commit-boost uses default template. +mev_type: custom +mev_params: + mev_relay: helix + mev_sidecar: commit-boost + mev_builder: flashbots + helix_relay_image: ghcr.io/gattaca-com/helix-relay:main + mev_boost_image: ghcr.io/commit-boost/pbs:latest + mev_builder_image: ethpandaops/reth-rbuilder:develop + mev_builder_cl_image: ethpandaops/lighthouse:unstable + mev_builder_subsidy: 1 + helix_relay_config: | + instance_id: "custom-helix-cb-test" + + network_config: !Custom + dir_path: "{{ .GENESIS_CONFIG_MOUNT_PATH_ON_CONTAINER }}/config.json" + genesis_validator_root: "{{ .GENESIS_VALIDATORS_ROOT }}" + genesis_time: {{ .GENESIS_TIME }} + + postgres: + hostname: "{{ .POSTGRES_HOST_NAME }}" + port: {{ .POSTGRES_PORT }} + db_name: "{{ .POSTGRES_DB }}" + user: "{{ .POSTGRES_USER }}" + password: "{{ .POSTGRES_PASS }}" + region: 0 + region_name: "LOCAL" + + beacon_clients: + - url: "{{ .BEACON_URI }}" + + gossip_payload_on_header: false + + simulators: + - url: "{{ .BLOCKSIM_URI }}" + namespace: flashbots + is_merging_simulator: false + max_concurrent_tasks: 32 + + router_config: + enabled_routes: + - route: GetValidators + - route: SubmitBlock + - route: GetTopBid + - route: GetHeader + rate_limit: + replenish_ms: 50 + burst_size: 20 + - route: GetPayload + - route: RegisterValidators + - route: Status + - route: ProposerPayloadDelivered + - route: BuilderBidsReceived + - route: ValidatorRegistration + shutdown_delay_ms: 12000 + + timing_game_config: + max_header_delay_ms: 400 + latest_header_delay_ms_in_slot: 1500 + default_client_latency_ms: 50 + + target_get_payload_propagation_duration_ms: 500 + + is_submission_instance: true + is_registration_instance: true + + admin_token: "test_admin_token" + + logging: + type: Console + + cores: + auctioneer: 0 + sub_workers: [0] + reg_workers: [0] + tokio: [0] + tcp_bid_submissions_tile: 2 + + is_local_dev: false + + +spamoor_params: + spammers: + - name: "Blob Spammer" + scenario: "blobs" + config: + throughput: 10 + - name: "ERC txs" + scenario: "erctx" + config: + throughput: 50 + max_pending: 400 + +network_params: + min_validator_withdrawability_delay: 1 + shard_committee_period: 1 + churn_limit_quotient: 16 + prefunded_accounts: '{"0xb9e79d19f651a941757b35830232e7efc77e1c79": {"balance": "100000ETH"}}' diff --git a/README.md b/README.md index e425b290d..4c69098ad 100644 --- a/README.md +++ b/README.md @@ -1470,6 +1470,7 @@ mempool_bridge_params: # Note: Helix uses TimescaleDB (PostgreSQL with time-series extension) for data storage # "buildoor" - a self-contained builder+relay service & mev-boost are spun up, powered by [buildoor](https://github.com/ethpandaops/buildoor) # Supports both legacy builder API and ePBS bidding. No separate relay infrastructure or builder participant needed. +# "custom" - mix and match relay, sidecar, and builder components via mev_params.mev_relay, mev_params.mev_sidecar, mev_params.mev_builder # We have seen instances of multibuilder instances failing to start mev-relay-api with non zero epochs mev_type: null @@ -1538,6 +1539,20 @@ mev_params: # [logs.stdout] # level = "debug" commit_boost_config: "" + # Inline Helix relay config template. When set, replaces the default auto-generated config. + # Template variables {{ .GENESIS_TIME }}, {{ .BEACON_URI }}, {{ .GENESIS_VALIDATORS_ROOT }}, + # {{ .POSTGRES_HOST_NAME }}, {{ .POSTGRES_PORT }}, {{ .POSTGRES_DB }}, {{ .POSTGRES_USER }}, + # {{ .POSTGRES_PASS }}, {{ .BLOCKSIM_URI }}, {{ .GENESIS_CONFIG_MOUNT_PATH_ON_CONTAINER }} + # are rendered at enclave creation. + helix_relay_config: "" + # Component overrides for custom mev_type (required when mev_type is "custom", optional otherwise) + # mev_relay: which relay to launch. Valid: "flashbots", "helix", "mev-rs", "mock", "none" + # mev_sidecar: which per-validator PBS service. Valid: "mev-boost", "commit-boost", "mev-rs", "none" + # mev_builder: which block builder. Valid: "flashbots", "mev-rs", "buildoor", "mock", "none" + # When used with a preset mev_type (e.g. "flashbots"), these override individual components. + mev_relay: "" + mev_sidecar: "" + mev_builder: "" # Parameters for the buildoor builder+relay service (used when mev_type is "buildoor") buildoor_params: @@ -1985,6 +2000,42 @@ network_params: +
+ Custom MEV: Helix relay + Commit-Boost sidecar + Flashbots builder + +```yaml +participants: + - el_type: geth + el_image: ethpandaops/geth:master + cl_type: lighthouse + cl_image: ethpandaops/lighthouse:unstable + vc_image: ethpandaops/lighthouse:unstable + supernode: true + count: 2 + +mev_type: custom +mev_params: + mev_relay: helix + mev_sidecar: commit-boost + mev_builder: flashbots + helix_relay_image: ghcr.io/gattaca-com/helix-relay:main + mev_boost_image: ghcr.io/commit-boost/pbs:latest + mev_builder_image: ethpandaops/reth-rbuilder:develop + mev_builder_cl_image: ethpandaops/lighthouse:unstable + mev_builder_subsidy: 1 + +additional_services: + - dora + - spamoor + +network_params: + min_validator_withdrawability_delay: 1 + shard_committee_period: 1 + prefunded_accounts: '{"0xb9e79d19f651a941757b35830232e7efc77e1c79": {"balance": "100000ETH"}}' +``` + +
+
A 2-node geth/lighthouse network with optional services (Grafana, Prometheus, tx_fuzz, EngineAPI snooper) @@ -2156,9 +2207,19 @@ The package also supports other MEV implementations: - `"mev_type": "mev-rs"` - Alternative relay implementation powered by [mev-rs](https://github.com/ralexstokes/mev-rs/) - `"mev_type": "commit-boost"` - Infrastructure powered by [commit-boost](https://github.com/Commit-Boost/commit-boost-client) - `"mev_type": "buildoor"` - A self-contained builder+relay service powered by [buildoor](https://github.com/ethpandaops/buildoor). Supports both legacy builder API and ePBS bidding without requiring separate relay infrastructure or a dedicated builder participant. +- `"mev_type": "custom"` - Mix and match any relay, sidecar, and builder via `mev_params.mev_relay`, `mev_params.mev_sidecar`, `mev_params.mev_builder`. For example, Helix relay + Commit-Boost sidecar + Flashbots builder. Each implementation provides different features and performance characteristics suitable for various testing and development scenarios. +You can also override individual components on any preset. For example, to use commit-boost as the sidecar with an otherwise-standard flashbots setup: + +```yaml +mev_type: flashbots +mev_params: + mev_sidecar: commit-boost + mev_boost_image: ghcr.io/commit-boost/pbs:latest +``` +
Caveats when using "mev_type": "flashbots" diff --git a/main.star b/main.star index dbd35aaf2..a2e64b187 100644 --- a/main.star +++ b/main.star @@ -1,5 +1,6 @@ input_parser = import_module("./src/package_io/input_parser.star") constants = import_module("./src/package_io/constants.star") +mev_resolver = import_module("./src/package_io/mev_resolver.star") participant_network = import_module("./src/participant_network.star") shared_utils = import_module("./src/shared_utils/shared_utils.star") static_files = import_module("./src/static_files/static_files.star") @@ -228,7 +229,9 @@ def run(plan, args={}): tempo.SERVICE_NAME, tempo.HTTP_PORT_NUMBER ) - if args_with_right_defaults.mev_type == constants.MEV_RS_MEV_TYPE: + mev_components = args_with_right_defaults.mev_components + + if mev_components != None and mev_components.builder == "mev-rs": plan.print("Generating mev-rs builder config file") mev_rs_builder_config_file = mev_rs_mev_builder.new_builder_config( plan, @@ -239,15 +242,11 @@ def run(plan, args={}): args_with_right_defaults.mev_params.mev_builder_extra_data, global_node_selectors, ) - elif ( - args_with_right_defaults.mev_type == constants.FLASHBOTS_MEV_TYPE - or args_with_right_defaults.mev_type == constants.COMMIT_BOOST_MEV_TYPE - or args_with_right_defaults.mev_type == constants.HELIX_MEV_TYPE - ): + elif mev_components != None and mev_components.builder == "flashbots": plan.print("Generating flashbots builder config file") flashbots_builder_config_file = flashbots_mev_rbuilder.new_builder_config( plan, - args_with_right_defaults.mev_type, + mev_components.relay, network_params, constants.VALIDATING_REWARDS_ACCOUNT, network_params.preregistered_validator_keys_mnemonic, @@ -373,7 +372,6 @@ def run(plan, args={}): mev_endpoints = [] mev_endpoint_names = [] # passed external relays get priority - # perhaps add mev_type External or remove this if ( hasattr(participant, "builder_network_params") and participant.builder_network_params != None @@ -381,205 +379,153 @@ def run(plan, args={}): mev_endpoints = participant.builder_network_params.relay_end_points for idx, mev_endpoint in enumerate(mev_endpoints): mev_endpoint_names.append("relay-{0}".format(idx + 1)) - # otherwise dummy relays spinup if chosen - elif ( - args_with_right_defaults.mev_type - and args_with_right_defaults.mev_type == constants.MOCK_MEV_TYPE - ): - el_uri = "{0}:{1}".format( - all_el_contexts[0].dns_name, - all_el_contexts[0].engine_rpc_port_num, - ) + elif mev_components != None: + # ─── RELAY LAUNCH ───────────────────────────────────────────────── + # Launch each relay in the resolved relay list + relay_index = 0 + for relay_name in mev_components.relay: + if relay_name == "none": + continue - # beacon uri for mock mev needs to use ip address and not dns name - beacon_uri_for_mock_mev = "{0}:{1}".format( - all_cl_contexts[0].ip_address, - all_cl_contexts[0].http_port, - ) - - endpoint = mock_mev.launch_mock_mev( - plan, - el_uri, - beacon_uri_for_mock_mev, - jwt_file, - args_with_right_defaults.global_log_level, - global_node_selectors, - global_tolerations, - args_with_right_defaults.mev_params, - ) - mev_endpoints.append(endpoint) - mev_endpoint_names.append(constants.MOCK_MEV_TYPE) - elif ( - args_with_right_defaults.mev_type - and args_with_right_defaults.mev_type == constants.BUILDOOR_MEV_TYPE - ): - beacon_uri = "http://{0}:{1}".format( - all_cl_contexts[0].beacon_service_name, - all_cl_contexts[0].http_port, - ) - el_rpc_uri = "http://{0}:{1}".format( - all_el_contexts[0].dns_name, - all_el_contexts[0].rpc_port_num, - ) - engine_rpc_uri = "http://{0}:{1}".format( - all_el_contexts[0].dns_name, - all_el_contexts[0].engine_rpc_port_num, - ) - endpoint = buildoor.launch_buildoor( - plan, - beacon_uri, - el_rpc_uri, - engine_rpc_uri, - jwt_file, - prefunded_accounts[0].private_key, - args_with_right_defaults.buildoor_params, - global_node_selectors, - global_tolerations, - builder_bls_secret_key, - ) - mev_endpoints.append(endpoint) - mev_endpoint_names.append(constants.BUILDOOR_MEV_TYPE) - elif args_with_right_defaults.mev_type and ( - args_with_right_defaults.mev_type == constants.FLASHBOTS_MEV_TYPE - or args_with_right_defaults.mev_type == constants.MEV_RS_MEV_TYPE - or args_with_right_defaults.mev_type == constants.COMMIT_BOOST_MEV_TYPE - or args_with_right_defaults.mev_type == constants.HELIX_MEV_TYPE - ): - builder_cl_context = all_cl_contexts[-1] - blocksim_uri = "http://{0}:{1}".format( - all_el_contexts[-1].dns_name, all_el_contexts[-1].rpc_port_num - ) - beacon_uri = builder_cl_context.beacon_http_url + if relay_name == "mock": + el_uri = "{0}:{1}".format( + all_el_contexts[0].dns_name, + all_el_contexts[0].engine_rpc_port_num, + ) + beacon_uri_for_mock_mev = "{0}:{1}".format( + all_cl_contexts[0].ip_address, + all_cl_contexts[0].http_port, + ) + endpoint = mock_mev.launch_mock_mev( + plan, + el_uri, + beacon_uri_for_mock_mev, + jwt_file, + args_with_right_defaults.global_log_level, + global_node_selectors, + global_tolerations, + args_with_right_defaults.mev_params, + ) + elif relay_name == "flashbots": + builder_cl_context = all_cl_contexts[-1] + blocksim_uri = "http://{0}:{1}".format( + all_el_contexts[-1].dns_name, all_el_contexts[-1].rpc_port_num + ) + beacon_uri = builder_cl_context.beacon_http_url + endpoint = flashbots_mev_relay.launch_mev_relay( + plan, + mev_params, + network_id, + beacon_uri, + genesis_validators_root, + blocksim_uri, + network_params, + persistent, + args_with_right_defaults.port_publisher, + num_participants + relay_index, + global_node_selectors, + global_tolerations, + builder_cl_context.beacon_service_name, + ) + elif relay_name == "helix": + builder_cl_context = all_cl_contexts[-1] + blocksim_uri = "http://{0}:{1}".format( + all_el_contexts[-1].dns_name, all_el_contexts[-1].rpc_port_num + ) + beacon_uri = builder_cl_context.beacon_http_url + endpoint = helix_relay.launch_helix_relay( + plan, + network_params, + mev_params, + beacon_uri, + genesis_validators_root, + final_genesis_timestamp, + blocksim_uri, + persistent, + args_with_right_defaults.port_publisher, + num_participants + relay_index, + global_node_selectors, + global_tolerations, + el_cl_data_files_artifact_uuid, + ) + elif relay_name == "mev-rs": + builder_cl_context = all_cl_contexts[-1] + beacon_uri = builder_cl_context.beacon_http_url + endpoint, _relay_ip, _relay_port = mev_rs_mev_relay.launch_mev_relay( + plan, + mev_params, + network_params.network, + beacon_uri, + el_cl_data_files_artifact_uuid, + args_with_right_defaults.port_publisher, + num_participants + relay_index, + global_node_selectors, + global_tolerations, + ) + else: + fail("Unsupported relay type: {0}".format(relay_name)) - first_cl_client = all_cl_contexts[0] - first_client_beacon_name = first_cl_client.beacon_service_name + mev_endpoints.append(endpoint) + mev_endpoint_names.append(relay_name) + relay_index += 1 - # Check if we should run multiple relays (flashbots + helix) - if mev_params.run_multiple_relays: - plan.print("Launching multiple MEV relays (flashbots + helix)") - # Launch flashbots relay first - flashbots_endpoint = flashbots_mev_relay.launch_mev_relay( - plan, - mev_params, - network_id, - beacon_uri, - genesis_validators_root, - blocksim_uri, - network_params, - persistent, - args_with_right_defaults.port_publisher, - num_participants, - global_node_selectors, - global_tolerations, - builder_cl_context.beacon_service_name, + # ─── BUILDOOR (has its own relay-like endpoint) ─────────────────── + if mev_components.builder == "buildoor": + beacon_uri = "http://{0}:{1}".format( + all_cl_contexts[0].beacon_service_name, + all_cl_contexts[0].http_port, ) - mev_endpoints.append(flashbots_endpoint) - mev_endpoint_names.append("flashbots") - - # Launch helix relay second - helix_endpoint = helix_relay.launch_helix_relay( - plan, - network_params, - mev_params, - beacon_uri, - genesis_validators_root, - final_genesis_timestamp, - blocksim_uri, - persistent, - args_with_right_defaults.port_publisher, - num_participants + 1, # Use different index for port allocation - global_node_selectors, - global_tolerations, - el_cl_data_files_artifact_uuid, - mev_params.helix_relay_image, # Use the helix-specific image + el_rpc_uri = "http://{0}:{1}".format( + all_el_contexts[0].dns_name, + all_el_contexts[0].rpc_port_num, ) - mev_endpoints.append(helix_endpoint) - mev_endpoint_names.append("helix") - elif ( - args_with_right_defaults.mev_type == constants.FLASHBOTS_MEV_TYPE - or args_with_right_defaults.mev_type == constants.COMMIT_BOOST_MEV_TYPE - ): - endpoint = flashbots_mev_relay.launch_mev_relay( - plan, - mev_params, - network_id, - beacon_uri, - genesis_validators_root, - blocksim_uri, - network_params, - persistent, - args_with_right_defaults.port_publisher, - num_participants, - global_node_selectors, - global_tolerations, - builder_cl_context.beacon_service_name, + engine_rpc_uri = "http://{0}:{1}".format( + all_el_contexts[0].dns_name, + all_el_contexts[0].engine_rpc_port_num, ) - mev_endpoints.append(endpoint) - mev_endpoint_names.append(args_with_right_defaults.mev_type) - elif args_with_right_defaults.mev_type == constants.MEV_RS_MEV_TYPE: - endpoint, relay_ip_address, relay_port = mev_rs_mev_relay.launch_mev_relay( + endpoint = buildoor.launch_buildoor( plan, - mev_params, - network_params.network, beacon_uri, - el_cl_data_files_artifact_uuid, - args_with_right_defaults.port_publisher, - num_participants, + el_rpc_uri, + engine_rpc_uri, + jwt_file, + prefunded_accounts[0].private_key, + args_with_right_defaults.buildoor_params, global_node_selectors, global_tolerations, + builder_bls_secret_key, ) - mev_endpoints.append(endpoint) - mev_endpoint_names.append(args_with_right_defaults.mev_type) - elif args_with_right_defaults.mev_type == constants.HELIX_MEV_TYPE: - endpoint = helix_relay.launch_helix_relay( - plan, - network_params, - mev_params, - beacon_uri, - genesis_validators_root, - final_genesis_timestamp, - blocksim_uri, - persistent, - args_with_right_defaults.port_publisher, - num_participants, - global_node_selectors, - global_tolerations, - el_cl_data_files_artifact_uuid, - ) - mev_endpoints.append(endpoint) - mev_endpoint_names.append(args_with_right_defaults.mev_type) - else: - fail("Invalid MEV type") + # Only add endpoint if there's a sidecar to consume it + if mev_components.sidecar != "none": + mev_endpoints.append(endpoint) + mev_endpoint_names.append("buildoor") - # spin up the mev boost contexts if some endpoints for relays have been passed + # ─── SIDECAR LAUNCH (per validator) ─────────────────────────────────── all_mevboost_contexts = [] - if mev_endpoints: + if mev_components != None and mev_components.sidecar == "none": + # ePBS: no sidecar needed, CL handles builder natively + pass + elif mev_endpoints: for index, participant in enumerate(all_participants): index_str = shared_utils.zfill_custom( index + 1, len(str(len(all_participants))) ) - plan.print( - "args_with_right_defaults.participants[index].validator_count {0}".format( - args_with_right_defaults.participants[index].validator_count - ) - ) if args_with_right_defaults.participants[index].validator_count != 0: - if ( - args_with_right_defaults.mev_type == constants.FLASHBOTS_MEV_TYPE - or args_with_right_defaults.mev_type == constants.MOCK_MEV_TYPE - or args_with_right_defaults.mev_type == constants.HELIX_MEV_TYPE - or args_with_right_defaults.mev_type == constants.BUILDOOR_MEV_TYPE - ): + sidecar_prefix = mev_resolver.get_sidecar_service_prefix( + mev_components.sidecar + ) + mev_boost_service_name = "{0}-{1}-{2}-{3}".format( + sidecar_prefix, + index_str, + participant.cl_type, + participant.el_type, + ) + + if mev_components.sidecar == "mev-boost": mev_boost_launcher = flashbots_mev_boost.new_mev_boost_launcher( MEV_BOOST_SHOULD_CHECK_RELAY, mev_endpoints, ) - mev_boost_service_name = "{0}-{1}-{2}-{3}".format( - constants.MEV_BOOST_SERVICE_NAME_PREFIX, - index_str, - participant.cl_type, - participant.el_type, - ) mev_boost_context = flashbots_mev_boost.launch( plan, mev_boost_launcher, @@ -594,19 +540,13 @@ def run(plan, args={}): global_node_selectors, global_tolerations, ) - elif args_with_right_defaults.mev_type == constants.MEV_RS_MEV_TYPE: - plan.print("Launching mev-rs mev boost") - mev_boost_launcher = mev_rs_mev_boost.new_mev_boost_launcher( + elif mev_components.sidecar == "commit-boost": + plan.print("Launching commit-boost PBS service") + mev_boost_launcher = commit_boost_mev_boost.new_mev_boost_launcher( MEV_BOOST_SHOULD_CHECK_RELAY, mev_endpoints, ) - mev_boost_service_name = "{0}-{1}-{2}-{3}".format( - constants.MEV_BOOST_SERVICE_NAME_PREFIX, - index_str, - participant.cl_type, - participant.el_type, - ) - mev_boost_context = mev_rs_mev_boost.launch( + mev_boost_context = commit_boost_mev_boost.launch( plan, mev_boost_launcher, mev_boost_service_name, @@ -618,22 +558,15 @@ def run(plan, args={}): index, global_node_selectors, global_tolerations, + final_genesis_timestamp, ) - elif ( - args_with_right_defaults.mev_type == constants.COMMIT_BOOST_MEV_TYPE - ): - plan.print("Launching commit-boost PBS service") - mev_boost_launcher = commit_boost_mev_boost.new_mev_boost_launcher( + elif mev_components.sidecar == "mev-rs": + plan.print("Launching mev-rs mev boost") + mev_boost_launcher = mev_rs_mev_boost.new_mev_boost_launcher( MEV_BOOST_SHOULD_CHECK_RELAY, mev_endpoints, ) - mev_boost_service_name = "{0}-{1}-{2}-{3}".format( - constants.COMMIT_BOOST_SERVICE_NAME_PREFIX, - index_str, - participant.cl_type, - participant.el_type, - ) - mev_boost_context = commit_boost_mev_boost.launch( + mev_boost_context = mev_rs_mev_boost.launch( plan, mev_boost_launcher, mev_boost_service_name, @@ -645,10 +578,7 @@ def run(plan, args={}): index, global_node_selectors, global_tolerations, - final_genesis_timestamp, ) - else: - fail("Invalid MEV type") all_mevboost_contexts.append(mev_boost_context) if len(args_with_right_defaults.additional_services) == 0: diff --git a/network_params.yaml b/network_params.yaml index 37e26c88d..1d98473cb 100644 --- a/network_params.yaml +++ b/network_params.yaml @@ -207,7 +207,7 @@ ethereum_metrics_exporter_enabled: false parallel_keystore_generation: false disable_peer_scoring: false persistent: false -# Supports: null, mock, flashbots, mev-rs, commit-boost, helix, buildoor +# Supports: null, mock, flashbots, mev-rs, commit-boost, helix, buildoor, epbs, custom mev_type: null mev_params: mev_relay_image: ethpandaops/mev-boost-relay:main @@ -229,6 +229,7 @@ mev_params: run_multiple_relays: false helix_relay_image: ghcr.io/gattaca-com/helix-relay:main commit_boost_config: "" + helix_relay_config: "" custom_flood_params: interval_between_transactions: 1 buildoor_params: diff --git a/src/el/reth/reth_launcher.star b/src/el/reth/reth_launcher.star index 5b32a33ac..3e2c997dc 100644 --- a/src/el/reth/reth_launcher.star +++ b/src/el/reth/reth_launcher.star @@ -120,11 +120,7 @@ def get_config( constants.RPC_PORT_ID: public_ports_for_component[3], constants.WS_PORT_ID: public_ports_for_component[4], } - if ( - launcher.builder_type == constants.FLASHBOTS_MEV_TYPE - or launcher.builder_type == constants.COMMIT_BOOST_MEV_TYPE - or launcher.builder_type == constants.HELIX_MEV_TYPE - ): + if launcher.builder_type == "flashbots": additional_public_port_assignments[ constants.RBUILDER_PORT_ID ] = public_ports_for_component[5] @@ -155,11 +151,7 @@ def get_config( constants.METRICS_PORT_ID: METRICS_PORT_NUM, } - if ( - launcher.builder_type == constants.FLASHBOTS_MEV_TYPE - or launcher.builder_type == constants.COMMIT_BOOST_MEV_TYPE - or launcher.builder_type == constants.HELIX_MEV_TYPE - ): + if launcher.builder_type == "flashbots": used_port_assignments[constants.RBUILDER_PORT_ID] = RBUILDER_PORT_NUM used_port_assignments[ constants.RBUILDER_METRICS_PORT_ID @@ -187,11 +179,7 @@ def get_config( "--http.addr=0.0.0.0", "--http.corsdomain=*", "--http.api=admin,net,eth,web3,debug,txpool,trace{0}".format( - ",flashbots" - if launcher.builder_type == constants.FLASHBOTS_MEV_TYPE - or launcher.builder_type == constants.COMMIT_BOOST_MEV_TYPE - or launcher.builder_type == constants.HELIX_MEV_TYPE - else "" + ",flashbots" if launcher.builder_type == "flashbots" else "" ), "--ws", "--ws.addr=0.0.0.0", @@ -279,15 +267,11 @@ def get_config( env_vars = {} image = participant.el_image - if launcher.builder_type == constants.MEV_RS_MEV_TYPE: + if launcher.builder_type == "mev-rs": files[ mev_rs_builder.MEV_BUILDER_MOUNT_DIRPATH_ON_SERVICE ] = mev_rs_builder.MEV_BUILDER_FILES_ARTIFACT_NAME - elif ( - launcher.builder_type == constants.FLASHBOTS_MEV_TYPE - or launcher.builder_type == constants.COMMIT_BOOST_MEV_TYPE - or launcher.builder_type == constants.HELIX_MEV_TYPE - ): + elif launcher.builder_type == "flashbots": image = launcher.mev_params.mev_builder_image cl_client_name = service_name.split("-")[4] cmd.append("--rbuilder.config=" + flashbots_rbuilder.MEV_FILE_PATH_ON_CONTAINER) diff --git a/src/mev/commit-boost/mev_boost/mev_boost_launcher.star b/src/mev/commit-boost/mev_boost/mev_boost_launcher.star index 0bec0abf0..4c3dc89ff 100644 --- a/src/mev/commit-boost/mev_boost/mev_boost_launcher.star +++ b/src/mev/commit-boost/mev_boost/mev_boost_launcher.star @@ -10,7 +10,9 @@ CB_CONFIG_FILES_ARTIFACT_NAME = "commit-boost-config" USED_PORTS = { "http": shared_utils.new_port_spec( - constants.MEV_BOOST_PORT, shared_utils.TCP_PROTOCOL + constants.MEV_BOOST_PORT, + shared_utils.TCP_PROTOCOL, + wait="15s", ) } diff --git a/src/mev/flashbots/mev_builder/mev_builder_launcher.star b/src/mev/flashbots/mev_builder/mev_builder_launcher.star index e695e2a53..787bb326f 100644 --- a/src/mev/flashbots/mev_builder/mev_builder_launcher.star +++ b/src/mev/flashbots/mev_builder/mev_builder_launcher.star @@ -17,7 +17,7 @@ MEV_FILE_PATH_ON_CONTAINER = ( def new_builder_config( plan, - mev_type, + relay_list, network_params, fee_recipient, mnemonic, @@ -25,6 +25,12 @@ def new_builder_config( participants, global_node_selectors, ): + """ + Generate rbuilder config file. + + Args: + relay_list: List of relay name strings (e.g., ["flashbots"], ["flashbots", "helix"]) + """ num_of_participants = shared_utils.zfill_custom( len(participants), len(str(len(participants))) ) @@ -37,8 +43,7 @@ def new_builder_config( mev_params.mev_builder_extra_data, num_of_participants, mev_params.mev_builder_subsidy, - mev_type, - mev_params.run_multiple_relays, + relay_list, ) flashbots_builder_config_template = read_file( static_files.FLASHBOTS_RBUILDER_CONFIG_FILEPATH @@ -73,48 +78,37 @@ def new_builder_config_template_data( extra_data, num_of_participants, subsidy, - mev_type, - run_multiple_relays=False, + relay_list, ): - # Build the list of relays based on configuration - relays = [] + """ + Build template data using the resolved relay list directly. - if run_multiple_relays: - # Add both flashbots and helix relays - relays.append( - { - "Name": "flashbots", - "Service": "mev-relay-api", - "Port": flashbots_relay.MEV_RELAY_ENDPOINT_PORT, - "Priority": 0, - } - ) - relays.append( - { - "Name": "helix", - "Service": "helix-relay", - "Port": helix_relay.HELIX_RELAY_ENDPOINT_PORT, - "Priority": 1, - } - ) - elif mev_type == constants.HELIX_MEV_TYPE: - relays.append( - { - "Name": "helix", - "Service": "helix-relay", - "Port": helix_relay.HELIX_RELAY_ENDPOINT_PORT, - "Priority": 0, - } - ) - else: - relays.append( - { - "Name": "flashbots", - "Service": "mev-relay-api", - "Port": flashbots_relay.MEV_RELAY_ENDPOINT_PORT, - "Priority": 0, - } - ) + Args: + relay_list: List of relay name strings (e.g., ["flashbots", "helix"]) + """ + relays = [] + for priority, relay_name in enumerate(relay_list): + if relay_name == "none": + continue + elif relay_name == "flashbots": + relays.append( + { + "Name": "flashbots", + "Service": "mev-relay-api", + "Port": flashbots_relay.MEV_RELAY_ENDPOINT_PORT, + "Priority": priority, + } + ) + elif relay_name == "helix": + relays.append( + { + "Name": "helix", + "Service": "helix-relay", + "Port": helix_relay.HELIX_RELAY_ENDPOINT_PORT, + "Priority": priority, + } + ) + # mev-rs relay is not supported in rbuilder config (different protocol) # Build enabled_relays string for the config: "relay1", "relay2" enabled_relays = ", ".join(['"{}"'.format(r["Name"]) for r in relays]) diff --git a/src/mev/helix/helix_relay_launcher.star b/src/mev/helix/helix_relay_launcher.star index f0afeec65..2f83dae4a 100644 --- a/src/mev/helix/helix_relay_launcher.star +++ b/src/mev/helix/helix_relay_launcher.star @@ -6,26 +6,28 @@ static_files = import_module("../../static_files/static_files.star") HELIX_RELAY_NAME = "helix-relay" -HTTP_PORT_ID = "http" ENDPOINT_PORT_ID = "endpoint" +ADMIN_PORT_ID = "admin" HELIX_RELAY_CONFIG_FILENAME = "config.yaml" HELIX_RELAY_MOUNT_DIRPATH_ON_SERVICE = "/config/" HELIX_RELAY_FILES_ARTIFACT_NAME = "helix-relay-config" HELIX_RELAY_ENDPOINT_PORT = 4040 -HELIX_RELAY_WEBSITE_PORT = 9060 +HELIX_RELAY_ADMIN_PORT = 4050 USED_PORTS = { ENDPOINT_PORT_ID: shared_utils.new_port_spec( HELIX_RELAY_ENDPOINT_PORT, shared_utils.TCP_PROTOCOL, shared_utils.HTTP_APPLICATION_PROTOCOL, + wait="60s", ), - HTTP_PORT_ID: shared_utils.new_port_spec( - HELIX_RELAY_WEBSITE_PORT, + ADMIN_PORT_ID: shared_utils.new_port_spec( + HELIX_RELAY_ADMIN_PORT, shared_utils.TCP_PROTOCOL, shared_utils.HTTP_APPLICATION_PROTOCOL, + wait="60s", ), } @@ -67,14 +69,6 @@ def launch_helix_relay( 0, ) public_ports.update(endpoint_public_port) - website_public_port = shared_utils.get_mev_public_port( - port_publisher, - HTTP_PORT_ID, - index, - 1, - ) - public_ports.update(website_public_port) - node_selectors = global_node_selectors postgres = postgres_module.run( @@ -104,8 +98,11 @@ def launch_helix_relay( postgres, ) - # Read the helix config template - helix_config_template = read_file(static_files.HELIX_RELAY_CONFIG_FILEPATH) + # Read the helix config template (allow inline override) + if hasattr(mev_params, "helix_relay_config") and mev_params.helix_relay_config: + helix_config_template = mev_params.helix_relay_config + else: + helix_config_template = read_file(static_files.HELIX_RELAY_CONFIG_FILEPATH) template_and_data = shared_utils.new_template_and_data( helix_config_template, helix_template_data ) @@ -128,10 +125,12 @@ def launch_helix_relay( env_vars = { "RELAY_KEY": constants.DEFAULT_MEV_SECRET_KEY, + "POSTGRES_PASSWORD": "postgres", + "ADMIN_TOKEN": "admin_token", } - # Use provided relay_image if available, otherwise use mev_params.mev_relay_image - helix_image = relay_image if relay_image else mev_params.mev_relay_image + # Use provided relay_image if available, otherwise use mev_params.helix_relay_image + helix_image = relay_image if relay_image else mev_params.helix_relay_image endpoint = plan.add_service( name=HELIX_RELAY_NAME, @@ -179,7 +178,6 @@ def new_helix_relay_config_template_data( "POSTGRES_USER": "postgres", "POSTGRES_PASS": "postgres", "HELIX_RELAY_ENDPOINT_PORT": HELIX_RELAY_ENDPOINT_PORT, - "HELIX_RELAY_WEBSITE_PORT": HELIX_RELAY_WEBSITE_PORT, "HELIX_RELAY_ENDPOINT_URL": "helix-relay:{}".format(HELIX_RELAY_ENDPOINT_PORT), "HELIX_RELAY_PUBKEY": constants.DEFAULT_MEV_PUBKEY, "GENESIS_CONFIG_MOUNT_PATH_ON_CONTAINER": constants.GENESIS_DATA_MOUNTPOINT_ON_CLIENTS, diff --git a/src/package_io/constants.star b/src/package_io/constants.star index 940b56e09..38a451c58 100644 --- a/src/package_io/constants.star +++ b/src/package_io/constants.star @@ -100,6 +100,9 @@ MEV_RS_MEV_TYPE = "mev-rs" COMMIT_BOOST_MEV_TYPE = "commit-boost" HELIX_MEV_TYPE = "helix" BUILDOOR_MEV_TYPE = "buildoor" +CUSTOM_MEV_TYPE = "custom" +EPBS_MEV_TYPE = "epbs" +MEV_NONE = "none" DEFAULT_DORA_IMAGE = "ethpandaops/dora:latest" DEFAULT_CHECKPOINTZ_IMAGE = "ethpandaops/checkpointz:latest" DEFAULT_SPAMOOR_IMAGE = "ethpandaops/spamoor:latest" diff --git a/src/package_io/input_parser.star b/src/package_io/input_parser.star index 00dd98c25..5955ed10d 100644 --- a/src/package_io/input_parser.star +++ b/src/package_io/input_parser.star @@ -3,6 +3,7 @@ shared_utils = import_module("../shared_utils/shared_utils.star") genesis_constants = import_module( "../prelaunch_data_generator/genesis_constants/genesis_constants.star" ) +mev_resolver = import_module("./mev_resolver.star") sanity_check = import_module("./sanity_check.star") @@ -257,28 +258,20 @@ def input_parser(plan, input_args): if result.get("disable_peer_scoring"): result = enrich_disable_peer_scoring(result) - if result.get("mev_type") in ( - constants.MOCK_MEV_TYPE, - constants.FLASHBOTS_MEV_TYPE, - constants.MEV_RS_MEV_TYPE, - constants.COMMIT_BOOST_MEV_TYPE, - constants.HELIX_MEV_TYPE, - constants.BUILDOOR_MEV_TYPE, - ): + # Resolve mev_type into (relay, sidecar, builder) components + mev_components = mev_resolver.resolve_mev_components( + result.get("mev_type"), result["mev_params"] + ) + result["mev_components"] = mev_components + + if mev_components != None: result = enrich_mev_extra_params( result, - constants.MEV_BOOST_SERVICE_NAME_PREFIX, constants.MEV_BOOST_PORT, - result.get("mev_type"), + mev_components, ) elif result.get("mev_type") == None: pass - else: - fail( - "Unsupported MEV type: {0}, please use 'mock', 'flashbots', 'mev-rs', 'commit-boost', 'helix' or 'buildoor' type".format( - result.get("mev_type") - ) - ) if ( result["mev_params"].get("mev_builder_subsidy") != 0 @@ -892,6 +885,10 @@ def input_parser(plan, input_args): run_multiple_relays=result["mev_params"]["run_multiple_relays"], helix_relay_image=result["mev_params"]["helix_relay_image"], commit_boost_config=result["mev_params"].get("commit_boost_config", ""), + helix_relay_config=result["mev_params"].get("helix_relay_config", ""), + mev_relay=result["mev_params"].get("mev_relay"), + mev_sidecar=result["mev_params"].get("mev_sidecar"), + mev_builder=result["mev_params"].get("mev_builder"), ) if result["mev_params"] else None, @@ -1033,6 +1030,7 @@ def input_parser(plan, input_args): wait_for_finalization=result["wait_for_finalization"], global_log_level=result["global_log_level"], mev_type=result["mev_type"], + mev_components=result["mev_components"], snooper_enabled=result["snooper_enabled"], snooper_params=struct( enabled=result["snooper_params"]["enabled"], @@ -2068,6 +2066,10 @@ def get_default_mev_params(mev_type, preset): "run_multiple_relays": False, "helix_relay_image": constants.DEFAULT_HELIX_RELAY_IMAGE, "commit_boost_config": "", + "helix_relay_config": "", + "mev_relay": None, + "mev_sidecar": None, + "mev_builder": None, } @@ -2362,77 +2364,83 @@ def enrich_disable_peer_scoring(parsed_arguments_dict): return parsed_arguments_dict -# TODO perhaps clean this up into a map -def enrich_mev_extra_params(parsed_arguments_dict, mev_prefix, mev_port, mev_type): - for index, participant in enumerate(parsed_arguments_dict["participants"]): - index_str = shared_utils.zfill_custom( - index + 1, len(str(len(parsed_arguments_dict["participants"]))) - ) - - if mev_type == constants.COMMIT_BOOST_MEV_TYPE: - prefix = constants.COMMIT_BOOST_SERVICE_NAME_PREFIX - else: - prefix = constants.MEV_BOOST_SERVICE_NAME_PREFIX - - mev_url = "http://{0}-{1}-{2}-{3}:{4}".format( - prefix, - index_str, - participant["cl_type"], - participant["el_type"], - mev_port, - ) +def enrich_mev_extra_params(parsed_arguments_dict, mev_port, mev_components): + """ + Enrich participant CL/VC params with builder configuration. + Two responsibilities: + 1. Inject --builder= into CL/VC params (only when sidecar != "none") + 2. Append builder participant to participant list (for flashbots/mev-rs builders) + + Args: + parsed_arguments_dict: The full parsed arguments dict + mev_port: The MEV boost port number + mev_components: Resolved struct with .relay, .sidecar, .builder + """ + # Part 1: CL/VC builder flags (only when there IS a sidecar to point them at) + if mev_components.sidecar != "none": + prefix = mev_resolver.get_sidecar_service_prefix(mev_components.sidecar) - if participant["cl_type"] == "lighthouse": - participant["cl_extra_params"].append("--builder={0}".format(mev_url)) - if participant["vc_type"] == "lighthouse": - if ( - parsed_arguments_dict["network_params"]["gas_limit"] == 0 - ): # if the gas limit is set we already enable builder-proposals - participant["vc_extra_params"].append("--builder-proposals") - if participant["cl_type"] == "lodestar": - participant["cl_extra_params"].append("--builder") - participant["cl_extra_params"].append("--builder.urls={0}".format(mev_url)) - if participant["vc_type"] == "lodestar": - participant["vc_extra_params"].append("--builder") - if participant["cl_type"] == "nimbus": - participant["cl_extra_params"].append("--payload-builder=true") - participant["cl_extra_params"].append( - "--payload-builder-url={0}".format(mev_url) + for index, participant in enumerate(parsed_arguments_dict["participants"]): + index_str = shared_utils.zfill_custom( + index + 1, len(str(len(parsed_arguments_dict["participants"]))) ) - if participant["vc_type"] == "nimbus": - participant["vc_extra_params"].append("--payload-builder=true") - if participant["cl_type"] == "teku": - participant["cl_extra_params"].append( - "--builder-endpoint={0}".format(mev_url) - ) - participant["cl_extra_params"].append( - "--validators-builder-registration-default-enabled=true" - ) - if participant["vc_type"] == "teku": - participant["vc_extra_params"].append( - "--validators-builder-registration-default-enabled=true" - ) - if participant["cl_type"] == "prysm": - participant["cl_extra_params"].append( - "--http-mev-relay={0}".format(mev_url) + + mev_url = "http://{0}-{1}-{2}-{3}:{4}".format( + prefix, + index_str, + participant["cl_type"], + participant["el_type"], + mev_port, ) - if participant["vc_type"] == "prysm": - participant["vc_extra_params"].append("--enable-builder") - if participant["cl_type"] == "grandine": - participant["cl_extra_params"].append("--builder-url={0}".format(mev_url)) - if participant["vc_type"] == "vero": - participant["vc_extra_params"].append("--use-external-builder") + if participant["cl_type"] == "lighthouse": + participant["cl_extra_params"].append("--builder={0}".format(mev_url)) + if participant["vc_type"] == "lighthouse": + if ( + parsed_arguments_dict["network_params"]["gas_limit"] == 0 + ): # if the gas limit is set we already enable builder-proposals + participant["vc_extra_params"].append("--builder-proposals") + if participant["cl_type"] == "lodestar": + participant["cl_extra_params"].append("--builder") + participant["cl_extra_params"].append( + "--builder.urls={0}".format(mev_url) + ) + if participant["vc_type"] == "lodestar": + participant["vc_extra_params"].append("--builder") + if participant["cl_type"] == "nimbus": + participant["cl_extra_params"].append("--payload-builder=true") + participant["cl_extra_params"].append( + "--payload-builder-url={0}".format(mev_url) + ) + if participant["vc_type"] == "nimbus": + participant["vc_extra_params"].append("--payload-builder=true") + if participant["cl_type"] == "teku": + participant["cl_extra_params"].append( + "--builder-endpoint={0}".format(mev_url) + ) + participant["cl_extra_params"].append( + "--validators-builder-registration-default-enabled=true" + ) + if participant["vc_type"] == "teku": + participant["vc_extra_params"].append( + "--validators-builder-registration-default-enabled=true" + ) + if participant["cl_type"] == "prysm": + participant["cl_extra_params"].append( + "--http-mev-relay={0}".format(mev_url) + ) + if participant["vc_type"] == "prysm": + participant["vc_extra_params"].append("--enable-builder") + if participant["cl_type"] == "grandine": + participant["cl_extra_params"].append( + "--builder-url={0}".format(mev_url) + ) - num_participants = len(parsed_arguments_dict["participants"]) - index_str = shared_utils.zfill_custom( - num_participants + 1, len(str(num_participants + 1)) - ) - if ( - mev_type == constants.FLASHBOTS_MEV_TYPE - or mev_type == constants.COMMIT_BOOST_MEV_TYPE - or mev_type == constants.HELIX_MEV_TYPE - ): + if participant["vc_type"] == "vero": + participant["vc_extra_params"].append("--use-external-builder") + + # Part 2: Builder participant (add a dedicated builder EL+CL pair) + if mev_components.builder == "flashbots": mev_participant = default_participant() mev_participant["el_type"] = "reth-builder" mev_participant.update( @@ -2457,10 +2465,8 @@ def enrich_mev_extra_params(parsed_arguments_dict, mev_prefix, mev_port, mev_typ ], } ) - parsed_arguments_dict["participants"].append(mev_participant) - - if mev_type == constants.MEV_RS_MEV_TYPE: + elif mev_components.builder == "mev-rs": mev_participant = default_participant() mev_participant["el_type"] = "reth-builder" mev_participant.update( @@ -2482,10 +2488,12 @@ def enrich_mev_extra_params(parsed_arguments_dict, mev_prefix, mev_port, mev_typ } ) parsed_arguments_dict["participants"].append(mev_participant) - if mev_type == constants.MOCK_MEV_TYPE: + elif mev_components.builder == "mock": parsed_arguments_dict["mev_params"]["mock_mev_image"] = parsed_arguments_dict[ "mev_params" ]["mock_mev_image"] + # builder in ("buildoor", "none") -> no builder participant added + return parsed_arguments_dict diff --git a/src/package_io/mev_resolver.star b/src/package_io/mev_resolver.star new file mode 100644 index 000000000..705eb317b --- /dev/null +++ b/src/package_io/mev_resolver.star @@ -0,0 +1,168 @@ +# MEV Component Resolver +# +# Decomposes mev_type (a preset shortcut) into three independent components: +# - relay: which relay(s) to launch (flashbots, helix, mev-rs, mock, none) +# - sidecar: which per-validator boost/PBS service to use (mev-boost, commit-boost, mev-rs, none) +# - builder: which block builder to run (flashbots, mev-rs, buildoor, mock, none) +# +# This allows mix-and-match configurations (e.g., helix relay + commit-boost sidecar) +# without patching the code. + +constants = import_module("./constants.star") + +# Preset expansion table: mev_type -> (relay, sidecar, builder) +MEV_PRESETS = { + constants.FLASHBOTS_MEV_TYPE: { + "relay": "flashbots", + "sidecar": "mev-boost", + "builder": "flashbots", + }, + constants.HELIX_MEV_TYPE: { + "relay": "helix", + "sidecar": "mev-boost", + "builder": "flashbots", + }, + constants.COMMIT_BOOST_MEV_TYPE: { + "relay": "flashbots", + "sidecar": "commit-boost", + "builder": "flashbots", + }, + constants.MEV_RS_MEV_TYPE: { + "relay": "mev-rs", + "sidecar": "mev-rs", + "builder": "mev-rs", + }, + constants.MOCK_MEV_TYPE: { + "relay": "mock", + "sidecar": "mev-boost", + "builder": "mock", + }, + constants.BUILDOOR_MEV_TYPE: { + "relay": "none", + "sidecar": "mev-boost", + "builder": "buildoor", + }, + constants.EPBS_MEV_TYPE: { + "relay": "none", + "sidecar": "none", + "builder": "buildoor", + }, +} + +VALID_RELAYS = ["flashbots", "helix", "mev-rs", "mock", "none"] +VALID_SIDECARS = ["mev-boost", "commit-boost", "mev-rs", "none"] +VALID_BUILDERS = ["flashbots", "mev-rs", "buildoor", "mock", "none"] + + +def resolve_mev_components(mev_type, mev_params): + if mev_type == None: + return None + + if mev_type == constants.CUSTOM_MEV_TYPE: + relay = mev_params.get("mev_relay") + sidecar = mev_params.get("mev_sidecar") + builder = mev_params.get("mev_builder") + if not relay or not sidecar or not builder: + fail( + "mev_type 'custom' requires explicit mev_params.mev_relay, " + + "mev_params.mev_sidecar, and mev_params.mev_builder to be set" + ) + elif mev_type in MEV_PRESETS: + preset = MEV_PRESETS[mev_type] + # Allow user to override individual components via mev_params + relay = ( + mev_params.get("mev_relay") + if mev_params.get("mev_relay") + else preset["relay"] + ) + sidecar = ( + mev_params.get("mev_sidecar") + if mev_params.get("mev_sidecar") + else preset["sidecar"] + ) + builder = ( + mev_params.get("mev_builder") + if mev_params.get("mev_builder") + else preset["builder"] + ) + else: + fail( + "Unsupported mev_type: '{0}'. Valid options: mock, flashbots, mev-rs, commit-boost, helix, buildoor, epbs, custom".format( + mev_type + ) + ) + + # Legacy: run_multiple_relays overrides relay to a list + if mev_params.get("run_multiple_relays", False): + relay = ["flashbots", "helix"] + + # Normalize relay to always be a list internally + if type(relay) == "string": + relay_list = [relay] + else: + relay_list = [r for r in relay] + + # Validate relay values + for r in relay_list: + if r not in VALID_RELAYS: + fail("Invalid mev_relay value: '{0}'. Valid: {1}".format(r, VALID_RELAYS)) + + # Validate sidecar value + if sidecar not in VALID_SIDECARS: + fail( + "Invalid mev_sidecar value: '{0}'. Valid: {1}".format( + sidecar, VALID_SIDECARS + ) + ) + + # Validate builder value + if builder not in VALID_BUILDERS: + fail( + "Invalid mev_builder value: '{0}'. Valid: {1}".format( + builder, VALID_BUILDERS + ) + ) + + # Cross-component validation (hard errors for impossible combinations) + all_none_relays = len([r for r in relay_list if r != "none"]) == 0 + + if all_none_relays and builder == "flashbots": + fail( + "Invalid MEV config: mev_builder='flashbots' (rbuilder) requires at least one relay " + + "to submit blocks to, but mev_relay is 'none'. Use mev_builder='buildoor' for ePBS " + + "or set a relay." + ) + + if all_none_relays and sidecar != "none" and builder != "buildoor": + fail( + "Invalid MEV config: mev_sidecar='{0}' needs relay endpoints to connect to, ".format( + sidecar + ) + + "but mev_relay is 'none' and builder is not 'buildoor' (which provides its own endpoint). " + + "Set a relay, use builder='buildoor', or set sidecar='none' for ePBS." + ) + + return struct( + relay=relay_list, + sidecar=sidecar, + builder=builder, + ) + + +def get_sidecar_service_prefix(sidecar): + if sidecar == "none": + fail("BUG: get_sidecar_service_prefix called with sidecar='none'") + if sidecar == "commit-boost": + return constants.COMMIT_BOOST_SERVICE_NAME_PREFIX + return constants.MEV_BOOST_SERVICE_NAME_PREFIX + + +def get_relay_image(relay_name, mev_params): + if relay_name == "helix": + return mev_params.helix_relay_image or constants.DEFAULT_HELIX_RELAY_IMAGE + elif relay_name == "flashbots": + return mev_params.mev_relay_image or constants.DEFAULT_FLASHBOTS_RELAY_IMAGE + elif relay_name == "mev-rs": + return mev_params.mev_relay_image or constants.DEFAULT_MEV_RS_IMAGE + else: + return mev_params.mev_relay_image diff --git a/src/package_io/sanity_check.star b/src/package_io/sanity_check.star index bf7cb38cc..1969c064a 100644 --- a/src/package_io/sanity_check.star +++ b/src/package_io/sanity_check.star @@ -380,6 +380,10 @@ SUBCATEGORY_PARAMS = { "run_multiple_relays", "helix_relay_image", "commit_boost_config", + "helix_relay_config", + "mev_relay", + "mev_sidecar", + "mev_builder", ], "xatu_sentry_params": [ "xatu_sentry_image", diff --git a/src/participant_network.star b/src/participant_network.star index 1b4c0dd8e..717757d48 100644 --- a/src/participant_network.star +++ b/src/participant_network.star @@ -208,7 +208,9 @@ def launch_participant_network( network_id, num_participants, args_with_right_defaults.port_publisher, - args_with_right_defaults.mev_type, + args_with_right_defaults.mev_components.builder + if args_with_right_defaults.mev_components + else False, args_with_right_defaults.mev_params, extra_files_artifacts, bootnodoor_enode, diff --git a/static_files/mev/helix/config.yaml.tmpl b/static_files/mev/helix/config.yaml.tmpl index 27d7376d9..30e8d6b0e 100644 --- a/static_files/mev/helix/config.yaml.tmpl +++ b/static_files/mev/helix/config.yaml.tmpl @@ -37,7 +37,7 @@ router_config: - route: GetValidators - route: SubmitBlock - route: GetTopBid - + # Proposer API routes - route: GetHeader rate_limit: @@ -46,12 +46,12 @@ router_config: - route: GetPayload - route: RegisterValidators - route: Status - + # Data API routes - route: ProposerPayloadDelivered - route: BuilderBidsReceived - route: ValidatorRegistration - + # Graceful shutdown delay (milliseconds) shutdown_delay_ms: 12000 @@ -75,25 +75,13 @@ admin_token: "admin_token" logging: type: Console -# Optional: Website/dashboard -website: - enabled: true - port: {{ .HELIX_RELAY_WEBSITE_PORT }} - listen_address: "0.0.0.0" - show_config_details: false - network_name: "Kurtosis Helix Relay" # TODO - we can configure this to show network - relay_url: "https://{{ .HELIX_RELAY_ENDPOINT_URL }}" - relay_pubkey: "{{ .HELIX_RELAY_PUBKEY }}" - link_beaconchain: "https://hoodi.beaconcha.in" - link_etherscan: "https://hoodi.etherscan.io" - link_data_api: "https://relay.example.com/relay/v1/data" - # CPU Core Pinning (CRITICAL for production performance) cores: auctioneer: 0 # Single core for main auctioneer thread sub_workers: [0] # Cores for submission workers reg_workers: [0] # Cores for registration workers tokio: [0] # Cores for Tokio async runtime + tcp_bid_submissions_tile: 2 # Optional: Enable local development mode (disables some checks) -is_local_dev: false \ No newline at end of file +is_local_dev: false