input_parser.star 46.1 KB
Newer Older
1 2
constants = import_module("./constants.star")
shared_utils = import_module("../shared_utils/shared_utils.star")
3 4 5 6
genesis_constants = import_module(
    "../prelaunch_data_generator/genesis_constants/genesis_constants.star"
)

7 8
DEFAULT_EL_IMAGES = {
    "geth": "ethereum/client-go:latest",
9
    "erigon": "ethpandaops/erigon:main",
10
    "nethermind": "nethermindeth/nethermind:master",
11
    "besu": "hyperledger/besu:latest",
12 13
    "reth": "ghcr.io/paradigmxyz/reth",
    "ethereumjs": "ethpandaops/ethereumjs:master",
14
    "nimbus": "ethpandaops/nimbus-eth1:master",
15 16 17 18 19
}

DEFAULT_CL_IMAGES = {
    "lighthouse": "sigp/lighthouse:latest",
    "teku": "consensys/teku:latest",
20
    "nimbus": "statusim/nimbus-eth2:multiarch-latest",
21
    "prysm": "gcr.io/prysmaticlabs/prysm/beacon-chain:latest",
22 23 24 25 26 27 28 29 30 31 32
    "lodestar": "chainsafe/lodestar:latest",
    "grandine": "ethpandaops/grandine:master",
}

DEFAULT_CL_IMAGES_MINIMAL = {
    "lighthouse": "ethpandaops/lighthouse:stable-minimal",
    "teku": "consensys/teku:latest",
    "nimbus": "ethpandaops/nimbus-eth2:stable-minimal",
    "prysm": "ethpandaops/prysm-beacon-chain:develop-minimal",
    "lodestar": "chainsafe/lodestar:latest",
    "grandine": "ethpandaops/grandine:master-minimal",
33 34
}

35 36
DEFAULT_VC_IMAGES = {
    "lighthouse": "sigp/lighthouse:latest",
37
    "lodestar": "chainsafe/lodestar:latest",
38 39 40
    "nimbus": "statusim/nimbus-validator-client:multiarch-latest",
    "prysm": "gcr.io/prysmaticlabs/prysm/validator:latest",
    "teku": "consensys/teku:latest",
41
    "grandine": "ethpandaops/grandine:master",
42 43
}

44 45 46 47 48 49 50 51
DEFAULT_VC_IMAGES_MINIMAL = {
    "lighthouse": "ethpandaops/lighthouse:stable-minimal",
    "lodestar": "chainsafe/lodestar:latest",
    "nimbus": "ethpandaops/nimbus-validator-client:stable-minimal",
    "prysm": "ethpandaops/prysm-validator:develop-minimal",
    "teku": "consensys/teku:latest",
    "grandine": "ethpandaops/grandine:master-minimal",
}
52 53 54

# Placeholder value for the deneb fork epoch if electra is being run
# TODO: This is a hack, and should be removed once we electra is rebased on deneb
55
HIGH_DENEB_VALUE_FORK_VERKLE = 2000000000
56

57
# MEV Params
58
MEV_BOOST_PORT = 18550
59
MEV_BOOST_SERVICE_NAME_PREFIX = "mev-boost"
60

61 62 63
# Minimum number of validators required for a network to be valid is 64
MIN_VALIDATORS = 64

64 65 66 67 68
DEFAULT_ADDITIONAL_SERVICES = [
    "tx_spammer",
    "blob_spammer",
    "el_forkmon",
    "beacon_metrics_gazer",
69
    "dora",
70 71
    "prometheus_grafana",
]
72

73 74 75 76
ATTR_TO_BE_SKIPPED_AT_ROOT = (
    "network_params",
    "participants",
    "mev_params",
77
    "dora_params",
78
    "assertoor_params",
79
    "goomy_blob_params",
80
    "tx_spammer_params",
81
    "custom_flood_params",
82
    "xatu_sentry_params",
83
    "port_publisher",
84 85
)

86

87
def input_parser(plan, input_args):
88
    result = parse_network_params(plan, input_args)
89

90
    # add default eth2 input params
91
    result["dora_params"] = get_default_dora_params()
92 93 94
    result["mev_params"] = get_default_mev_params(
        result.get("mev_type"), result["network_params"]["preset"]
    )
95 96 97 98
    if (
        result["network_params"]["network"] == constants.NETWORK_NAME.kurtosis
        or constants.NETWORK_NAME.shadowfork in result["network_params"]["network"]
    ):
99 100 101
        result["additional_services"] = DEFAULT_ADDITIONAL_SERVICES
    else:
        result["additional_services"] = []
102
    result["grafana_additional_dashboards"] = []
103
    result["tx_spammer_params"] = get_default_tx_spammer_params()
104
    result["custom_flood_params"] = get_default_custom_flood_params()
105
    result["disable_peer_scoring"] = False
106 107
    result["goomy_blob_params"] = get_default_goomy_blob_params()
    result["assertoor_params"] = get_default_assertoor_params()
108
    result["xatu_sentry_params"] = get_default_xatu_sentry_params()
109
    result["persistent"] = False
110
    result["parallel_keystore_generation"] = False
111
    result["global_tolerations"] = []
112 113 114 115 116 117 118
    result["global_node_selectors"] = {}

    if constants.NETWORK_NAME.shadowfork in result["network_params"]["network"]:
        shadow_base = result["network_params"]["network"].split("-shadowfork")[0]
        result["network_params"][
            "deposit_contract_address"
        ] = constants.DEPOSIT_CONTRACT_ADDRESS[shadow_base]
119

120 121 122 123 124 125
    if constants.NETWORK_NAME.shadowfork in result["network_params"]["network"]:
        shadow_base = result["network_params"]["network"].split("-shadowfork")[0]
        result["network_params"][
            "deposit_contract_address"
        ] = constants.DEPOSIT_CONTRACT_ADDRESS[shadow_base]

126 127 128 129 130 131
    for attr in input_args:
        value = input_args[attr]
        # if its inserted we use the value inserted
        if attr not in ATTR_TO_BE_SKIPPED_AT_ROOT and attr in input_args:
            result[attr] = value
        # custom eth2 attributes config
