Commit d2755b01 authored by Barnabas Busa's avatar Barnabas Busa Committed by GitHub

feat: add blobber (#401)

parent c5728d98
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
......@@ -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.
......
......@@ -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"
......
def new_blobber_context(ip_addr, port_num):
return struct(
ip_addr=ip_addr,
port_num=port_num,
)
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,
)
......@@ -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"
......@@ -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,
......@@ -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:
......
......@@ -3,7 +3,7 @@ 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 -------------------------------------
......@@ -11,7 +11,7 @@ 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"
......@@ -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
),
......@@ -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,
......@@ -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
......@@ -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]",
......@@ -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,
......
......@@ -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,
......
......@@ -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
......@@ -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
......@@ -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
),
......@@ -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,
......@@ -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)
......@@ -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]",
......@@ -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,
......
......@@ -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
......@@ -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,
......
......@@ -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"]
],
......@@ -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"
......@@ -433,6 +446,8 @@ def default_participant():
"scrape_interval": "15s",
"labels": None,
},
"blobber_enabled": False,
"blobber_extra_params": [],
}
......
......@@ -311,7 +311,6 @@ def launch_participant_network(
snooper_engine_context
)
)
all_snooper_engine_contexts.append(snooper_engine_context)
if index == 0:
......@@ -335,6 +334,8 @@ def launch_participant_network(
participant.v_max_mem,
participant.snooper_enabled,
snooper_engine_context,
participant.blobber_enabled,
participant.blobber_extra_params,
participant.beacon_extra_params,
participant.validator_extra_params,
participant.beacon_extra_labels,
......@@ -362,6 +363,8 @@ def launch_participant_network(
participant.v_max_mem,
participant.snooper_enabled,
snooper_engine_context,
participant.blobber_enabled,
participant.blobber_extra_params,
participant.beacon_extra_params,
participant.validator_extra_params,
participant.beacon_extra_labels,
......
# One of these will be created per node we're trying to start
def new_keystore_files(
files_artifact_uuid,
raw_root_dirpath,
raw_keys_relative_dirpath,
raw_secrets_relative_dirpath,
nimbus_keys_relative_dirpath,
......@@ -11,6 +12,7 @@ def new_keystore_files(
return struct(
files_artifact_uuid=files_artifact_uuid,
# ------------ All directories below are relative to the root of the files artifact ----------------
raw_root_dirpath=raw_root_dirpath,
raw_keys_relative_dirpath=raw_keys_relative_dirpath,
raw_secrets_relative_dirpath=raw_secrets_relative_dirpath,
nimbus_keys_relative_dirpath=nimbus_keys_relative_dirpath,
......
......@@ -140,6 +140,7 @@ def generate_validator_keystores(plan, mnemonic, participants):
base_dirname_in_artifact = shared_utils.path_base(output_dirpath)
to_add = keystore_files_module.new_keystore_files(
artifact_name,
shared_utils.path_join(base_dirname_in_artifact),
shared_utils.path_join(base_dirname_in_artifact, RAW_KEYS_DIRNAME),
shared_utils.path_join(base_dirname_in_artifact, RAW_SECRETS_DIRNAME),
shared_utils.path_join(base_dirname_in_artifact, NIMBUS_KEYS_DIRNAME),
......@@ -283,6 +284,7 @@ def generate_valdiator_keystores_in_parallel(plan, mnemonic, participants):
base_dirname_in_artifact = shared_utils.path_base(output_dirpath)
to_add = keystore_files_module.new_keystore_files(
artifact_name,
shared_utils.path_join(base_dirname_in_artifact),
shared_utils.path_join(base_dirname_in_artifact, RAW_KEYS_DIRNAME),
shared_utils.path_join(base_dirname_in_artifact, RAW_SECRETS_DIRNAME),
shared_utils.path_join(base_dirname_in_artifact, NIMBUS_KEYS_DIRNAME),
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment