Skip to content

Commit

Permalink
feat: add blobber (#401)
Browse files Browse the repository at this point in the history
  • Loading branch information
barnabasbusa committed Dec 12, 2023
1 parent c5728d9 commit d2755b0
Show file tree
Hide file tree
Showing 14 changed files with 208 additions and 14 deletions.
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

0 comments on commit d2755b0

Please sign in to comment.