132 133 134 135
        elif attr == "dora_params":
            for sub_attr in input_args["dora_params"]:
                sub_value = input_args["dora_params"][sub_attr]
                result["dora_params"][sub_attr] = sub_value
136 137 138 139
        elif attr == "mev_params":
            for sub_attr in input_args["mev_params"]:
                sub_value = input_args["mev_params"][sub_attr]
                result["mev_params"][sub_attr] = sub_value
140 141 142 143
        elif attr == "tx_spammer_params":
            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
144 145 146 147
        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
148 149 150 151 152 153 154 155
        elif attr == "goomy_blob_params":
            for sub_attr in input_args["goomy_blob_params"]:
                sub_value = input_args["goomy_blob_params"][sub_attr]
                result["goomy_blob_params"][sub_attr] = sub_value
        elif attr == "assertoor_params":
            for sub_attr in input_args["assertoor_params"]:
                sub_value = input_args["assertoor_params"][sub_attr]
                result["assertoor_params"][sub_attr] = sub_value
156 157 158 159
        elif attr == "xatu_sentry_params":
            for sub_attr in input_args["xatu_sentry_params"]:
                sub_value = input_args["xatu_sentry_params"][sub_attr]
                result["xatu_sentry_params"][sub_attr] = sub_value
160 161 162 163
        elif attr == "port_publisher":
            for sub_attr in input_args["port_publisher"]:
                sub_value = input_args["port_publisher"][sub_attr]
                result["port_publisher"][sub_attr] = sub_value
164

165 166 167
    if result.get("disable_peer_scoring"):
        result = enrich_disable_peer_scoring(result)

168 169 170 171 172
    if result.get("mev_type") in (
        constants.MOCK_MEV_TYPE,
        constants.FLASHBOTS_MEV_TYPE,
        constants.MEV_RS_MEV_TYPE,
    ):
173 174 175
        result = enrich_mev_extra_params(
            result,
            MEV_BOOST_SERVICE_NAME_PREFIX,
176
            MEV_BOOST_PORT,
177 178
            result.get("mev_type"),
        )
179 180 181 182 183 184 185 186
    elif result.get("mev_type") == None:
        pass
    else:
        fail(
            "Unsupported MEV type: {0}, please use 'mock', 'flashbots' or 'mev-rs' type".format(
                result.get("mev_type")
            )
        )
187

188 189 190 191 192 193 194 195
    if result["port_publisher"]["nat_exit_ip"] == "auto":
        result["port_publisher"]["nat_exit_ip"] = get_public_ip(plan)

    if result["port_publisher"]["public_port_start"] != None:
        start = result["port_publisher"]["public_port_start"]
        result["port_publisher"]["el_start"] = start
        result["port_publisher"]["cl_start"] = start + len(result["participants"])

