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: Add configurable spamming frequency to custom flood #283

Merged
merged 13 commits into from
Oct 16, 2023
10 changes: 9 additions & 1 deletion .circleci/tests/mev.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,15 @@
{
"mev_type": "full",
"additional_services": [
"tx_spammer",
"blob_spammer",
"custom_flood",
"el_forkmon",
"beacon_metrics_gazer",
"dora",
"prometheus_grafana"
],
"mev_params": {
"launch_custom_flood": true,
"mev_relay_image": "flashbots/mev-boost-relay:0.27"
},
"network_params": {
Expand Down
10 changes: 6 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -247,7 +247,8 @@ To configure the package behaviour, you can modify your `network_params.json` fi
"additional_services": [
"tx_spammer",
"blob_spammer",
"goomy_blob"
"custom_flood",
"goomy_blob",
"el_forkmon",
"beacon_metrics_gazer",
"dora",
Expand Down Expand Up @@ -307,9 +308,10 @@ To configure the package behaviour, you can modify your `network_params.json` fi
"mev_flood_extra_args": [],
// Number of seconds between bundles for mev-flood
"mev_flood_seconds_per_bundle": 15,
// A custom flood script that increases the balance of the coinbase addresss leading to more reliable
// payload delivery
"launch_custom_flood": false
// Optional parameters to send to the custom_flood script that sends reliable payloads
"custom_flood_params": {
"interval_between_transactions": 1
}
},
// A list of locators for grafana dashboards to be loaded be the grafana service
"grafana_additional_dashboards": []
Expand Down
1 change: 0 additions & 1 deletion examples/capella-mev.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@
},
"mev_params": {
"mev_flood_seconds_per_bundle": 12,
"launch_custom_flood": false,
"mev_flood_extra_args": [ "--txsPerBundle=300" ],
"mev_flood_image": "flashbots/mev-flood:0.0.9",
"mev_relay_image": "flashbots/mev-boost-relay:0.27.0"
Expand Down
15 changes: 8 additions & 7 deletions main.star
Original file line number Diff line number Diff line change
Expand Up @@ -190,13 +190,6 @@ def run(plan, 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
Expand Down Expand Up @@ -313,6 +306,14 @@ def run(plan, args={}):
elif additional_service == "prometheus_grafana":
# Allow prometheus to be launched last so is able to collect metrics from other services
launch_prometheus_grafana = True
elif additional_service == "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,
args_with_right_defaults.custom_flood_params,
)
else:
fail("Invalid additional service %s" % (additional_service))
if launch_prometheus_grafana:
Expand Down
3 changes: 1 addition & 2 deletions network_params.json
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,7 @@
"mev_builder_extra_args": [],
"mev_flood_image": "flashbots/mev-flood",
"mev_flood_extra_args": [],
"mev_flood_seconds_per_bundle": 15,
"launch_custom_flood": false
"mev_flood_seconds_per_bundle": 15
},
"grafana_additional_dashboards": []
}
12 changes: 9 additions & 3 deletions src/mev_custom_flood/mev_custom_flood_launcher.star
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ PYTHON_IMAGE = "python:3.11-alpine"
CUSTOM_FLOOD_SERVICE_NAME = "mev-custom-flood"


def spam_in_background(plan, sender_key, receiver_key, el_uri):
def spam_in_background(plan, sender_key, receiver_key, el_uri, params):
sender_script = plan.upload_files("./sender.py")

plan.add_service(
Expand All @@ -21,12 +21,18 @@ def spam_in_background(plan, sender_key, receiver_key, el_uri):

plan.exec(
service_name=CUSTOM_FLOOD_SERVICE_NAME,
recipe=ExecRecipe(["pip", "install", "web3"]),
recipe=ExecRecipe(["pip", "install", "web3", "click"]),
)

plan.exec(
service_name=CUSTOM_FLOOD_SERVICE_NAME,
recipe=ExecRecipe(
["/bin/sh", "-c", "nohup python /tmp/sender.py > /dev/null 2>&1 &"]
[
"/bin/sh",
"-c",
"nohup python /tmp/sender.py --interval_between_transactions {} > /dev/null 2>&1 &".format(
params.interval_between_transactions
),
]
),
)
68 changes: 36 additions & 32 deletions src/mev_custom_flood/sender.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,15 @@
this is s a really dumb script that sends tokens to the receiver from the sender every 3 seconds
this is being used as of 2023-09-06 to guarantee that payloads are delivered
"""
from functools import partial

from web3 import Web3
from web3.middleware import construct_sign_and_send_raw_middleware
import os
import time
import logging
import click


VALUE_TO_SEND = 0x9184

Expand All @@ -17,49 +20,50 @@
datefmt='%H:%M:%S',
level=logging.DEBUG)

# this is the last prefunded address
SENDER = os.getenv("SENDER_PRIVATE_KEY", "17fdf89989597e8bcac6cdfcc001b6241c64cece2c358ffc818b72ca70f5e1ce")
# this is the first prefunded address
RECEIVER = os.getenv("RECEIVER_PUBLIC_KEY", "0x878705ba3f8Bc32FCf7F4CAa1A35E72AF65CF766")
EL_URI = os.getenv("EL_RPC_URI", 'http://0.0.0.0:53913')

def flood():
# this is the last prefunded address
sender = os.getenv("SENDER_PRIVATE_KEY", "17fdf89989597e8bcac6cdfcc001b6241c64cece2c358ffc818b72ca70f5e1ce")
# this is the first prefunded address
receiver = os.getenv("RECEIVER_PUBLIC_KEY", "0x878705ba3f8Bc32FCf7F4CAa1A35E72AF65CF766")
el_uri = os.getenv("EL_RPC_URI", 'http://0.0.0.0:53913')

logging.info(f"Using sender {sender} receiver {receiver} and el_uri {el_uri}")

w3 = Web3(Web3.HTTPProvider(el_uri))

sender_account = w3.eth.account.from_key(sender)

while True:
time.sleep(3)
def send_transaction():
# Setting w3 as constant causes recursion exceeded error after ~500 transactions
h4ck3rk3y marked this conversation as resolved.
Show resolved Hide resolved
# Thus it's created everytime a transaction is sent
w3 = Web3(Web3.HTTPProvider(EL_URI))

w3.middleware_onion.add(construct_sign_and_send_raw_middleware(sender_account))
sender_account = w3.eth.account.from_key(SENDER)
w3.middleware_onion.add(construct_sign_and_send_raw_middleware(sender_account))

transaction = {
"from": sender_account.address,
"value": VALUE_TO_SEND,
"to": receiver,
"data": "0xabcd",
"gasPrice": w3.eth.gas_price,
"nonce": w3.eth.get_transaction_count(sender_account.address)
}
transaction = {
"from": sender_account.address,
"value": VALUE_TO_SEND,
"to": RECEIVER,
"data": "0xabcd",
"gasPrice": w3.eth.gas_price,
"nonce": w3.eth.get_transaction_count(sender_account.address)
}

estimated_gas = w3.eth.estimate_gas(transaction)
transaction["gas"] = estimated_gas

transaction["gas"] = estimated_gas
tx_hash = w3.eth.send_transaction(transaction)

tx_hash = w3.eth.send_transaction(transaction)
tx = w3.eth.get_transaction(tx_hash)
logging.info(tx_hash.hex())
assert tx["from"] == sender_account.address

tx = w3.eth.get_transaction(tx_hash)
logging.info(tx_hash.hex())
assert tx["from"] == sender_account.address
def delayed_send(interval_between_transactions):
send_transaction()
time.sleep(interval_between_transactions)


def run_infinitely():
@click.command()
@click.option('--interval_between_transactions', default=0.5, help='Interval between successive transaction sends (in seconds). The value may be an integer or decimal')
def run_infinitely(interval_between_transactions):
logging.info(f"Using sender {SENDER} receiver {RECEIVER} and el_uri {EL_URI}")
spam = send_transaction if interval_between_transactions == 0 else partial(delayed_send, interval_between_transactions)
while True:
try:
flood()
spam()
except Exception as e:
print("e")
print("restarting flood as previous one failed")
Expand Down
20 changes: 16 additions & 4 deletions src/package_io/parse_input.star
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ ATTR_TO_BE_SKIPPED_AT_ROOT = (
"mev_params",
"goomy_blob_params",
"tx_spammer_params",
"custom_flood_params",
)

package_io_constants = import_module("../package_io/constants.star")
Expand All @@ -65,6 +66,7 @@ def parse_input(plan, input_args):
result["additional_services"] = DEFAULT_ADDITIONAL_SERVICES
result["grafana_additional_dashboards"] = []
result["tx_spammer_params"] = get_default_tx_spammer_params()
result["custom_flood_params"] = get_default_custom_flood_params()

for attr in input_args:
value = input_args[attr]
Expand All @@ -80,6 +82,10 @@ def parse_input(plan, input_args):
for sub_attr in input_args["tx_spammer_params"]:
sub_value = input_args["tx_spammer_params"][sub_attr]
result["tx_spammer_params"][sub_attr] = sub_value
elif attr == "custom_flood_params":
for sub_attr in input_args["custom_flood_params"]:
sub_value = input_args["custom_flood_params"][sub_attr]
result["custom_flood_params"][sub_attr] = sub_value

if result.get("mev_type") in ("mock", "full"):
result = enrich_mev_extra_params(
Expand All @@ -101,7 +107,6 @@ def parse_input(plan, input_args):
)

result["goomy_blob_params"] = get_default_goomy_blob_params()

return struct(
participants=[
struct(
Expand Down Expand Up @@ -168,14 +173,18 @@ 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"],
),
goomy_blob_params=struct(
goomy_blob_args=result["goomy_blob_params"]["goomy_blob_args"],
),
custom_flood_params=struct(
interval_between_transactions=result["custom_flood_params"][
"interval_between_transactions"
],
),
launch_additional_services=result["launch_additional_services"],
additional_services=result["additional_services"],
wait_for_finalization=result["wait_for_finalization"],
Expand Down Expand Up @@ -399,8 +408,6 @@ def get_default_mev_params():
"mev_flood_image": "flashbots/mev-flood",
"mev_flood_extra_args": [],
"mev_flood_seconds_per_bundle": 15,
# this is a simple script that increases the balance of the coinbase address at a cadence
"launch_custom_flood": False,
}


Expand All @@ -412,6 +419,11 @@ def get_default_goomy_blob_params():
return {"goomy_blob_args": []}


def get_default_custom_flood_params():
# this is a simple script that increases the balance of the coinbase address at a cadence
return {"interval_between_transactions": 1}


# 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"]):
Expand Down