Skip to content

Commit

Permalink
feat: support full MEV (#115)
Browse files Browse the repository at this point in the history
There are some immediate FLUPs here

1. Replace `h4ck3rk3y/builder` with `flashbots/builder` ( pending
publishing of builder)
2. Replace `h4ck3rk3y/mev-boost-relay` with `flashbots/mev-boost-relay`
(pending Capella signature fix)
  • Loading branch information
h4ck3rk3y committed Aug 15, 2023
1 parent 373c6c9 commit e9e8c41
Show file tree
Hide file tree
Showing 6 changed files with 214 additions and 14 deletions.
21 changes: 20 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,26 @@ To configure the package behaviour, you can modify your `eth2-package-params.yam
// Default: None - no mev boost, mev builder, mev flood or relays are spun up
// mock - mock-builder & mev-boost are spun up
// full - mev-boost, relays, flooder and builder are all spun up
"mev_type": None
"mev_type": None,
// Parameters if MEV is used
"mev_params": {
// The image to use for MEV boot relay
// This uses the h4ck3rk3y image instead of the flashbots image as that isn't published yet
"mev_relay_image": "h4ck3rk3y/mev-boost-relay",
// Extra parameters to send to the API
"mev_relay_api_extra_args": [],
// Extra parameters to send to the housekeeper
"mev_relay_housekeeper_extra_args": [],
// Extra parameters to send to the website
"mev_relay_website_extra_args": [],
// Extra parameters to send to the builder
"mev_builder_extra_args": [],
// Image to use for mev-flood
"mev_flood_image": "flashbots/mev-flood",
// Extra parameters to send to mev-flood
"mev_flood_extra_args": []
}
}
```
Expand Down
28 changes: 27 additions & 1 deletion main.star
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ grafana =import_module("github.com/kurtosis-tech/eth2-package/src/grafana/grafan
testnet_verifier = import_module("github.com/kurtosis-tech/eth2-package/src/testnet_verifier/testnet_verifier.star")
mev_boost_launcher_module = import_module("github.com/kurtosis-tech/eth2-package/src/mev_boost/mev_boost_launcher.star")
mock_mev_launcher_module = import_module("github.com/kurtosis-tech/eth2-package/src/mock_mev/mock_mev_launcher.star")
mev_relay_launcher_module = import_module("github.com/kurtosis-tech/eth2-package/src/mev_relay/mev_relay_launcher.star")
mev_flood_module = import_module("github.com/kurtosis-tech/eth2-package/src/mev_flood/mev_flood_launcher.star")

GRAFANA_USER = "admin"
GRAFANA_PASSWORD = "admin"
Expand All @@ -23,12 +25,15 @@ HTTP_PORT_ID_FOR_FACT = "http"

MEV_BOOST_SHOULD_CHECK_RELAY = True
MOCK_MEV_TYPE = "mock"
FULL_MEV_TYPE = "full"
PATH_TO_PARSED_BEACON_STATE = "/genesis/output/parsedBeaconState.json"

def run(plan, args):
args_with_right_defaults, args_with_defaults_dict = parse_input.parse_input(args)

num_participants = len(args_with_right_defaults.participants)
network_params = args_with_right_defaults.network_params
mev_params = args_with_right_defaults.mev_params

grafana_datasource_config_template = read_file(static_files.GRAFANA_DATASOURCE_CONFIG_TEMPLATE_FILEPATH)
grafana_dashboards_config_template = read_file(static_files.GRAFANA_DASHBOARD_PROVIDERS_CONFIG_TEMPLATE_FILEPATH)
Expand All @@ -37,7 +42,7 @@ def run(plan, args):
plan.print("Read the prometheus, grafana templates")

plan.print("Launching participant network with {0} participants and the following network params {1}".format(num_participants, network_params))
all_participants, cl_genesis_timestamp, _ = eth_network_module.run(plan, args_with_defaults_dict)
all_participants, cl_genesis_timestamp, genesis_validators_root = eth_network_module.run(plan, args_with_defaults_dict)

all_el_client_contexts = []
all_cl_client_contexts = []
Expand All @@ -57,8 +62,29 @@ def run(plan, args):
beacon_uri = "{0}:{1}".format(all_cl_client_contexts[0].ip_addr, all_cl_client_contexts[0].http_port_num)
jwt_secret = all_el_client_contexts[0].jwt_secret
endpoint = mock_mev_launcher_module.launch_mock_mev(plan, el_uri, beacon_uri, jwt_secret)
mev_endpoints.append(endpoint)
elif args_with_right_defaults.mev_type and args_with_right_defaults.mev_type == FULL_MEV_TYPE:
el_uri = "http://{0}:{1}".format(all_el_client_contexts[0].ip_addr, all_el_client_contexts[0].rpc_port_num)
builder_uri = "http://{0}:{1}".format(all_el_client_contexts[-1].ip_addr, all_el_client_contexts[-1].rpc_port_num)
beacon_uri = ["http://{0}:{1}".format(context.ip_addr, context.http_port_num) for context in all_cl_client_contexts][-1]
beacon_uris = beacon_uri
first_cl_client = all_cl_client_contexts[0]
first_client_beacon_name = first_cl_client.beacon_service_name
mev_flood_module.launch_mev_flood(plan, mev_params.mev_flood_image, el_uri)
epoch_recipe = GetHttpRequestRecipe(
endpoint = "/eth/v1/beacon/blocks/head",
port_id = HTTP_PORT_ID_FOR_FACT,
extract = {
"epoch": ".data.message.body.attestations[0].data.target.epoch"
}
)
plan.wait(recipe = epoch_recipe, field = "extract.epoch", assertion = ">=", target_value = str(network_params.capella_fork_epoch), timeout = "20m", service_name = first_client_beacon_name)
plan.print("epoch 2 reached, can begin mev stuff")
endpoint = mev_relay_launcher_module.launch_mev_relay(plan, mev_params, network_params.network_id, beacon_uris, genesis_validators_root, builder_uri)
mev_flood_module.spam_in_background(plan, el_uri, mev_params.mev_flood_extra_args)
mev_endpoints.append(endpoint)


# spin up the mev boost contexts if some endpoints for relays have been passed
all_mevboost_contexts = []
if mev_endpoints:
Expand Down
7 changes: 5 additions & 2 deletions src/mev_boost/mev_boost_launcher.star
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,14 @@ def get_config(mev_boost_launcher, network_id):
ports = USED_PORTS,
cmd = command,
env_vars = {
# TODO remove the hardcoding
# TODO(maybe) remove the hardcoding
# This is set to match this file https://github.com/kurtosis-tech/eth-network-package/blob/main/static_files/genesis-generation-config/cl/config.yaml.tmpl#L11
# latest-notes
# does this need genesis time to be set as well
"GENESIS_FORK_VERSION": "0x10000038",
"BOOST_LISTEN_ADDR": "0.0.0.0:{0}".format(parse_input.FLASHBOTS_MEV_BOOST_PORT),
"SKIP_RELAY_SIGNATURE_CHECK": "true",
# maybe this is breaking; this isn't verifyign the bid and not sending it to the validator
"SKIP_RELAY_SIGNATURE_CHECK": "1",
"RELAYS": mev_boost_launcher.relay_end_points[0]
}
)
Expand Down
30 changes: 30 additions & 0 deletions src/mev_flood/mev_flood_launcher.star
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
ADMIN_KEY = "0xef5177cd0b6b21c87db5a0bf35d4084a8a57a9d6a064f86d51ac85f2b873a4e2"
USER_KEY = "0x7988b3a148716ff800414935b305436493e1f25237a2a03e5eebc343735e2f31"

def launch_mev_flood(plan, image, el_uri):
plan.add_service(
name = "mev-flood",
config = ServiceConfig(
image = image,
entrypoint = ["/bin/sh", "-c", "touch main.log && tail -F main.log"]
)
)

plan.exec(
service_name = "mev-flood",
recipe = ExecRecipe(
command = ["/bin/sh", "-c", "./run init -r {0} -k {1} -u {2} -s deployment.json".format(el_uri, ADMIN_KEY, USER_KEY)]
)
)

def spam_in_background(plan, el_uri, mev_flood_extra_args):
command = ["/bin/sh", "-c", "nohup ./run spam -r {0} -k {1} -u {2} -l deployment.json --secondsPerBundle 15 >main.log 2>&1 &".format(el_uri, ADMIN_KEY, USER_KEY)]
if mev_flood_extra_args:
joined_extra_args = " ".join(mev_flood_extra_args)
command = ["/bin/sh", "-c", "nohup ./run spam -r {0} -k {1} -u {2} -l deployment.json --secondsPerBundle 15 {3} >main.log 2>&1 &".format(el_uri, ADMIN_KEY, USER_KEY, joined_extra_args)]
plan.exec(
service_name = "mev-flood",
recipe = ExecRecipe(
command = command
)
)
71 changes: 71 additions & 0 deletions src/mev_relay/mev_relay_launcher.star
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
redis_module = import_module("github.com/kurtosis-tech/redis-package/main.star")
postgres_module = import_module("github.com/kurtosis-tech/postgres-package/main.star")

DUMMY_SECRET_KEY = "0x607a11b45a7219cc61a3d9c5fd08c7eebd602a6a19a977f8d3771d5711a550f2"
DUMMY_PUB_KEY = "0xa55c1285d84ba83a5ad26420cd5ad3091e49c55a813eee651cd467db38a8c8e63192f47955e9376f6b42f6d190571cb5"

MEV_RELAY_WEBSITE = "mev-relay-website"
MEV_RELAY_ENDPOINT = "mev-relay-api"
MEV_RELAY_HOUSEKEEPER = "mev-relay-housekeeper"

MEV_RELAY_ENDPOINT_PORT = 9062
MEV_RELAY_WEBSITE_PORT = 9060

NETWORK_ID_TO_NAME = {
"5": "goerli",
"11155111": "sepolia",
"3": "ropsten",
}

def launch_mev_relay(plan, mev_params, network_id, beacon_uris, validator_root, builder_uri):
redis = redis_module.run(plan, {})
# making the password postgres as the relay expects it to be postgres
postgres = postgres_module.run(plan, {"password": "postgres", "user": "postgres", "database": "postgres", "name": "postgres"})

network_name = NETWORK_ID_TO_NAME.get(network_id, network_id)

image = mev_params.mev_relay_image

# TODO(maybe) remove hardocded values for the forks
env_vars= {
"GENESIS_FORK_VERSION": "0x10000038",
"BELLATRIX_FORK_VERSION": "0x30000038",
"CAPELLA_FORK_VERSION": "0x40000038",
"DENEB_FORK_VERSION": "0x50000038",
"GENESIS_VALIDATORS_ROOT": validator_root
}

plan.add_service(
name = MEV_RELAY_HOUSEKEEPER,
config = ServiceConfig(
image = image,
cmd = ["housekeeper", "--network", "custom", "--db", "postgres://postgres:postgres@postgres:5432/postgres?sslmode=disable", "--redis-uri", "redis:6379", "--beacon-uris", beacon_uris] + mev_params.mev_relay_housekeeper_extra_args,
env_vars= env_vars
)
)

api = plan.add_service(
name = MEV_RELAY_ENDPOINT,
config = ServiceConfig(
image = image,
cmd = ["api", "--network", "custom", "--db", "postgres://postgres:postgres@postgres:5432/postgres?sslmode=disable", "--secret-key", DUMMY_SECRET_KEY, "--listen-addr", "0.0.0.0:{0}".format(MEV_RELAY_ENDPOINT_PORT), "--redis-uri", "redis:6379", "--beacon-uris", beacon_uris, "--blocksim", builder_uri] + mev_params.mev_relay_api_extra_args,
ports = {
"api": PortSpec(number = MEV_RELAY_ENDPOINT_PORT, transport_protocol= "TCP")
},
env_vars= env_vars
)
)

plan.add_service(
name = MEV_RELAY_WEBSITE,
config = ServiceConfig(
image = image,
cmd = ["website", "--network", "custom", "--db", "postgres://postgres:postgres@postgres:5432/postgres?sslmode=disable", "--listen-addr", "0.0.0.0:{0}".format(MEV_RELAY_WEBSITE_PORT), "--redis-uri", "redis:6379", "https://{0}@{1}".format(DUMMY_PUB_KEY, MEV_RELAY_ENDPOINT)] + mev_params.mev_relay_website_extra_args,
ports = {
"api": PortSpec(number = MEV_RELAY_WEBSITE_PORT, transport_protocol= "TCP", application_protocol="http")
},
env_vars= env_vars
)
)

return "http://{0}@{1}:{2}".format(DUMMY_PUB_KEY, api.ip_address, MEV_RELAY_ENDPOINT_PORT)
71 changes: 61 additions & 10 deletions src/package_io/parse_input.star
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ FLASHBOTS_MEV_BOOST_PORT = 18550
MEV_BOOST_SERVICE_NAME_PREFIX = "mev-boost-"


package_io = import_module("github.com/kurtosis-tech/eth-network-package/package_io/constants.star")

def parse_input(input_args):
result = default_input_args()
for attr in input_args:
Expand All @@ -35,6 +37,10 @@ def parse_input(input_args):
for sub_attr in input_args["network_params"]:
sub_value = input_args["network_params"][sub_attr]
result["network_params"][sub_attr] = sub_value
elif attr == "mev_params":
for sub_attr in input_args["mev_params"]:
sub_value = input_args["mev_params"]["sub_attr"]
result["mev_params"][sub_attr] = sub_value
elif attr == "participants":
participants = []
for participant in input_args["participants"]:
Expand Down Expand Up @@ -139,6 +145,15 @@ def parse_input(input_args):
deneb_fork_epoch=result["network_params"]["deneb_fork_epoch"],
genesis_delay=result["network_params"]["genesis_delay"]
),
mev_params = struct(
mev_relay_image = result["mev_params"]["mev_relay_image"],
mev_relay_api_extra_args = result["mev_params"]["mev_relay_api_extra_args"],
mev_relay_housekeeper_extra_args = result["mev_params"]["mev_relay_housekeeper_extra_args"],
mev_relay_website_extra_args = result["mev_params"]["mev_relay_website_extra_args"],
mev_builder_extra_args = result["mev_params"]["mev_builder_extra_args"],
mev_flood_image = result["mev_params"]["mev_flood_image"],
mev_flood_extra_args = result["mev_params"]["mev_flood_extra_args"]
),
launch_additional_services=result["launch_additional_services"],
wait_for_finalization=result["wait_for_finalization"],
wait_for_verifications=result["wait_for_verifications"],
Expand All @@ -158,6 +173,7 @@ def get_client_log_level_or_default(participant_log_level, global_log_level, cli
def default_input_args():
network_params = default_network_params()
participants = [default_participant()]
mev_params = get_default_mev_params()
return {
"mev_type": None,
"participants": participants,
Expand All @@ -167,26 +183,26 @@ def default_input_args():
"wait_for_verifications": False,
"verifications_epoch_limit": 5,
"global_client_log_level": "info",
"mev_params": mev_params,
"snooper_enabled": False,
}

def default_network_params():
# this is temporary till we get params working
return {
"preregistered_validator_keys_mnemonic": "giant issue aisle success illegal bike spike question tent bar rely arctic volcano long crawl hungry vocal artwork sniff fantasy very lucky have athlete",
"num_validator_keys_per_node": 64,
"network_id": "3151908",
"deposit_contract_address": "0x4242424242424242424242424242424242424242",
"seconds_per_slot": 12,
"slots_per_epoch": 32,
"genesis_delay": 120,
"capella_fork_epoch": 1,
# arbitrarily large while we sort out https://github.com/kurtosis-tech/eth-network-package/issues/42
# this will take 53~ hoours for now
"deneb_fork_epoch": 500,
"num_validator_keys_per_node": 64,
"network_id": "3151908",
"deposit_contract_address": "0x4242424242424242424242424242424242424242",
"seconds_per_slot": 12,
"slots_per_epoch": 32,
"genesis_delay": 120,
"capella_fork_epoch": 1,
"deneb_fork_epoch": 500
}

def default_participant():
# TODO(now) add support for mev boost image and extra parameters
return {
"el_client_type": "geth",
"el_client_image": "",
Expand All @@ -201,6 +217,18 @@ def default_participant():
"count": 1
}

def get_default_mev_params():
return {
# TODO fix this when Capella Signature verification works - change it to flashbots/
"mev_relay_image": "h4ck3rk3y/mev-boost-relay",
"mev_relay_api_extra_args": [],
"mev_relay_housekeeper_extra_args": [],
"mev_relay_website_extra_args": [],
"mev_builder_extra_args": [],
"mev_flood_image": "flashbots/mev-flood",
"mev_flood_extra_args": []
}


# TODO perhaps clean this up into a map
def enrich_mev_extra_params(parsed_arguments_dict, mev_prefix, mev_port):
Expand All @@ -220,4 +248,27 @@ def enrich_mev_extra_params(parsed_arguments_dict, mev_prefix, mev_port):
if participant["cl_client_type"] == "prysm":
participant["validator_extra_params"].append("--enable-builder")
participant["beacon_extra_params"].append("--http-mev-relay={0}".format(mev_url))

num_participants = len(parsed_arguments_dict["participants"])

mev_url = "http://{0}{1}:{2}".format(mev_prefix, num_participants, mev_port)

mev_participant = {
"el_client_type": "geth",
# TODO replace with actual when flashbots/builder is published
"el_client_image": "h4ck3rk3y/builder",
"el_client_log_level": "",
"cl_client_type": "lighthouse",
# THIS overrides the beacon image
"cl_client_image": "sigp/lighthouse",
"cl_client_log_level": "",
"beacon_extra_params": ["--builder={0}".format(mev_url), "--always-prepare-payload", "--prepare-payload-lookahead", "12000"],
# TODO(maybe) make parts of this more passable like the mev-relay-endpoint & forks
"el_extra_params": ["--builder", "--builder.remote_relay_endpoint=http://mev-relay-api:9062", "--builder.beacon_endpoints=http://cl-{0}-lighthouse-geth:4000".format(num_participants+1), "--builder.bellatrix_fork_version=0x30000038", "--builder.genesis_fork_version=0x10000038", "--builder.genesis_validators_root={0}".format(package_io.GENESIS_VALIDATORS_ROOT_PLACEHOLDER), "--miner.extradata=\"Illuminate Dmocratize Dstribute\"", "--miner.algotype=greedy"] + parsed_arguments_dict["mev_params"]["mev_builder_extra_args"],
"validator_extra_params": ["--builder-proposals"],
"builder_network_params": None
}

parsed_arguments_dict["participants"].append(mev_participant)

return parsed_arguments_dict

0 comments on commit e9e8c41

Please sign in to comment.