196 197 198
    return struct(
        participants=[
            struct(
199 200 201 202
                el_type=participant["el_type"],
                el_image=participant["el_image"],
                el_log_level=participant["el_log_level"],
                el_volume_size=participant["el_volume_size"],
203 204 205
                el_extra_params=participant["el_extra_params"],
                el_extra_env_vars=participant["el_extra_env_vars"],
                el_extra_labels=participant["el_extra_labels"],
206
                el_tolerations=participant["el_tolerations"],
207 208 209 210 211
                cl_type=participant["cl_type"],
                cl_image=participant["cl_image"],
                cl_log_level=participant["cl_log_level"],
                cl_volume_size=participant["cl_volume_size"],
                cl_extra_env_vars=participant["cl_extra_env_vars"],
212
                cl_tolerations=participant["cl_tolerations"],
213 214 215 216
                use_separate_vc=participant["use_separate_vc"],
                vc_type=participant["vc_type"],
                vc_image=participant["vc_image"],
                vc_log_level=participant["vc_log_level"],
217
                vc_count=participant["vc_count"],
218 219 220 221 222 223
                vc_tolerations=participant["vc_tolerations"],
                cl_extra_params=participant["cl_extra_params"],
                cl_extra_labels=participant["cl_extra_labels"],
                vc_extra_params=participant["vc_extra_params"],
                vc_extra_env_vars=participant["vc_extra_env_vars"],
                vc_extra_labels=participant["vc_extra_labels"],
224 225 226 227 228
                builder_network_params=participant["builder_network_params"],
                el_min_cpu=participant["el_min_cpu"],
                el_max_cpu=participant["el_max_cpu"],
                el_min_mem=participant["el_min_mem"],
                el_max_mem=participant["el_max_mem"],
229 230 231 232 233 234 235 236
                cl_min_cpu=participant["cl_min_cpu"],
                cl_max_cpu=participant["cl_max_cpu"],
                cl_min_mem=participant["cl_min_mem"],
                cl_max_mem=participant["cl_max_mem"],
                vc_min_cpu=participant["vc_min_cpu"],
                vc_max_cpu=participant["vc_max_cpu"],
                vc_min_mem=participant["vc_min_mem"],
                vc_max_mem=participant["vc_max_mem"],
237
                validator_count=participant["validator_count"],
238 239
                tolerations=participant["tolerations"],
                node_selectors=participant["node_selectors"],
240 241
                snooper_enabled=participant["snooper_enabled"],
                count=participant["count"],
242 243 244
                ethereum_metrics_exporter_enabled=participant[
                    "ethereum_metrics_exporter_enabled"
                ],
245
                xatu_sentry_enabled=participant["xatu_sentry_enabled"],
246 247 248 249
                prometheus_config=struct(
                    scrape_interval=participant["prometheus_config"]["scrape_interval"],
                    labels=participant["prometheus_config"]["labels"],
                ),
250 251
                blobber_enabled=participant["blobber_enabled"],
                blobber_extra_params=participant["blobber_extra_params"],
252
                keymanager_enabled=participant["keymanager_enabled"],
253 254 255 256 257 258
            )
            for participant in result["participants"]
        ],
        network_params=struct(
            preregistered_validator_keys_mnemonic=result["network_params"][
                "preregistered_validator_keys_mnemonic"
259
            ],
260 261 262
            preregistered_validator_count=result["network_params"][
                "preregistered_validator_count"
            ],
263 264 265 266 267 268 269 270 271
            num_validator_keys_per_node=result["network_params"][
                "num_validator_keys_per_node"
            ],
            network_id=result["network_params"]["network_id"],
            deposit_contract_address=result["network_params"][
                "deposit_contract_address"
            ],
            seconds_per_slot=result["network_params"]["seconds_per_slot"],
            genesis_delay=result["network_params"]["genesis_delay"],
272 273 274 275
            max_per_epoch_activation_churn_limit=result["network_params"][
                "max_per_epoch_activation_churn_limit"
            ],
            churn_limit_quotient=result["network_params"]["churn_limit_quotient"],
276
            ejection_balance=result["network_params"]["ejection_balance"],
277
            eth1_follow_distance=result["network_params"]["eth1_follow_distance"],
278 279
            deneb_fork_epoch=result["network_params"]["deneb_fork_epoch"],
            electra_fork_epoch=result["network_params"]["electra_fork_epoch"],
280 281
            eip7594_fork_epoch=result["network_params"]["eip7594_fork_epoch"],
            eip7594_fork_version=result["network_params"]["eip7594_fork_version"],
282
            network=result["network_params"]["network"],
283 284 285 286
            min_validator_withdrawability_delay=result["network_params"][
                "min_validator_withdrawability_delay"
            ],
            shard_committee_period=result["network_params"]["shard_committee_period"],
287
            network_sync_base_url=result["network_params"]["network_sync_base_url"],
288 289 290 291 292 293
            data_column_sidecar_subnet_count=result["network_params"][
                "data_column_sidecar_subnet_count"
            ],
            samples_per_slot=result["network_params"]["samples_per_slot"],
            custody_requirement=result["network_params"]["custody_requirement"],
            target_number_of_peers=result["network_params"]["target_number_of_peers"],
294
            preset=result["network_params"]["preset"],
295
        ),
296 297 298
        mev_params=struct(
            mev_relay_image=result["mev_params"]["mev_relay_image"],
            mev_builder_image=result["mev_params"]["mev_builder_image"],
299
            mev_builder_cl_image=result["mev_params"]["mev_builder_cl_image"],
300
            mev_builder_extra_data=result["mev_params"]["mev_builder_extra_data"],
301
            mev_boost_image=result["mev_params"]["mev_boost_image"],
302
            mev_boost_args=result["mev_params"]["mev_boost_args"],
303 304 305 306 307 308 309 310 311 312 313 314 315
            mev_relay_api_extra_args=result["mev_params"]["mev_relay_api_extra_args"],
            mev_relay_housekeeper_extra_args=result["mev_params"][
                "mev_relay_housekeeper_extra_args"
            ],
            mev_relay_website_extra_args=result["mev_params"][
                "mev_relay_website_extra_args"
            ],
            mev_builder_extra_args=result["mev_params"]["mev_builder_extra_args"],
            mev_flood_image=result["mev_params"]["mev_flood_image"],
            mev_flood_extra_args=result["mev_params"]["mev_flood_extra_args"],
            mev_flood_seconds_per_bundle=result["mev_params"][
                "mev_flood_seconds_per_bundle"
            ],
316 317 318
        )
        if result["mev_params"]
        else None,
319 320 321 322
        dora_params=struct(
            image=result["dora_params"]["image"],
            env=result["dora_params"]["env"],
        ),
323 324 325
        tx_spammer_params=struct(
            tx_spammer_extra_args=result["tx_spammer_params"]["tx_spammer_extra_args"],
        ),
326 327 328
        goomy_blob_params=struct(
            goomy_blob_args=result["goomy_blob_params"]["goomy_blob_args"],
        ),
329
        apache_port=result["apache_port"],
330
        assertoor_params=struct(
331
            image=result["assertoor_params"]["image"],
332 333 334 335 336 337 338 339 340 341 342 343 344 345
            run_stability_check=result["assertoor_params"]["run_stability_check"],
            run_block_proposal_check=result["assertoor_params"][
                "run_block_proposal_check"
            ],
            run_lifecycle_test=result["assertoor_params"]["run_lifecycle_test"],
            run_transaction_test=result["assertoor_params"]["run_transaction_test"],
            run_blob_transaction_test=result["assertoor_params"][
                "run_blob_transaction_test"
            ],
            run_opcodes_transaction_test=result["assertoor_params"][
                "run_opcodes_transaction_test"
            ],
            tests=result["assertoor_params"]["tests"],
        ),
346 347 348 349 350
        custom_flood_params=struct(
            interval_between_transactions=result["custom_flood_params"][
                "interval_between_transactions"
            ],
        ),
351 352
        additional_services=result["additional_services"],
        wait_for_finalization=result["wait_for_finalization"],
353
        global_log_level=result["global_log_level"],
354 355
        mev_type=result["mev_type"],
        snooper_enabled=result["snooper_enabled"],
356
        ethereum_metrics_exporter_enabled=result["ethereum_metrics_exporter_enabled"],
357
        xatu_sentry_enabled=result["xatu_sentry_enabled"],
358
        parallel_keystore_generation=result["parallel_keystore_generation"],
359
        grafana_additional_dashboards=result["grafana_additional_dashboards"],
360
        disable_peer_scoring=result["disable_peer_scoring"],
361
        persistent=result["persistent"],
362 363 364 365 366 367 368
        xatu_sentry_params=struct(
            xatu_sentry_image=result["xatu_sentry_params"]["xatu_sentry_image"],
            xatu_server_addr=result["xatu_sentry_params"]["xatu_server_addr"],
            xatu_server_headers=result["xatu_sentry_params"]["xatu_server_headers"],
            beacon_subscriptions=result["xatu_sentry_params"]["beacon_subscriptions"],
            xatu_server_tls=result["xatu_sentry_params"]["xatu_server_tls"],
        ),
369
        global_tolerations=result["global_tolerations"],
370
        global_node_selectors=result["global_node_selectors"],
371
        keymanager_enabled=result["keymanager_enabled"],
372 373 374 375 376 377
        port_publisher=struct(
            public_port_start=result["port_publisher"]["public_port_start"],
            nat_exit_ip=result["port_publisher"]["nat_exit_ip"],
            el_start=result["port_publisher"].get("el_start"),
            cl_start=result["port_publisher"].get("cl_start"),
        ),
378 379
    )

