diff --git a/main.star b/main.star index c9ea27d3b..5e9682140 100644 --- a/main.star +++ b/main.star @@ -31,6 +31,7 @@ grafana = import_module("./src/grafana/grafana_launcher.star") mev_boost = import_module("./src/mev/mev_boost/mev_boost_launcher.star") mock_mev = import_module("./src/mev/mock_mev/mock_mev_launcher.star") mev_relay = import_module("./src/mev/mev_relay/mev_relay_launcher.star") +helix_relay = import_module("./src/mev/mev_relay/helix_launcher.star") mev_flood = import_module("./src/mev/mev_flood/mev_flood_launcher.star") mev_custom_flood = import_module( "./src/mev/mev_custom_flood/mev_custom_flood_launcher.star" @@ -237,15 +238,16 @@ def run(plan, args={}): timeout="20m", service_name=first_client_beacon_name, ) - endpoint = mev_relay.launch_mev_relay( + endpoint = helix_relay.launch_helix_relay( plan, mev_params, - network_params.network_id, + network_params, beacon_uris, genesis_validators_root, builder_uri, network_params.seconds_per_slot, persistent, + final_genesis_timestamp, global_node_selectors, ) mev_flood.spam_in_background( diff --git a/src/mev/mev_relay/helix_launcher.star b/src/mev/mev_relay/helix_launcher.star new file mode 100644 index 000000000..2d4b1846f --- /dev/null +++ b/src/mev/mev_relay/helix_launcher.star @@ -0,0 +1,205 @@ +redis_module = import_module("github.com/kurtosis-tech/redis-package/main.star") +postgres_module = import_module("github.com/kurtosis-tech/postgres-package/main.star") +constants = import_module("../../package_io/constants.star") +shared_utils = import_module("../../shared_utils/shared_utils.star") +static_files = import_module("../../static_files/static_files.star") + +# Misc constants +SERVICE_NAME="helix-relay" +HELIX_CONFIG_FILENAME="helix-config.yaml" +HELIX_NETWORK_CONFIG_FILENAME = "network-config.yaml" +HELIX_CONFIG_MOUNT_DIRPATH_ON_SERVICE="/config" + +# The secret key and public key for the relay, exposed as environment variables +DUMMY_SECRET_KEY = "0x607a11b45a7219cc61a3d9c5fd08c7eebd602a6a19a977f8d3771d5711a550f2" +DUMMY_PUB_KEY = "0xa55c1285d84ba83a5ad26420cd5ad3091e49c55a813eee651cd467db38a8c8e63192f47955e9376f6b42f6d190571cb5" + +# This is currenlty hardcoded in the Helix relay +HELIX_RELAY_ENDPOINT_PORT = 4040 + +# The min/max CPU/memory that mev-relay can use +RELAY_MIN_CPU = 2000 # 2 cores +RELAY_MAX_CPU = 4000 # 2 cores +RELAY_MIN_MEMORY = 128 +RELAY_MAX_MEMORY = 1024 + +# The min/max CPU/memory that postgres can use +POSTGRES_MIN_CPU = 10 +POSTGRES_MAX_CPU = 1000 +POSTGRES_MIN_MEMORY = 32 +POSTGRES_MAX_MEMORY = 1024 + +# The min/max CPU/memory that redis can use +REDIS_MIN_CPU = 10 +REDIS_MAX_CPU = 1000 +REDIS_MIN_MEMORY = 16 +REDIS_MAX_MEMORY = 1024 + + +def launch_helix_relay( + plan, + mev_params, + network_params, + beacon_uris, + validator_root, + builder_uri, + seconds_per_slot, + persistent, + genesis_timestamp, + global_node_selectors, +): + plan.print(network_params) + + node_selectors = global_node_selectors + + # Read the template files with Helix configuration and network configuration + helix_config_template = read_file( + static_files.HELIX_CONFIG_TEMPLATE_FILEPATH + ) + helix_network_config_template = read_file( + static_files.HELIX_NETWORK_CONFIG_TEMPLATE_FILEPATH + ) + + # Start both the Redis and Postgres services + redis = redis_module.run( + plan, + service_name="mev-relay-redis", + min_cpu=REDIS_MIN_CPU, + max_cpu=REDIS_MAX_CPU, + min_memory=REDIS_MIN_MEMORY, + max_memory=REDIS_MAX_MEMORY, + node_selectors=node_selectors, + ) + postgres = postgres_module.run( + plan, + # Postgres image with TimescaleDB extension: + # References: + # - https://docs.timescale.com/ + # - https://github.com/gattaca-com/helix/blob/9e078f1ec4710869b2e41e1ca20d31e1c7cfde52/crates/database/src/postgres/postgres_db_service_tests.rs#L41-L44 + image="timescale/timescaledb-ha:pg16", + password="postgres", + user="postgres", + database="postgres", + service_name="helix-postgres", + persistent=persistent, + launch_adminer=True, + min_cpu=POSTGRES_MIN_CPU, + max_cpu=POSTGRES_MAX_CPU, + min_memory=POSTGRES_MIN_MEMORY, + max_memory=POSTGRES_MAX_MEMORY, + node_selectors=node_selectors, + ) + + image = mev_params.helix_relay_image + + # Convert beacon_uris from a comma-separated string to a list of URIs + beacon_uris = [uri.strip() for uri in beacon_uris.split(",")] + + network_config_dir_path_on_service = "{0}/{1}".format( + HELIX_CONFIG_MOUNT_DIRPATH_ON_SERVICE, HELIX_NETWORK_CONFIG_FILENAME + ) + + # See https://github.com/kurtosis-tech/postgres-package#use-this-package-in-your-package + # and https://docs.kurtosis.com/api-reference/starlark-reference/service/ + helix_config_template_data = new_config_template_data( + postgres.service.hostname, + postgres.port.number, + postgres.database, + postgres.user, + postgres.password, + redis.url, + builder_uri, + beacon_uris, + network_config_dir_path_on_service, + validator_root, + genesis_timestamp, + ) + + helix_config_template_and_data = shared_utils.new_template_and_data( + helix_config_template, helix_config_template_data + ) + + helix_network_config_template_and_data = shared_utils.new_template_and_data( + helix_network_config_template, network_params + ) + template_and_data_by_rel_dest_filepath = {} + template_and_data_by_rel_dest_filepath[HELIX_CONFIG_FILENAME] = helix_config_template_and_data + template_and_data_by_rel_dest_filepath[HELIX_NETWORK_CONFIG_FILENAME] = helix_network_config_template_and_data + + config_files_artifact_name = plan.render_templates( + template_and_data_by_rel_dest_filepath + ) + + env_vars = { + "RELAY_KEY": DUMMY_SECRET_KEY, + "RUST_LOG": "debug", + } + + helix = plan.add_service( + name=SERVICE_NAME, + config=ServiceConfig( + image=image, + files={ + HELIX_CONFIG_MOUNT_DIRPATH_ON_SERVICE: config_files_artifact_name + }, + cmd=[ + "--config", + shared_utils.path_join( + HELIX_CONFIG_MOUNT_DIRPATH_ON_SERVICE, + HELIX_CONFIG_FILENAME, + ) + ], + ports={ + "api": PortSpec( + number=HELIX_RELAY_ENDPOINT_PORT, transport_protocol="TCP" + ) + }, + env_vars=env_vars, + min_cpu=RELAY_MIN_CPU, + max_cpu=RELAY_MAX_CPU, + min_memory=RELAY_MIN_MEMORY, + max_memory=RELAY_MAX_MEMORY, + node_selectors=node_selectors, + ), + ) + + return "http://{0}@{1}:{2}".format( + DUMMY_PUB_KEY, helix.ip_address, HELIX_RELAY_ENDPOINT_PORT + ) + +def new_config_template_data( + postgres_hostname, + postgres_port, + postgres_db_name, + postgres_user, + postgres_password, + redis_url, + blocksim_url, + beacon_uris, + network_config_dir_path, + genesis_validator_root, + genesis_time, +): + return { + "PostgresConfig": { + "hostname": postgres_hostname, + "port": postgres_port, + "db_name": postgres_db_name, + "user": postgres_user, + "password": postgres_password, + }, + "RedisConfig": { + "url": redis_url, + }, + "BlockSimulatorConfig": { + "url": blocksim_url, + }, + "BeaconClientsConfig": [ + {"url": uri} for uri in beacon_uris + ], + "NetworkConfig": { + "dir_path": network_config_dir_path, + "genesis_validator_root": genesis_validator_root, + "genesis_time": genesis_time, + }, + } diff --git a/src/mev/mev_sidecar/mev_sidecar_launcher.star b/src/mev/mev_sidecar/mev_sidecar_launcher.star index 1d45fa4ed..9dfb3ef37 100644 --- a/src/mev/mev_sidecar/mev_sidecar_launcher.star +++ b/src/mev/mev_sidecar/mev_sidecar_launcher.star @@ -42,9 +42,9 @@ def launch_mev_sidecar( "--private-key", # Random private key for testing, generated with `openssl rand -hex 32` "18d1c5302e734fd6fbfaa51828d42c4c6d3cbe020c42bab7dd15a2799cf00b82", - "--mevboost-url", + "--constraints-url", mev_boost_context_util.mev_boost_endpoint(mev_boost_context), - "--mevboost-proxy-port", + "--constraints-proxy-port", str(MEV_SIDECAR_BOOST_PROXY_PORT), "--beacon-api-url", beacon_api_url, diff --git a/src/package_io/input_parser.star b/src/package_io/input_parser.star index 0697750dc..b59141d8d 100644 --- a/src/package_io/input_parser.star +++ b/src/package_io/input_parser.star @@ -237,6 +237,7 @@ def input_parser(plan, input_args): preset=result["network_params"]["preset"], ), mev_params=struct( + helix_relay_image=result["mev_params"]["helix_relay_image"], mev_relay_image=result["mev_params"]["mev_relay_image"], mev_builder_image=result["mev_params"]["mev_builder_image"], mev_builder_cl_image=result["mev_params"]["mev_builder_cl_image"], diff --git a/src/static_files/static_files.star b/src/static_files/static_files.star index 98d2c838e..250e6c275 100644 --- a/src/static_files/static_files.star +++ b/src/static_files/static_files.star @@ -31,6 +31,16 @@ ASSERTOOR_TESTS_CONFIG_DIRPATH = ( STATIC_FILES_DIRPATH + ASSERTOOR_CONFIG_DIRPATH + "/tests" ) +# helix config +HELIX_CONFIG_DIRPATH = "/helix-relay-config" +HELIX_CONFIG_FULL_DIRPATH = ( + STATIC_FILES_DIRPATH + HELIX_CONFIG_DIRPATH +) +HELIX_CONFIG_TEMPLATE_FILEPATH = ( + STATIC_FILES_DIRPATH + HELIX_CONFIG_DIRPATH + "/config.yaml.tmpl" +) +HELIX_NETWORK_CONFIG_TEMPLATE_FILEPATH=HELIX_CONFIG_FULL_DIRPATH + "/network-config.yaml.tmpl" + # xatu-sentry config XATU_SENTRY_CONFIG_DIRPATH = "/xatu-sentry-config" XATU_SENTRY_CONFIG_TEMPLATE_FILEPATH = ( diff --git a/static_files/helix-relay-config/config.yaml.tmpl b/static_files/helix-relay-config/config.yaml.tmpl new file mode 100644 index 000000000..538bfd16d --- /dev/null +++ b/static_files/helix-relay-config/config.yaml.tmpl @@ -0,0 +1,23 @@ +postgres: + hostname: {{ .PostgresConfig.hostname }} + port: {{ .PostgresConfig.port }} + db_name: {{ .PostgresConfig.db_name }} + user: {{ .PostgresConfig.user }} + password: {{ .PostgresConfig.password }} + +redis: + url: {{ .RedisConfig.url }} + +simulator: + url: {{ .BlockSimulatorConfig.url }} + +beacon_clients: + {{ range $bcConfig := .BeaconClientsConfig }} + - url: "{{ $bcConfig.url }}" + {{- end }} + +network_config: + !Custom # this is a custom enum type and requies a '!' + dir_path: {{ .NetworkConfig.dir_path }} + genesis_validator_root: {{ .NetworkConfig.genesis_validator_root }} + genesis_time: {{ .NetworkConfig.genesis_time }} diff --git a/static_files/helix-relay-config/network-config.yaml.tmpl b/static_files/helix-relay-config/network-config.yaml.tmpl new file mode 100644 index 000000000..2bcaee005 --- /dev/null +++ b/static_files/helix-relay-config/network-config.yaml.tmpl @@ -0,0 +1,35 @@ +# The preset for the network configuration. +# Needed for `NetworkConfig` inside Helix + +PRESET_BASE: {{ .preset }} +CONFIG_NAME: "mainnet" +TERMINAL_TOTAL_DIFFICULTY: 0 +TERMINAL_BLOCK_HASH: "0x0000000000000000000000000000000000000000000000000000000000000000" +TERMINAL_BLOCK_HASH_ACTIVATION_EPOCH: 18446744073709551615 +MIN_GENESIS_ACTIVE_VALIDATOR_COUNT: 2 +MIN_GENESIS_TIME: 1727185220 +GENESIS_FORK_VERSION: "0x10000038" +GENESIS_DELAY: 20 +ALTAIR_FORK_VERSION: "0x20000038" +ALTAIR_FORK_EPOCH: 0 +BELLATRIX_FORK_VERSION: "0x30000038" +BELLATRIX_FORK_EPOCH: 0 +CAPELLA_FORK_VERSION: "0x40000038" +CAPELLA_FORK_EPOCH: 0 +DENEB_FORK_VERSION: "0x50000038" +DENEB_FORK_EPOCH: 0 +SECONDS_PER_SLOT: {{ .seconds_per_slot }} +SECONDS_PER_ETH1_BLOCK: {{ .seconds_per_slot }} +MIN_VALIDATOR_WITHDRAWABILITY_DELAY: {{ .min_validator_withdrawability_delay }} +SHARD_COMMITTEE_PERIOD: {{ .shard_committee_period }} +ETH1_FOLLOW_DISTANCE: {{ .eth1_follow_distance }} +INACTIVITY_SCORE_BIAS: 4 +INACTIVITY_SCORE_RECOVERY_RATE: 16 +EJECTION_BALANCE: {{ .ejection_balance }} +MIN_PER_EPOCH_CHURN_LIMIT: 4 +MAX_PER_EPOCH_ACTIVATION_CHURN_LIMIT: {{ .max_churn }} +CHURN_LIMIT_QUOTIENT: 65536 +PROPOSER_SCORE_BOOST: 40 +DEPOSIT_CHAIN_ID: {{ .network_id }} +DEPOSIT_NETWORK_ID: {{ .network_id }} +DEPOSIT_CONTRACT_ADDRESS: {{ .deposit_contract_address }}