Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 59 additions & 0 deletions main.star
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@ op_challenger_launcher = import_module(
"./src/challenger/op-challenger/op_challenger_launcher.star"
)

faucet = import_module("./src/faucet/op-faucet/op_faucet_launcher.star")
observability = import_module("./src/observability/observability.star")
util = import_module("./src/util.star")

wait_for_sync = import_module("./src/wait/wait_for_sync.star")
input_parser = import_module("./src/package_io/input_parser.star")
Expand Down Expand Up @@ -196,6 +198,16 @@ def run(plan, args={}):
observability_helper=observability_helper,
)

if optimism_args.faucet.enabled:
_install_faucet(
plan=plan,
faucet_params=optimism_args.faucet,
l1_config_env_vars=l1_config_env_vars,
l1_priv_key=l1_priv_key,
deployment_output=deployment_output,
l2s=l2s,
)

observability.launch(
plan, observability_helper, global_node_selectors, observability_params
)
Expand All @@ -211,3 +223,50 @@ def get_l1_config(all_l1_participants, l1_network_params, l1_network_id):
env_vars["L1_CHAIN_ID"] = str(l1_network_id)
env_vars["L1_BLOCK_TIME"] = str(l1_network_params.seconds_per_slot)
return env_vars


def _install_faucet(
plan,
faucet_params,
l1_config_env_vars,
l1_priv_key,
deployment_output,
l2s,
):
faucets = [
faucet.faucet_data(
name="l1",
chain_id=l1_config_env_vars["L1_CHAIN_ID"],
el_rpc=l1_config_env_vars["L1_RPC_URL"],
private_key=l1_priv_key,
),
]
for l2 in l2s:
chain_id = l2.network_id

private_key = util.read_network_config_value(
plan,
deployment_output,
"wallets",
'."{0}" | .["l2FaucetPrivateKey"]'.format(chain_id),
)
faucets.append(
faucet.faucet_data(
name=l2.name,
chain_id=chain_id,
el_rpc=l2.participants[0].el_context.rpc_http_url,
private_key=private_key,
)
)

faucet_image = (
faucet_params.image
if faucet_params.image != ""
else input_parser.DEFAULT_FAUCET_IMAGES["op-faucet"]
)
faucet.launch(
plan,
"op-faucet",
faucet_image,
faucets,
)
8 changes: 8 additions & 0 deletions src/faucet/op-faucet/config.tmpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
faucets:
{{- range . }}
{{ .Name }}:
el_rpc: "{{ .RPC }}"
chain_id: {{ .ChainID }}
tx_cfg:
private_key: "{{ .PrivateKey }}"
{{ end }}
97 changes: 97 additions & 0 deletions src/faucet/op-faucet/op_faucet_launcher.star
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
"""
Support for the op-faucet service.

TODO: op-faucet doesn't have a proper release yet. Don't use this for now
unless you know what you're doing.
"""


def launch(
plan,
service_name,
image,
faucets,
):
"""Launch the op-faucet service.

Args:
plan: The plan to add the service to.
service_name (str): The name of the service.
image (str): The image to use for the op-faucet service.
faucets (list of faucet_data): The faucets to use for the op-faucet service.
"""
faucet_config = plan.render_templates(
name="faucet_config",
description="rendering op-faucet config",
config={
"/config.yaml": struct(
template=read_file("./config.tmpl"),
data=faucets,
)
},
)

config = _get_config(
image,
faucet_config,
)
plan.add_service(service_name, config)


def _get_config(
image,
faucet_config,
):
"""Get the ServiceConfig for the op-faucet service.

Args:
image (str): The image to use for the op-faucet service.
faucet_config (artifact): The config artifact for the op-faucet service.
"""
mount_path = "/config"
cmd = [
"op-faucet",
"--rpc.port=9000",
"--config={0}/config.yaml".format(mount_path),
]

return ServiceConfig(
image=image,
cmd=cmd,
ports={
"rpc": PortSpec(
number=9000,
transport_protocol="TCP",
application_protocol="http",
),
},
files={
mount_path: faucet_config,
},
)


def faucet_data(
chain_id,
el_rpc,
private_key,
name=None,
):
"""Constructor for a faucet data struct.

Args:
chain_id (str): The chain ID the faucet will be used on.
el_rpc (str): The EL RPC the faucet will use.
private_key (str): The private key of the underlying faucet wallet.
name (str): The name of the faucet.
"""
if name == None:
name = chain_id

return struct(
# capitalization for Go template expansion
Name=name,
ChainID=chain_id,
RPC=el_rpc,
PrivateKey=private_key,
)
20 changes: 20 additions & 0 deletions src/package_io/input_parser.star
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,12 @@ DEFAULT_TX_FUZZER_IMAGES = {
"tx-fuzzer": "ethpandaops/tx-fuzz:master",
}