Gyanendra Mishra's avatar
Gyanendra Mishra committed
380

381
def parse_network_params(plan, input_args):
382
    result = default_input_args(input_args)
383 384
    if input_args.get("network_params", {}).get("preset") == "minimal":
        result["network_params"] = default_minimal_network_params()
385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418

    # Ensure we handle matrix participants before standard participants are handled.
    if "participants_matrix" in input_args:
        participants_matrix = []
        participants = []

        el_matrix = []
        if "el" in input_args["participants_matrix"]:
            el_matrix = input_args["participants_matrix"]["el"]
        cl_matrix = []
        if "cl" in input_args["participants_matrix"]:
            cl_matrix = input_args["participants_matrix"]["cl"]
        vc_matrix = []
        if "vc" in input_args["participants_matrix"]:
            vc_matrix = input_args["participants_matrix"]["vc"]

        for el in el_matrix:
            for cl in cl_matrix:
                participant = {k: v for k, v in el.items()}
                for k, v in cl.items():
                    participant[k] = v

                participants.append(participant)

        for index, participant in enumerate(participants):
            for vc in vc_matrix:
                for k, v in vc.items():
                    participants[index][k] = v

        if "participants" in input_args:
            input_args["participants"].extend(participants)
        else:
            input_args["participants"] = participants

419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443
    for attr in input_args:
        value = input_args[attr]
        # if its insterted we use the value inserted
        if attr not in ATTR_TO_BE_SKIPPED_AT_ROOT and attr in input_args:
            result[attr] = value
        elif attr == "network_params":
            for sub_attr in input_args["network_params"]:
                sub_value = input_args["network_params"][sub_attr]
                result["network_params"][sub_attr] = sub_value
        elif attr == "participants":
            participants = []
            for participant in input_args["participants"]:
                new_participant = default_participant()
                for sub_attr, sub_value in participant.items():
                    # if the value is set in input we set it in participant
                    new_participant[sub_attr] = sub_value
                for _ in range(0, new_participant["count"]):
                    participant_copy = deep_copy_participant(new_participant)
                    participants.append(participant_copy)
            result["participants"] = participants

    total_participant_count = 0
    actual_num_validators = 0
    # validation of the above defaults
    for index, participant in enumerate(result["participants"]):
444 445 446
        el_type = participant["el_type"]
        cl_type = participant["cl_type"]
        vc_type = participant["vc_type"]
447

448 449 450 451
        if (
            cl_type in (constants.CL_TYPE.nimbus)
            and (result["network_params"]["seconds_per_slot"] < 12)
            and result["network_params"]["preset"] == "mainnet"
452
        ):
453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468
            fail(
                "nimbus can't be run with slot times below 12 seconds with "
                + result["network_params"]["preset"]
                + " preset"
            )

        if (
            cl_type in (constants.CL_TYPE.nimbus)
            and (result["network_params"]["seconds_per_slot"] != 6)
            and result["network_params"]["preset"] == "minimal"
        ):
            fail(
                "nimbus can't be run with slot times different than 6 seconds with "
                + result["network_params"]["preset"]
                + " preset"
            )
469

470
        el_image = participant["el_image"]
471
        if el_image == "":
472
            default_image = DEFAULT_EL_IMAGES.get(el_type, "")
473 474 475
            if default_image == "":
                fail(
                    "{0} received an empty image name and we don't have a default for it".format(
476
                        el_type
477 478
                    )
                )
479
            participant["el_image"] = default_image
480

481
        cl_image = participant["cl_image"]
482
        if cl_image == "":
483 484 485 486
            if result["network_params"]["preset"] == "minimal":
                default_image = DEFAULT_CL_IMAGES_MINIMAL.get(cl_type, "")
            else:
                default_image = DEFAULT_CL_IMAGES.get(cl_type, "")
487 488 489
            if default_image == "":
                fail(
                    "{0} received an empty image name and we don't have a default for it".format(
490
                        cl_type
491 492
                    )
                )
493
            participant["cl_image"] = default_image
494

495
        if participant["use_separate_vc"] == None:
496 497
            # Default to false for CL clients that can run validator clients
            # in the same process.
498 499 500 501 502 503 504 505
            if (
                cl_type
                in (
                    constants.CL_TYPE.nimbus,
                    constants.CL_TYPE.teku,
                    constants.CL_TYPE.grandine,
                )
                and vc_type == ""
506
            ):
507
                participant["use_separate_vc"] = False
508
            else:
509
                participant["use_separate_vc"] = True
510

511
        if vc_type == "":
512
            # Defaults to matching the chosen CL client
513 514
            vc_type = cl_type
            participant["vc_type"] = vc_type
515

516 517
        vc_image = participant["vc_image"]
        if vc_image == "":
518
            if cl_image == "" or vc_type != cl_type:
519
                # If the validator client image is also empty, default to the image for the chosen CL client
520 521 522 523
                if result["network_params"]["preset"] == "minimal":
                    default_image = DEFAULT_VC_IMAGES_MINIMAL.get(vc_type, "")
                else:
                    default_image = DEFAULT_VC_IMAGES.get(vc_type, "")
524
            else:
525
                if cl_type == "prysm":
526
                    default_image = cl_image.replace("beacon-chain", "validator")
527
                elif cl_type == "nimbus":
528 529 530 531 532
                    default_image = cl_image.replace(
                        "nimbus-eth2", "nimbus-validator-client"
                    )
                else:
                    default_image = cl_image
533 534 535
            if default_image == "":
                fail(
                    "{0} received an empty image name and we don't have a default for it".format(
536
                        vc_type
537 538
                    )
                )
539
            participant["vc_image"] = default_image
540

