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 blobber #401

Merged
merged 18 commits into from
Dec 12, 2023
Merged
20 changes: 20 additions & 0 deletions .github/tests/blobber.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
participants:
- el_client_type: geth
el_client_image: ethpandaops/geth:master
cl_client_type: lighthouse
cl_client_image: ethpandaops/lighthouse:sidecar-inclusion-proof-c6be31c
blobber_enabled: true
blobber_extra_params:
- --proposal-action-frequency=1
- "--proposal-action={\"name\": \"blob_gossip_delay\", \"delay_milliseconds\": 1500}"
count: 1
- el_client_type: geth
el_client_image: ethpandaops/geth:master
cl_client_type: lodestar
cl_client_image: ethpandaops/lodestar:blobs-inclproof-d5a5a47
count: 1
network_params:
deneb_fork_epoch: 1
additional_services:
- dora
- blob_spammer
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,14 @@ participants:
# Additional labels to be added. Default to empty
labels: {}

# Blobber can be enabled with the `blobber_enabled` flag per client or globally
# Defaults to false
blobber_enabled: false

# Blobber extra params can be passed in to the blobber container
# Defaults to empty
blobber_extra_params: []

# Default configuration parameters for the Eth network
network_params:
# The network ID of the network.
Expand Down
2 changes: 2 additions & 0 deletions network_params.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ participants:
prometheus_config:
scrape_interval: 15s
labels: {}
blobber_enabled: false
blobber_extra_params: []
network_params:
network_id: "3151908"
deposit_contract_address: "0x4242424242424242424242424242424242424242"
Expand Down
5 changes: 5 additions & 0 deletions src/blobber/blobber_context.star
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
def new_blobber_context(ip_addr, port_num):
return struct(
ip_addr=ip_addr,
port_num=port_num,
)
81 changes: 81 additions & 0 deletions src/blobber/blobber_launcher.star
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
shared_utils = import_module("../shared_utils/shared_utils.star")
input_parser = import_module("../package_io/input_parser.star")
cl_client_context = import_module("../cl/cl_client_context.star")

blobber_context = import_module("../blobber/blobber_context.star")

BLOBBER_BEACON_PORT_NUM = 9000
BLOBBER_BEACON_PORT_TCP_ID = "discovery-tcp"
BLOBBER_BEACON_PORT_UDP_ID = "discovery-udp"
BLOBBER_VALIDATOR_PROXY_PORT_NUM = 5000
BLOBBER_VALIDATOR_PROXY_PORT_ID = "http"

PRIVATE_IP_ADDRESS_PLACEHOLDER = "KURTOSIS_IP_ADDR_PLACEHOLDER"

DEFAULT_BLOBBER_IMAGE = "ethpandaops/blobber:1.1.0"

VALIDATOR_KEYS_MOUNTPOINT_ON_CLIENTS = "/validator-keys"

BLOBBER_USED_PORTS = {
BLOBBER_VALIDATOR_PROXY_PORT_ID: shared_utils.new_port_spec(
BLOBBER_VALIDATOR_PROXY_PORT_NUM, shared_utils.TCP_PROTOCOL, wait="5s"
),
BLOBBER_BEACON_PORT_TCP_ID: shared_utils.new_port_spec(
BLOBBER_BEACON_PORT_NUM, shared_utils.TCP_PROTOCOL, wait=None
),
BLOBBER_BEACON_PORT_UDP_ID: shared_utils.new_port_spec(
BLOBBER_BEACON_PORT_NUM, shared_utils.UDP_PROTOCOL, wait=None
),
}

# The min/max CPU/memory that blobbers can use
MIN_CPU = 10
MAX_CPU = 500
MIN_MEMORY = 10
MAX_MEMORY = 300


def launch(plan, service_name, node_keystore_files, beacon_http_url, extra_params):
blobber_service_name = "{0}".format(service_name)

blobber_config = get_config(
service_name, node_keystore_files, beacon_http_url, extra_params
)

blobber_service = plan.add_service(blobber_service_name, blobber_config)
return blobber_context.new_blobber_context(
blobber_service.ip_address,
blobber_service.ports[BLOBBER_VALIDATOR_PROXY_PORT_NUM],
)