DEFAULT_FAUCET_IMAGES = {
# TODO: update to use a versioned image when available
# For now, we'll need users to pass the image explicitly
"op-faucet": "",
}

DEFAULT_ADDITIONAL_SERVICES = []


Expand Down Expand Up @@ -120,6 +126,10 @@ def input_parser(plan, input_args):
max_mem=results["observability"]["grafana_params"]["max_mem"],
),
),
faucet=struct(
enabled=results["faucet"]["enabled"],
image=results["faucet"]["image"],
),
interop=struct(
enabled=results["interop"]["enabled"],
supervisor_params=struct(
Expand Down Expand Up @@ -308,6 +318,9 @@ def parse_network_params(plan, input_args):
results["observability"] = default_observability_params()
results["observability"].update(input_args.get("observability", {}))

results["faucet"] = default_faucet_params()
results["faucet"].update(input_args.get("faucet", {}))

results["observability"]["prometheus_params"] = default_prometheus_params()
results["observability"]["prometheus_params"].update(
input_args.get("observability", {}).get("prometheus_params", {})
Expand Down Expand Up @@ -482,6 +495,13 @@ def default_observability_params():
}


def default_faucet_params():
return {
"enabled": False,
"image": DEFAULT_FAUCET_IMAGES["op-faucet"],
}


def default_prometheus_params():
return {
"image": "prom/prometheus:v3.1.0",
Expand Down
14 changes: 14 additions & 0 deletions src/package_io/sanity_check.star
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ ROOT_PARAMS = [
"global_node_selectors",
"global_tolerations",
"persistent",
"faucet",
]

OBSERVABILITY_PARAMS = [
Expand All @@ -19,6 +20,11 @@ OBSERVABILITY_PARAMS = [
"grafana_params",
]

FAUCET_PARAMS = [
"enabled",
"image",
]

PROMETHEUS_PARAMS = [
"image",
"storage_tsdb_retention_time",
Expand Down Expand Up @@ -256,6 +262,14 @@ def sanity_check(plan, optimism_config):
GRAFANA_PARAMS,
)

if "faucet" in optimism_config:
validate_params(
plan,
optimism_config["faucet"],
"faucet",
FAUCET_PARAMS,
)

if "interop" in optimism_config:
validate_params(
plan,
Expand Down
1 change: 1 addition & 0 deletions src/participant_network.star
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,7 @@ def launch_participant_network(
)

return struct(
name=network_params.name,
network_id=network_params.network_id,
participants=all_participants,
)
80 changes: 80 additions & 0 deletions test/op_faucet_launcher_test.star
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
"""
Tests for the op-faucet launcher.
"""

op_faucet_launcher = import_module("/src/faucet/op-faucet/op_faucet_launcher.star")
input_parser = import_module("/src/package_io/input_parser.star")
constants = import_module("/src/package_io/constants.star")


def test_launch_with_defaults(plan):
"""Test launching the op-faucet service with default parameters."""
faucet_image = input_parser.DEFAULT_FAUCET_IMAGES["op-faucet"]
service_name = "op-faucet"

# Create test faucet data
faucets = [
op_faucet_launcher.faucet_data(
chain_id="1",
el_rpc="http://l1-rpc",
private_key=constants.dev_accounts[0]["private_key"],
name="l1",
),
op_faucet_launcher.faucet_data(
chain_id="10",
el_rpc="http://l2-rpc",
private_key=constants.dev_accounts[1]["private_key"],
name="l2",
),
]

op_faucet_launcher.launch(
plan=plan,
service_name=service_name,
image=faucet_image,
faucets=faucets,
)

# Verify service configuration
faucet_service_config = kurtosistest.get_service_config(service_name=service_name)
expect.ne(faucet_service_config, None)
expect.eq(faucet_service_config.image, faucet_image)
expect.eq(faucet_service_config.env_vars, {})
expect.eq(faucet_service_config.entrypoint, [])
expect.eq(
faucet_service_config.cmd,
[
"op-faucet",
"--rpc.port=9000",
"--config=/config/config.yaml",
],
)
expect.eq(faucet_service_config.ports["rpc"].number, 9000)
expect.eq(faucet_service_config.ports["rpc"].transport_protocol, "TCP")
expect.eq(faucet_service_config.ports["rpc"].application_protocol, "http")


def test_launch_with_custom_image(plan):
"""Test launching the op-faucet service with a custom image."""
custom_image = "custom-op-faucet:latest"
service_name = "op-faucet"

# Create test faucet data
faucets = [
op_faucet_launcher.faucet_data(
chain_id="1",
el_rpc="http://l1-rpc",
private_key=constants.dev_accounts[0]["private_key"],
),
]

op_faucet_launcher.launch(
plan=plan,
service_name=service_name,
image=custom_image,
faucets=faucets,
)

# Verify service configuration
faucet_service_config = kurtosistest.get_service_config(service_name=service_name)
expect.eq(faucet_service_config.image, custom_image)
Loading