541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564
        if result["parallel_keystore_generation"] and participant["vc_count"] != 1:
            fail(
                "parallel_keystore_generation is only supported for 1 validator client per participant (for now)"
            )

        # If the num validator keys per node is not divisible by vc_count of a participant, fail
        if (
            participant["vc_count"] > 0
            and result["network_params"]["num_validator_keys_per_node"]
            % participant["vc_count"]
            != 0
        ):
            fail(
                "num_validator_keys_per_node: {0} is not divisible by vc_count: {1} for participant: {2}".format(
                    result["network_params"]["num_validator_keys_per_node"],
                    participant["vc_count"],
                    str(index + 1)
                    + "-"
                    + participant["el_type"]
                    + "-"
                    + participant["cl_type"],
                )
            )

565
        snooper_enabled = participant["snooper_enabled"]
566 567
        if snooper_enabled == None:
            participant["snooper_enabled"] = result["snooper_enabled"]
568

569
        keymanager_enabled = participant["keymanager_enabled"]
570 571
        if keymanager_enabled == None:
            participant["keymanager_enabled"] = result["keymanager_enabled"]
572

573 574 575
        ethereum_metrics_exporter_enabled = participant[
            "ethereum_metrics_exporter_enabled"
        ]
576 577 578 579
        if ethereum_metrics_exporter_enabled == None:
            participant["ethereum_metrics_exporter_enabled"] = result[
                "ethereum_metrics_exporter_enabled"
            ]
580

581
        xatu_sentry_enabled = participant["xatu_sentry_enabled"]
582 583
        if xatu_sentry_enabled == None:
            participant["xatu_sentry_enabled"] = result["xatu_sentry_enabled"]
584

585 586 587
        blobber_enabled = participant["blobber_enabled"]
        if blobber_enabled:
            # unless we are running lighthouse, we don't support blobber
588
            if participant["cl_type"] != constants.CL_TYPE.lighthouse:
589 590
                fail(
                    "blobber is not supported for {0} client".format(
591
                        participant["cl_type"]
592 593 594
                    )
                )

595 596
        validator_count = participant["validator_count"]
        if validator_count == None:
597
            participant["validator_count"] = result["network_params"][
598 599 600 601 602
                "num_validator_keys_per_node"
            ]

        actual_num_validators += participant["validator_count"]

603 604
        cl_extra_params = participant.get("cl_extra_params", [])
        participant["cl_extra_params"] = cl_extra_params
605

606 607
        vc_extra_params = participant.get("vc_extra_params", [])
        participant["vc_extra_params"] = vc_extra_params
608 609 610

        total_participant_count += participant["count"]

611 612 613 614 615
    if total_participant_count == 1:
        for index, participant in enumerate(result["participants"]):
            # If there is only one participant, we run lodestar as a single node mode
            if participant["cl_type"] == constants.CL_TYPE.lodestar:
                participant["cl_extra_params"].append("--sync.isSingleNode")
616 617 618
                participant["cl_extra_params"].append(
                    "--network.allowPublishToZeroPeers"
                )
619

620 621 622 623 624 625 626 627
    if result["network_params"]["network_id"].strip() == "":
        fail("network_id is empty or spaces it needs to be of non zero length")

    if result["network_params"]["deposit_contract_address"].strip() == "":
        fail(
            "deposit_contract_address is empty or spaces it needs to be of non zero length"
        )

628 629 630 631
    if (
        result["network_params"]["network"] == "kurtosis"
        or constants.NETWORK_NAME.shadowfork in result["network_params"]["network"]
    ):
632 633 634 635 636 637 638
        if (
            result["network_params"]["preregistered_validator_keys_mnemonic"].strip()
            == ""
        ):
            fail(
                "preregistered_validator_keys_mnemonic is empty or spaces it needs to be of non zero length"
            )
639 640 641 642

    if result["network_params"]["seconds_per_slot"] == 0:
        fail("seconds_per_slot is 0 needs to be > 0 ")

643 644 645 646
    if (
        result["network_params"]["network"] == constants.NETWORK_NAME.kurtosis
        or constants.NETWORK_NAME.shadowfork in result["network_params"]["network"]
    ):
647 648 649 650 651
        if MIN_VALIDATORS > actual_num_validators:
            fail(
                "We require at least {0} validators but got {1}".format(
                    MIN_VALIDATORS, actual_num_validators
                )
652
            )
653 654 655 656
    else:
        # Don't allow validators on non-kurtosis networks
        for participant in result["participants"]:
            participant["validator_count"] = 0
657

658 659 660 661 662 663 664 665 666 667 668
    if result["network_params"]["preset"] not in ["mainnet", "minimal"]:
        fail(
            "preset "
            + result["network_params"]["preset"]
            + " is not supported, it can only be mainnet or minimal"
        )

    if result["network_params"]["preset"] == "minimal":
        if result["network_params"]["deneb_fork_epoch"] > 0:
            fail("minimal preset only supports deneb genesis fork epoch")

669 670 671 672 673 674
    return result


def get_client_log_level_or_default(
    participant_log_level, global_log_level, client_log_levels
):
675
    log_level = client_log_levels.get(participant_log_level, "")
676 677 678 679 680 681 682 683 684 685 686
    if log_level == "":
        log_level = client_log_levels.get(global_log_level, "")
        if log_level == "":
            fail(
                "No participant log level defined, and the client log level has no mapping for global log level '{0}'".format(
                    global_log_level
                )
            )
    return log_level


687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724
def get_client_tolerations(
    specific_container_toleration, participant_tolerations, global_tolerations
):
    toleration_list = []
    tolerations = []
    tolerations = specific_container_toleration if specific_container_toleration else []
    if not tolerations:
        tolerations = participant_tolerations if participant_tolerations else []
        if not tolerations:
            tolerations = global_tolerations if global_tolerations else []

    if tolerations != []:
        for toleration_data in tolerations:
            if toleration_data.get("toleration_seconds"):
                toleration_list.append(
                    Toleration(
                        key=toleration_data.get("key", ""),
                        value=toleration_data.get("value", ""),
                        operator=toleration_data.get("operator", ""),
                        effect=toleration_data.get("effect", ""),
                        toleration_seconds=toleration_data.get("toleration_seconds"),
                    )
                )
            # Gyani has to fix this in the future
            # https://github.com/kurtosis-tech/kurtosis/issues/2093
            else:
                toleration_list.append(
                    Toleration(
                        key=toleration_data.get("key", ""),
                        value=toleration_data.get("value", ""),
                        operator=toleration_data.get("operator", ""),
                        effect=toleration_data.get("effect", ""),
                    )
                )

    return toleration_list