def get_config(service_name, node_keystore_files, beacon_http_url, extra_params):
validator_root_dirpath = shared_utils.path_join(
VALIDATOR_KEYS_MOUNTPOINT_ON_CLIENTS,
node_keystore_files.raw_root_dirpath,
)
cmd = [
"--beacon-port-start={0}".format(BLOBBER_BEACON_PORT_NUM),
"--cl={0}".format(beacon_http_url),
"--validator-key-folder={0}".format(validator_root_dirpath),
"--enable-unsafe-mode",
"--external-ip={0}".format(PRIVATE_IP_ADDRESS_PLACEHOLDER),
"--validator-proxy-port-start={0}".format(BLOBBER_VALIDATOR_PROXY_PORT_NUM),
]

if len(extra_params) > 0:
cmd.extend([param for param in extra_params])

return ServiceConfig(
image=DEFAULT_BLOBBER_IMAGE,
ports=BLOBBER_USED_PORTS,
files={
VALIDATOR_KEYS_MOUNTPOINT_ON_CLIENTS: node_keystore_files.files_artifact_uuid
},
cmd=cmd,
private_ip_address_placeholder=PRIVATE_IP_ADDRESS_PLACEHOLDER,
min_cpu=MIN_CPU,
max_cpu=MAX_CPU,
min_memory=MIN_MEMORY,
max_memory=MAX_MEMORY,
)
23 changes: 23 additions & 0 deletions src/cl/lighthouse/lighthouse_launcher.star
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ cl_node_ready_conditions = import_module("../../cl/cl_node_ready_conditions.star

constants = import_module("../../package_io/constants.star")

blobber_launcher = import_module("../../blobber/blobber_launcher.star")

LIGHTHOUSE_BINARY_COMMAND = "lighthouse"

VALIDATOR_KEYS_MOUNTPOINT_ON_CLIENTS = "/validator-keys"
Expand Down Expand Up @@ -113,6 +115,8 @@ def launch(
v_max_mem,
snooper_enabled,
snooper_engine_context,
blobber_enabled,
blobber_extra_params,
extra_beacon_params,
extra_validator_params,
extra_beacon_labels,
Expand Down Expand Up @@ -155,6 +159,25 @@ def launch(
beacon_service.ip_address, beacon_http_port.number
)

# Blobber config
if blobber_enabled:
blobber_service_name = "{0}-{1}".format("blobber", beacon_node_service_name)
blobber_config = blobber_launcher.get_config(
blobber_service_name,
node_keystore_files,
beacon_http_url,
blobber_extra_params,
)

blobber_service = plan.add_service(blobber_service_name, blobber_config)
blobber_http_port = blobber_service.ports[
blobber_launcher.BLOBBER_VALIDATOR_PROXY_PORT_ID
]
blobber_http_url = "http://{0}:{1}".format(
blobber_service.ip_address, blobber_http_port.number
)
beacon_http_url = blobber_http_url

# Launch validator node if we have a keystore
validator_service = None
if node_keystore_files != None:
Expand Down
37 changes: 31 additions & 6 deletions src/cl/lodestar/lodestar_launcher.star
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,15 @@ input_parser = import_module("../../package_io/input_parser.star")
cl_client_context = import_module("../../cl/cl_client_context.star")
node_metrics = import_module("../../node_metrics_info.star")
cl_node_ready_conditions = import_module("../../cl/cl_node_ready_conditions.star")

blobber_launcher = import_module("../../blobber/blobber_launcher.star")
constants = import_module("../../package_io/constants.star")

# ---------------------------------- Beacon client -------------------------------------
CONSENSUS_DATA_DIRPATH_ON_SERVICE_CONTAINER = "/consensus-data"
# Port IDs
TCP_DISCOVERY_PORT_ID = "tcp-discovery"
UDP_DISCOVERY_PORT_ID = "udp-discovery"
HTTP_PORT_ID = "http"
BEACON_HTTP_PORT_ID = "http"
METRICS_PORT_ID = "metrics"
VALIDATOR_METRICS_PORT_ID = "validator-metrics"

Expand Down Expand Up @@ -47,7 +47,9 @@ BEACON_USED_PORTS = {
UDP_DISCOVERY_PORT_ID: shared_utils.new_port_spec(
DISCOVERY_PORT_NUM, shared_utils.UDP_PROTOCOL
),
HTTP_PORT_ID: shared_utils.new_port_spec(HTTP_PORT_NUM, shared_utils.TCP_PROTOCOL),
BEACON_HTTP_PORT_ID: shared_utils.new_port_spec(
HTTP_PORT_NUM, shared_utils.TCP_PROTOCOL
),
METRICS_PORT_ID: shared_utils.new_port_spec(
METRICS_PORT_NUM, shared_utils.TCP_PROTOCOL
),
Expand Down Expand Up @@ -89,6 +91,8 @@ def launch(
v_max_mem,
snooper_enabled,
snooper_engine_context,
blobber_enabled,
blobber_extra_params,
extra_beacon_params,
extra_validator_params,
extra_beacon_labels,
Expand Down Expand Up @@ -126,12 +130,31 @@ def launch(

beacon_service = plan.add_service(beacon_node_service_name, beacon_config)

beacon_http_port = beacon_service.ports[HTTP_PORT_ID]
beacon_http_port = beacon_service.ports[BEACON_HTTP_PORT_ID]

beacon_http_url = "http://{0}:{1}".format(
beacon_service.ip_address, beacon_http_port.number
)

# Blobber config
if blobber_enabled:
blobber_service_name = "{0}-{1}".format("blobber", beacon_node_service_name)
blobber_config = blobber_launcher.get_config(
blobber_service_name,
node_keystore_files,
beacon_http_url,
blobber_extra_params,
)

blobber_service = plan.add_service(blobber_service_name, blobber_config)
blobber_http_port = blobber_service.ports[
blobber_launcher.BLOBBER_VALIDATOR_PROXY_PORT_ID
]
blobber_http_url = "http://{0}:{1}".format(
blobber_service.ip_address, blobber_http_port.number
)
beacon_http_url = blobber_http_url

# Launch validator node if we have a keystore
if node_keystore_files != None:
v_min_cpu = int(v_min_cpu) if int(v_min_cpu) > 0 else VALIDATOR_MIN_CPU
Expand Down Expand Up @@ -160,7 +183,7 @@ def launch(

beacon_node_identity_recipe = GetHttpRequestRecipe(
endpoint="/eth/v1/node/identity",
port_id=HTTP_PORT_ID,
port_id=BEACON_HTTP_PORT_ID,
extract={
"enr": ".data.enr",
"multiaddr": ".data.p2p_addresses[-1]",
Expand Down Expand Up @@ -287,7 +310,9 @@ def get_beacon_config(
constants.GENESIS_DATA_MOUNTPOINT_ON_CLIENTS: el_cl_genesis_data.files_artifact_uuid
},
private_ip_address_placeholder=PRIVATE_IP_ADDRESS_PLACEHOLDER,
ready_conditions=cl_node_ready_conditions.get_ready_conditions(HTTP_PORT_ID),
ready_conditions=cl_node_ready_conditions.get_ready_conditions(
BEACON_HTTP_PORT_ID
),
min_cpu=bn_min_cpu,
max_cpu=bn_max_cpu,
min_memory=bn_min_mem,
Expand Down
2 changes: 2 additions & 0 deletions src/cl/nimbus/nimbus_launcher.star
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,8 @@ def launch(
v_max_mem,
snooper_enabled,
snooper_engine_context,
blobber_enabled,
blobber_extra_params,
extra_beacon_params,
extra_validator_params,
extra_beacon_labels,
Expand Down
17 changes: 11 additions & 6 deletions src/cl/prysm/prysm_launcher.star
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ cl_client_context = import_module("../../cl/cl_client_context.star")
node_metrics = import_module("../../node_metrics_info.star")
cl_node_ready_conditions = import_module("../../cl/cl_node_ready_conditions.star")
constants = import_module("../../package_io/constants.star")

IMAGE_SEPARATOR_DELIMITER = ","
EXPECTED_NUM_IMAGES = 2

Expand All @@ -15,7 +14,7 @@ CONSENSUS_DATA_DIRPATH_ON_SERVICE_CONTAINER = "/consensus-data"
TCP_DISCOVERY_PORT_ID = "tcp-discovery"
UDP_DISCOVERY_PORT_ID = "udp-discovery"
RPC_PORT_ID = "rpc"
HTTP_PORT_ID = "http"
BEACON_HTTP_PORT_ID = "http"
BEACON_MONITORING_PORT_ID = "monitoring"

# Port nums
Expand Down Expand Up @@ -61,7 +60,9 @@ BEACON_NODE_USED_PORTS = {
DISCOVERY_UDP_PORT_NUM, shared_utils.UDP_PROTOCOL
),
RPC_PORT_ID: shared_utils.new_port_spec(RPC_PORT_NUM, shared_utils.TCP_PROTOCOL),
HTTP_PORT_ID: shared_utils.new_port_spec(HTTP_PORT_NUM, shared_utils.TCP_PROTOCOL),
BEACON_HTTP_PORT_ID: shared_utils.new_port_spec(
HTTP_PORT_NUM, shared_utils.TCP_PROTOCOL
),
BEACON_MONITORING_PORT_ID: shared_utils.new_port_spec(
BEACON_MONITORING_PORT_NUM, shared_utils.TCP_PROTOCOL
),
Expand Down Expand Up @@ -102,6 +103,8 @@ def launch(
v_max_mem,
snooper_enabled,
snooper_engine_context,
blobber_enabled,
blobber_extra_params,
extra_beacon_params,
extra_validator_params,
extra_beacon_labels,
Expand Down Expand Up @@ -153,7 +156,7 @@ def launch(

beacon_service = plan.add_service(beacon_node_service_name, beacon_config)

beacon_http_port = beacon_service.ports[HTTP_PORT_ID]
beacon_http_port = beacon_service.ports[BEACON_HTTP_PORT_ID]

beacon_http_endpoint = "{0}:{1}".format(beacon_service.ip_address, HTTP_PORT_NUM)
beacon_rpc_endpoint = "{0}:{1}".format(beacon_service.ip_address, RPC_PORT_NUM)
Expand Down Expand Up @@ -191,7 +194,7 @@ def launch(
# TODO(old) add validator availability using the validator API: https://ethereum.github.io/beacon-APIs/?urls.primaryName=v1#/ValidatorRequiredApi | from eth2-merge-kurtosis-module
beacon_node_identity_recipe = GetHttpRequestRecipe(
endpoint="/eth/v1/node/identity",
port_id=HTTP_PORT_ID,
port_id=BEACON_HTTP_PORT_ID,
extract={
"enr": ".data.enr",
"multiaddr": ".data.discovery_addresses[0]",
Expand Down Expand Up @@ -316,7 +319,9 @@ def get_beacon_config(
constants.GENESIS_DATA_MOUNTPOINT_ON_CLIENTS: el_cl_genesis_data.files_artifact_uuid,
},
private_ip_address_placeholder=PRIVATE_IP_ADDRESS_PLACEHOLDER,
ready_conditions=cl_node_ready_conditions.get_ready_conditions(HTTP_PORT_ID),
ready_conditions=cl_node_ready_conditions.get_ready_conditions(
BEACON_HTTP_PORT_ID
),
min_cpu=bn_min_cpu,
max_cpu=bn_max_cpu,
min_memory=bn_min_mem,
Expand Down
3 changes: 2 additions & 1 deletion src/cl/teku/teku_launcher.star
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ node_metrics = import_module("../../node_metrics_info.star")
cl_node_ready_conditions = import_module("../../cl/cl_node_ready_conditions.star")

constants = import_module("../../package_io/constants.star")

TEKU_BINARY_FILEPATH_IN_IMAGE = "/opt/teku/bin/teku"

# The Docker container runs as the "teku" user so we can't write to root
Expand Down Expand Up @@ -93,6 +92,8 @@ def launch(
v_max_mem,
snooper_enabled,
snooper_engine_context,
blobber_enabled,
blobber_extra_params,
extra_beacon_params,
extra_validator_params,
extra_beacon_labels,
Expand Down
15 changes: 15 additions & 0 deletions src/package_io/input_parser.star
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,8 @@ def input_parser(plan, input_args):
scrape_interval=participant["prometheus_config"]["scrape_interval"],
labels=participant["prometheus_config"]["labels"],
),
blobber_enabled=participant["blobber_enabled"],
blobber_extra_params=participant["blobber_extra_params"],
)
for participant in result["participants"]
],
Expand Down Expand Up @@ -281,6 +283,17 @@ def parse_network_params(input_args):
ethereum_metrics_exporter_enabled = participant[
"ethereum_metrics_exporter_enabled"
]

blobber_enabled = participant["blobber_enabled"]
if blobber_enabled:
# unless we are running lighthouse, we don't support blobber
if participant["cl_client_type"] != "lighthouse":
fail(
"blobber is not supported for {0} client".format(
participant["cl_client_type"]
)
)

if ethereum_metrics_exporter_enabled == False:
default_ethereum_metrics_exporter_enabled = result[
"ethereum_metrics_exporter_enabled"
Expand Down Expand Up @@ -433,6 +446,8 @@ def default_participant():
"scrape_interval": "15s",
"labels": None,
},
"blobber_enabled": False,
"blobber_extra_params": [],
}


Expand Down
Loading