From 23628b27a8d571df1c90c5cbe84455c7382e091c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20Chodo=C5=82a?= <43241881+kamilchodola@users.noreply.github.com> Date: Wed, 20 Sep 2023 16:48:37 +0200 Subject: [PATCH] feat: Add Tx_spamer_params and move MEV to the bottom of main.star (#208) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PR adds a possibility to push custom params to Tx_Spammer. tested with flag --txcount=100 - Looking at Tx_Spammer logs change is applied. Also addressing #168 --------- Co-authored-by: Kamil ChodoĊ‚a --- README.md | 6 ++ main.star | 94 ++++++++++--------- src/package_io/parse_input.star | 12 ++- .../transaction_spammer.star | 10 +- 4 files changed, 71 insertions(+), 51 deletions(-) diff --git a/README.md b/README.md index 0b73058aa..96d776c76 100644 --- a/README.md +++ b/README.md @@ -202,6 +202,12 @@ To configure the package behaviour, you can modify your `network_params.json` fi "deneb_fork_epoch": 4, "electra_fork_epoch": null, }, + + // Configuration place for transaction spammer - https://github.com/MariusVanDerWijden/tx-fuzz + "tx_spammer_params": { + // A list of optional extra params that will be passed to the TX Spammer container for modifying its behaviour + "tx_spammer_extra_args": [] + } // True by defaults such that in addition to the Ethereum network: // - A transaction spammer is launched to fake transactions sent to the network diff --git a/main.star b/main.star index a7553fe2b..7e23a9646 100644 --- a/main.star +++ b/main.star @@ -52,57 +52,14 @@ def run(plan, args = {}): for participant in all_participants: all_el_client_contexts.append(participant.el_client_context) all_cl_client_contexts.append(participant.cl_client_context) - - - mev_endpoints = [] - # 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: - mev_endpoints = participant.builder_network_params.relay_end_points - # otherwise dummy relays spinup if chosen - elif args_with_right_defaults.mev_type and args_with_right_defaults.mev_type == MOCK_MEV_TYPE: - el_uri = "{0}:{1}".format(all_el_client_contexts[0].ip_addr, all_el_client_contexts[0].engine_rpc_port_num) - 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, args_with_right_defaults.global_client_log_level) - 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, genesis_constants.PRE_FUNDED_ACCOUNTS) - epoch_recipe = GetHttpRequestRecipe( - endpoint = "/eth/v2/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, network_params.seconds_per_slot, network_params.slots_per_epoch) - mev_flood_module.spam_in_background(plan, el_uri, mev_params.mev_flood_extra_args, mev_params.mev_flood_seconds_per_bundle, genesis_constants.PRE_FUNDED_ACCOUNTS) - if args_with_right_defaults.mev_params.launch_custom_flood: - mev_custom_flood_module.spam_in_background(plan, genesis_constants.PRE_FUNDED_ACCOUNTS[-1].private_key, genesis_constants.PRE_FUNDED_ACCOUNTS[0].address, el_uri) - mev_endpoints.append(endpoint) - - # spin up the mev boost contexts if some endpoints for relays have been passed - all_mevboost_contexts = [] - if mev_endpoints: - for index, participant in enumerate(all_participants): - mev_boost_launcher = mev_boost_launcher_module.new_mev_boost_launcher(MEV_BOOST_SHOULD_CHECK_RELAY, mev_endpoints) - mev_boost_service_name = "{0}{1}".format(parse_input.MEV_BOOST_SERVICE_NAME_PREFIX, index) - mev_boost_context = mev_boost_launcher_module.launch(plan, mev_boost_launcher, mev_boost_service_name, network_params.network_id, mev_params.mev_boost_image) - all_mevboost_contexts.append(mev_boost_context) + if not args_with_right_defaults.launch_additional_services: return plan.print("Launching transaction spammer") - transaction_spammer.launch_transaction_spammer(plan, genesis_constants.PRE_FUNDED_ACCOUNTS, all_el_client_contexts[0]) + tx_spammer_params = args_with_right_defaults.tx_spammer_params + transaction_spammer.launch_transaction_spammer(plan, genesis_constants.PRE_FUNDED_ACCOUNTS, all_el_client_contexts[0], tx_spammer_params) plan.print("Succesfully launched transaction spammer") plan.print("Launching Blob spammer") @@ -184,4 +141,49 @@ def run(plan, args = {}): ) output = struct(grafana_info = grafana_info) + + mev_endpoints = [] + # 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: + mev_endpoints = participant.builder_network_params.relay_end_points + # otherwise dummy relays spinup if chosen + elif args_with_right_defaults.mev_type and args_with_right_defaults.mev_type == MOCK_MEV_TYPE: + el_uri = "{0}:{1}".format(all_el_client_contexts[0].ip_addr, all_el_client_contexts[0].engine_rpc_port_num) + 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, args_with_right_defaults.global_client_log_level) + 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, genesis_constants.PRE_FUNDED_ACCOUNTS) + epoch_recipe = GetHttpRequestRecipe( + endpoint = "/eth/v2/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, network_params.seconds_per_slot, network_params.slots_per_epoch) + mev_flood_module.spam_in_background(plan, el_uri, mev_params.mev_flood_extra_args, mev_params.mev_flood_seconds_per_bundle, genesis_constants.PRE_FUNDED_ACCOUNTS) + if args_with_right_defaults.mev_params.launch_custom_flood: + mev_custom_flood_module.spam_in_background(plan, genesis_constants.PRE_FUNDED_ACCOUNTS[-1].private_key, genesis_constants.PRE_FUNDED_ACCOUNTS[0].address, el_uri) + mev_endpoints.append(endpoint) + + # spin up the mev boost contexts if some endpoints for relays have been passed + all_mevboost_contexts = [] + if mev_endpoints: + for index, participant in enumerate(all_participants): + mev_boost_launcher = mev_boost_launcher_module.new_mev_boost_launcher(MEV_BOOST_SHOULD_CHECK_RELAY, mev_endpoints) + mev_boost_service_name = "{0}{1}".format(parse_input.MEV_BOOST_SERVICE_NAME_PREFIX, index) + mev_boost_context = mev_boost_launcher_module.launch(plan, mev_boost_launcher, mev_boost_service_name, network_params.network_id, mev_params.mev_boost_image) + all_mevboost_contexts.append(mev_boost_context) + return output diff --git a/src/package_io/parse_input.star b/src/package_io/parse_input.star index bbc7cdfa8..37a3c363d 100644 --- a/src/package_io/parse_input.star +++ b/src/package_io/parse_input.star @@ -2,7 +2,7 @@ FLASHBOTS_MEV_BOOST_PORT = 18550 MEV_BOOST_SERVICE_NAME_PREFIX = "mev-boost-" -ATTR_TO_BE_SKIPPED_AT_ROOT = ("network_params", "participants", "mev_params") +ATTR_TO_BE_SKIPPED_AT_ROOT = ("network_params", "participants", "mev_params", "tx_spammer_params") package_io_constants = import_module("github.com/kurtosis-tech/eth-network-package/package_io/constants.star") package_io_parser = import_module("github.com/kurtosis-tech/eth-network-package/package_io/input_parser.star") @@ -35,6 +35,8 @@ def parse_input(plan, input_args): if result.get("mev_type") == "full" and result["network_params"]["capella_fork_epoch"] == 0: fail("capella_fork_epoch needs to be set to a non-zero value when using full MEV, set it using network_params.capella_fork_epoch") + result["tx_spammer_params"] = get_default_tx_spammer_params() + return struct( participants=[struct( el_client_type=participant["el_client_type"], @@ -73,6 +75,9 @@ def parse_input(plan, input_args): mev_flood_seconds_per_bundle = result["mev_params"]["mev_flood_seconds_per_bundle"], launch_custom_flood = result["mev_params"]["launch_custom_flood"], ), + tx_spammer_params = struct( + tx_spammer_extra_args = result["tx_spammer_params"]["tx_spammer_extra_args"], + ), launch_additional_services=result["launch_additional_services"], wait_for_finalization=result["wait_for_finalization"], wait_for_verifications=result["wait_for_verifications"], @@ -98,6 +103,11 @@ def get_default_mev_params(): "launch_custom_flood": False } +def get_default_tx_spammer_params(): + return { + "tx_spammer_extra_args": [] + } + # 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"]): diff --git a/src/transaction_spammer/transaction_spammer.star b/src/transaction_spammer/transaction_spammer.star index 58657d8f0..15a56c1f5 100644 --- a/src/transaction_spammer/transaction_spammer.star +++ b/src/transaction_spammer/transaction_spammer.star @@ -1,18 +1,20 @@ +#TODO: Add Image and Service Name to tx_spammer_params IMAGE_NAME = "ethpandaops/tx-fuzz:latest" SERVICE_NAME = "transaction-spammer" -def launch_transaction_spammer(plan, prefunded_addresses, el_client_context): - config = get_config(prefunded_addresses, el_client_context) +def launch_transaction_spammer(plan, prefunded_addresses, el_client_context, tx_spammer_params): + config = get_config(prefunded_addresses, el_client_context, tx_spammer_params.tx_spammer_extra_args) plan.add_service(SERVICE_NAME, config) -def get_config(prefunded_addresses, el_client_context): +def get_config(prefunded_addresses, el_client_context, tx_spammer_extra_args): return ServiceConfig( image = IMAGE_NAME, cmd = [ "spam", "--rpc=http://{0}:{1}".format(el_client_context.ip_addr, el_client_context.rpc_port_num), - "--sk={0}".format(prefunded_addresses[3].private_key), + "--sk={0}".format(prefunded_addresses[0].private_key), + "{0}".format(" ".join(tx_spammer_extra_args)) ] )