725 726 727 728 729 730 731 732 733
def get_client_node_selectors(participant_node_selectors, global_node_selectors):
    node_selectors = {}
    node_selectors = participant_node_selectors if participant_node_selectors else {}
    if node_selectors == {}:
        node_selectors = global_node_selectors if global_node_selectors else {}

    return node_selectors


734
def default_input_args(input_args):
735
    network_params = default_network_params()
736 737 738 739 740
    if "participants_matrix" not in input_args:
        participants = [default_participant()]
    else:
        participants = []

741
    participants_matrix = []
742 743
    return {
        "participants": participants,
744
        "participants_matrix": participants_matrix,
745 746
        "network_params": network_params,
        "wait_for_finalization": False,
747
        "global_log_level": "info",
748
        "snooper_enabled": False,
749
        "ethereum_metrics_exporter_enabled": False,
750
        "parallel_keystore_generation": False,
751
        "disable_peer_scoring": False,
752 753 754
        "persistent": False,
        "mev_type": None,
        "xatu_sentry_enabled": False,
755
        "apache_port": None,
756
        "global_tolerations": [],
757
        "global_node_selectors": {},
758
        "keymanager_enabled": False,
759 760 761 762
        "port_publisher": {
            "nat_exit_ip": constants.PRIVATE_IP_ADDRESS_PLACEHOLDER,
            "public_port_start": None,
        },
763 764 765 766 767
    }


def default_network_params():
    return {
768
        "network": "kurtosis",
769 770 771
        "network_id": "3151908",
        "deposit_contract_address": "0x4242424242424242424242424242424242424242",
        "seconds_per_slot": 12,
772 773 774
        "num_validator_keys_per_node": 64,
        "preregistered_validator_keys_mnemonic": "giant issue aisle success illegal bike spike question tent bar rely arctic volcano long crawl hungry vocal artwork sniff fantasy very lucky have athlete",
        "preregistered_validator_count": 0,
775
        "genesis_delay": 20,
776 777
        "max_per_epoch_activation_churn_limit": 8,
        "churn_limit_quotient": 65536,
778
        "ejection_balance": 16000000000,
779
        "eth1_follow_distance": 2048,
780 781
        "min_validator_withdrawability_delay": 256,
        "shard_committee_period": 256,
782
        "deneb_fork_epoch": 0,
783 784
        "electra_fork_epoch": 100000000,
        "eip7594_fork_epoch": 100000001,
785
        "eip7594_fork_version": "0x70000038",
786
        "network_sync_base_url": "https://ethpandaops-ethereum-node-snapshots.ams3.digitaloceanspaces.com/",
787 788 789 790
        "data_column_sidecar_subnet_count": 32,
        "samples_per_slot": 8,
        "custody_requirement": 1,
        "target_number_of_peers": 70,
791
        "preset": "mainnet",
792 793 794
    }


795 796 797 798 799 800 801 802 803 804
def default_minimal_network_params():
    return {
        "network": "kurtosis",
        "network_id": "3151908",
        "deposit_contract_address": "0x4242424242424242424242424242424242424242",
        "seconds_per_slot": 6,
        "num_validator_keys_per_node": 64,
        "preregistered_validator_keys_mnemonic": "giant issue aisle success illegal bike spike question tent bar rely arctic volcano long crawl hungry vocal artwork sniff fantasy very lucky have athlete",
        "preregistered_validator_count": 0,
        "genesis_delay": 20,
805 806
        "max_per_epoch_activation_churn_limit": 4,
        "churn_limit_quotient": 32,
807 808 809 810 811
        "ejection_balance": 16000000000,
        "eth1_follow_distance": 16,
        "min_validator_withdrawability_delay": 256,
        "shard_committee_period": 64,
        "deneb_fork_epoch": 0,
812 813
        "electra_fork_epoch": 100000000,
        "eip7594_fork_epoch": 100000001,
814
        "eip7594_fork_version": "0x70000038",
815
        "network_sync_base_url": "https://ethpandaops-ethereum-node-snapshots.ams3.digitaloceanspaces.com/",
816 817 818 819
        "data_column_sidecar_subnet_count": 32,
        "samples_per_slot": 8,
        "custody_requirement": 1,
        "target_number_of_peers": 70,
820 821 822 823
        "preset": "minimal",
    }


824 825
def default_participant():
    return {
826 827 828
        "el_type": "geth",
        "el_image": "",
        "el_log_level": "",
829 830
        "el_extra_env_vars": {},
        "el_extra_labels": {},
831
        "el_extra_params": [],
832
        "el_tolerations": [],
833
        "el_volume_size": 0,
834 835 836 837
        "el_min_cpu": 0,
        "el_max_cpu": 0,
        "el_min_mem": 0,
        "el_max_mem": 0,
838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853
        "cl_type": "lighthouse",
        "cl_image": "",
        "cl_log_level": "",
        "cl_extra_env_vars": {},
        "cl_extra_labels": {},
        "cl_extra_params": [],
        "cl_tolerations": [],
        "cl_volume_size": 0,
        "cl_min_cpu": 0,
        "cl_max_cpu": 0,
        "cl_min_mem": 0,
        "cl_max_mem": 0,
        "use_separate_vc": None,
        "vc_type": "",
        "vc_image": "",
        "vc_log_level": "",
854
        "vc_count": 1,
855 856 857 858 859 860 861 862
        "vc_extra_env_vars": {},
        "vc_extra_labels": {},
        "vc_extra_params": [],
        "vc_tolerations": [],
        "vc_min_cpu": 0,
        "vc_max_cpu": 0,
        "vc_min_mem": 0,
        "vc_max_mem": 0,
863
        "validator_count": None,
864 865 866
        "node_selectors": {},
        "tolerations": [],
        "count": 1,
867 868 869
        "snooper_enabled": None,
        "ethereum_metrics_exporter_enabled": None,
        "xatu_sentry_enabled": None,
870 871 872 873
        "prometheus_config": {
            "scrape_interval": "15s",
            "labels": None,
        },
874 875
        "blobber_enabled": False,
        "blobber_extra_params": [],
876
        "builder_network_params": None,
877
        "keymanager_enabled": None,
878 879 880
    }


881 882 883 884 885 886 887
def get_default_dora_params():
    return {
        "image": "",
        "env": {},
    }


888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925
def get_default_mev_params(mev_type, preset):
    mev_relay_image = constants.DEFAULT_FLASHBOTS_RELAY_IMAGE
    mev_builder_image = constants.DEFAULT_FLASHBOTS_BUILDER_IMAGE
    if preset == "minimal":
        mev_builder_cl_image = DEFAULT_CL_IMAGES_MINIMAL[constants.CL_TYPE.lighthouse]
    else:
        mev_builder_cl_image = DEFAULT_CL_IMAGES[constants.CL_TYPE.lighthouse]
    mev_builder_extra_data = None
    mev_boost_image = constants.DEFAULT_FLASHBOTS_MEV_BOOST_IMAGE
    mev_boost_args = ["mev-boost", "--relay-check"]
    mev_relay_api_extra_args = []
    mev_relay_housekeeper_extra_args = []
    mev_relay_website_extra_args = []
    mev_builder_extra_args = []
    mev_flood_image = "flashbots/mev-flood"
    mev_flood_extra_args = []
    mev_flood_seconds_per_bundle = 15
    mev_builder_prometheus_config = {
        "scrape_interval": "15s",
        "labels": None,
    }

    if mev_type == constants.MEV_RS_MEV_TYPE:
        if preset == "minimal":
            mev_relay_image = constants.DEFAULT_MEV_RS_IMAGE_MINIMAL
            mev_builder_image = constants.DEFAULT_MEV_RS_IMAGE_MINIMAL
            mev_builder_cl_image = DEFAULT_CL_IMAGES_MINIMAL[
                constants.CL_TYPE.lighthouse
            ]
            mev_boost_image = constants.DEFAULT_MEV_RS_IMAGE_MINIMAL
        else:
            mev_relay_image = constants.DEFAULT_MEV_RS_IMAGE
            mev_builder_image = constants.DEFAULT_MEV_RS_IMAGE
            mev_builder_cl_image = DEFAULT_CL_IMAGES[constants.CL_TYPE.lighthouse]
            mev_boost_image = constants.DEFAULT_MEV_RS_IMAGE
        mev_builder_extra_data = "0x68656C6C6F20776F726C640A"  # "hello world\n"
        mev_builder_extra_args = ["--mev-builder-config=" + "/config/config.toml"]

926
    return {
927 928 929 930 931 932 933 934 935 936 937 938 939 940
        "mev_relay_image": mev_relay_image,
        "mev_builder_image": mev_builder_image,
        "mev_builder_cl_image": mev_builder_cl_image,
        "mev_builder_extra_data": mev_builder_extra_data,
        "mev_builder_extra_args": mev_builder_extra_args,
        "mev_boost_image": mev_boost_image,
        "mev_boost_args": mev_boost_args,
        "mev_relay_api_extra_args": mev_relay_api_extra_args,
        "mev_relay_housekeeper_extra_args": mev_relay_housekeeper_extra_args,
        "mev_relay_website_extra_args": mev_relay_website_extra_args,
        "mev_flood_image": mev_flood_image,
        "mev_flood_extra_args": mev_flood_extra_args,
        "mev_flood_seconds_per_bundle": mev_flood_seconds_per_bundle,
        "mev_builder_prometheus_config": mev_builder_prometheus_config,
941 942
    }

943

944
def get_default_tx_spammer_params():
945 946
    return {"tx_spammer_extra_args": []}

947

948 949 950 951
def get_default_goomy_blob_params():
    return {"goomy_blob_args": []}


952 953
def get_default_assertoor_params():
    return {
954
        "image": "",
955 956 957 958 959 960 961 962 963 964
        "run_stability_check": True,
        "run_block_proposal_check": True,
        "run_lifecycle_test": False,
        "run_transaction_test": False,
        "run_blob_transaction_test": False,
        "run_opcodes_transaction_test": False,
        "tests": [],
    }


965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983
def get_default_xatu_sentry_params():
    return {
        "xatu_sentry_image": "ethpandaops/xatu:latest",
        "xatu_server_addr": "localhost:8080",
        "xatu_server_headers": {},
        "xatu_server_tls": False,
        "beacon_subscriptions": [
            "attestation",
            "block",
            "chain_reorg",
            "finalized_checkpoint",
            "head",
            "voluntary_exit",
            "contribution_and_proof",
            "blob_sidecar",
        ],
    }


984 985 986 987 988
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}


989 990
def enrich_disable_peer_scoring(parsed_arguments_dict):
    for index, participant in enumerate(parsed_arguments_dict["participants"]):
991 992 993 994 995 996 997 998
        if participant["cl_type"] == "lighthouse":
            participant["cl_extra_params"].append("--disable-peer-scoring")
        if participant["cl_type"] == "prysm":
            participant["cl_extra_params"].append("--disable-peer-scorer")
        if participant["cl_type"] == "teku":
            participant["cl_extra_params"].append("--Xp2p-gossip-scoring-enabled")
        if participant["cl_type"] == "lodestar":
            participant["cl_extra_params"].append("--disablePeerScoring")
999 1000
        if participant["cl_type"] == "grandine":
            participant["cl_extra_params"].append("--disable-peer-scoring")
1001 1002 1003
    return parsed_arguments_dict


1004
# TODO perhaps clean this up into a map
1005
def enrich_mev_extra_params(parsed_arguments_dict, mev_prefix, mev_port, mev_type):
1006
    for index, participant in enumerate(parsed_arguments_dict["participants"]):
1007 1008 1009
        index_str = shared_utils.zfill_custom(
            index + 1, len(str(len(parsed_arguments_dict["participants"])))
        )
1010 1011
        mev_url = "http://{0}-{1}-{2}-{3}:{4}".format(
            MEV_BOOST_SERVICE_NAME_PREFIX,
1012
            index_str,
1013 1014
            participant["cl_type"],
            participant["el_type"],
1015 1016
            mev_port,
        )
1017

1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028
        if participant["cl_type"] == "lighthouse":
            participant["vc_extra_params"].append("--builder-proposals")
            participant["cl_extra_params"].append("--builder={0}".format(mev_url))
        if participant["cl_type"] == "lodestar":
            participant["vc_extra_params"].append("--builder")
            participant["cl_extra_params"].append("--builder")
            participant["cl_extra_params"].append("--builder.urls={0}".format(mev_url))
        if participant["cl_type"] == "nimbus":
            participant["vc_extra_params"].append("--payload-builder=true")
            participant["cl_extra_params"].append("--payload-builder=true")
            participant["cl_extra_params"].append(
1029
                "--payload-builder-url={0}".format(mev_url)
1030
            )
1031 1032
        if participant["cl_type"] == "teku":
            participant["vc_extra_params"].append(
1033 1034
                "--validators-builder-registration-default-enabled=true"
            )
1035
            participant["cl_extra_params"].append(
1036 1037
                "--builder-endpoint={0}".format(mev_url)
            )
1038 1039 1040
            participant["cl_extra_params"].append(
                "--validators-builder-registration-default-enabled=true"
            )
1041 1042 1043
        if participant["cl_type"] == "prysm":
            participant["vc_extra_params"].append("--enable-builder")
            participant["cl_extra_params"].append(
1044 1045
                "--http-mev-relay={0}".format(mev_url)
            )
1046 1047
        if participant["cl_type"] == "grandine":
            participant["cl_extra_params"].append("--builder-url={0}".format(mev_url))
1048 1049

    num_participants = len(parsed_arguments_dict["participants"])
1050 1051 1052
    index_str = shared_utils.zfill_custom(
        num_participants + 1, len(str(num_participants + 1))
    )
1053
    if mev_type == constants.FLASHBOTS_MEV_TYPE:
1054
        mev_participant = default_participant()
1055
        mev_participant["el_type"] = "geth-builder"
1056 1057
        mev_participant.update(
            {
1058 1059
                "el_image": parsed_arguments_dict["mev_params"]["mev_builder_image"],
                "cl_image": parsed_arguments_dict["mev_params"]["mev_builder_cl_image"],
1060
                "cl_log_level": parsed_arguments_dict["global_log_level"],
1061
                "cl_extra_params": [
1062 1063 1064
                    "--always-prepare-payload",
                    "--prepare-payload-lookahead",
                    "12000",
1065
                    "--disable-peer-scoring",
1066 1067 1068 1069 1070
                ],
                # TODO(maybe) make parts of this more passable like the mev-relay-endpoint & forks
                "el_extra_params": [
                    "--builder",
                    "--builder.remote_relay_endpoint=http://mev-relay-api:9062",
1071 1072
                    "--builder.beacon_endpoints=http://cl-{0}-lighthouse-geth-builder:4000".format(
                        index_str
1073
                    ),
1074 1075 1076 1077 1078 1079
                    "--builder.bellatrix_fork_version={0}".format(
                        constants.BELLATRIX_FORK_VERSION
                    ),
                    "--builder.genesis_fork_version={0}".format(
                        constants.GENESIS_FORK_VERSION
                    ),
1080
                    "--builder.genesis_validators_root={0}".format(
1081
                        constants.GENESIS_VALIDATORS_ROOT_PLACEHOLDER
1082 1083 1084
                    ),
                    '--miner.extradata="Illuminate Dmocratize Dstribute"',
                    "--builder.algotype=greedy",
1085
                    "--metrics.builder",
1086 1087 1088 1089 1090 1091 1092
                ]
                + parsed_arguments_dict["mev_params"]["mev_builder_extra_args"],
                "el_extra_env_vars": {
                    "BUILDER_TX_SIGNING_KEY": "0x"
                    + genesis_constants.PRE_FUNDED_ACCOUNTS[0].private_key
                },
                "validator_count": 0,
1093 1094 1095
                "prometheus_config": parsed_arguments_dict["mev_params"][
                    "mev_builder_prometheus_config"
                ],
1096 1097
            }
        )
1098 1099 1100

        parsed_arguments_dict["participants"].append(mev_participant)

1101 1102 1103 1104 1105 1106 1107
    if mev_type == constants.MEV_RS_MEV_TYPE:
        mev_participant = default_participant()
        mev_participant["el_type"] = "reth-builder"
        mev_participant.update(
            {
                "el_image": parsed_arguments_dict["mev_params"]["mev_builder_image"],
                "cl_image": parsed_arguments_dict["mev_params"]["mev_builder_cl_image"],
1108
                "cl_log_level": parsed_arguments_dict["global_log_level"],
1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121
                "cl_extra_params": [
                    "--always-prepare-payload",
                    "--prepare-payload-lookahead",
                    "12000",
                    "--disable-peer-scoring",
                ],
                "el_extra_params": parsed_arguments_dict["mev_params"][
                    "mev_builder_extra_args"
                ],
                "validator_count": 0,
            }
        )
        parsed_arguments_dict["participants"].append(mev_participant)
1122
    return parsed_arguments_dict
1123 1124 1125 1126 1127 1128 1129 1130 1131 1132


def deep_copy_participant(participant):
    part = {}
    for k, v in participant.items():
        if type(v) == type([]):
            part[k] = list(v)
        else:
            part[k] = v
    return part
1133 1134 1135 1136 1137 1138 1139


def get_public_ip(plan):
    response = plan.run_sh(
        run="curl -s https://ident.me",
    )
    return response.output