diff --git a/.github/tests/blockscout.yaml b/.github/tests/blockscout.yaml new file mode 100644 index 0000000..7fd40db --- /dev/null +++ b/.github/tests/blockscout.yaml @@ -0,0 +1,23 @@ +optimism_package: + - participants: + - el_type: op-geth + network_params: + name: op-rollup-one + network_id: '3151909' + additional_services: + - blockscout + - participants: + - el_type: op-geth + network_params: + name: op-rollup-two + network_id: '3151910' + additional_services: + - blockscout +ethereum_package: + participants: + - el_type: geth + - el_type: reth + network_params: + preset: minimal + additional_services: + - blockscout diff --git a/.github/tests/multiple_l2s.yaml b/.github/tests/multiple_l2s.yaml index 4aea777..f0d3606 100644 --- a/.github/tests/multiple_l2s.yaml +++ b/.github/tests/multiple_l2s.yaml @@ -1,18 +1,16 @@ optimism_package: - - participants: - - el_type: op-geth - network_params: - name: op-rollup-one - network_id: "3151909" - additional_services: - - blockscout - - participants: - - el_type: op-geth - network_params: - name: op-rollup-two - network_id: "3151910" - additional_services: - - blockscout + - participants: + - el_type: op-geth + network_params: + name: op-rollup-one + network_id: '3151909' + additional_services: [] + - participants: + - el_type: op-geth + network_params: + name: op-rollup-two + network_id: '3151910' + additional_services: [] ethereum_package: participants: - el_type: geth @@ -21,4 +19,3 @@ ethereum_package: preset: minimal additional_services: - dora - - blockscout diff --git a/.github/tests/op-erigon.yaml b/.github/tests/op-erigon.yaml new file mode 100644 index 0000000..61b150b --- /dev/null +++ b/.github/tests/op-erigon.yaml @@ -0,0 +1,12 @@ +optimism_package: + participants: + - el_type: op-erigon + cl_type: op-node +ethereum_package: + participants: + - el_type: geth + - el_type: reth + network_params: + preset: minimal + additional_services: + - dora diff --git a/.github/tests/op-geth.yaml b/.github/tests/op-geth.yaml index ab1fbe0..1a3085b 100644 --- a/.github/tests/op-geth.yaml +++ b/.github/tests/op-geth.yaml @@ -8,4 +8,5 @@ ethereum_package: - el_type: reth network_params: preset: minimal - + additional_services: + - dora diff --git a/.github/tests/op-node.yaml b/.github/tests/op-node.yaml index dcfde61..0b3bf5a 100644 --- a/.github/tests/op-node.yaml +++ b/.github/tests/op-node.yaml @@ -4,6 +4,8 @@ optimism_package: cl_type: op-node - el_type: op-reth cl_type: op-node + - el_type: op-erigon + cl_type: op-node ethereum_package: participants: - el_type: geth @@ -12,4 +14,3 @@ ethereum_package: preset: minimal additional_services: - dora - diff --git a/.github/tests/op-reth.yaml b/.github/tests/op-reth.yaml index 7143b12..0d65a6a 100644 --- a/.github/tests/op-reth.yaml +++ b/.github/tests/op-reth.yaml @@ -8,4 +8,5 @@ ethereum_package: - el_type: reth network_params: preset: minimal - + additional_services: + - dora diff --git a/.github/tests/single_l2.yaml b/.github/tests/single_l2.yaml index 4397e77..dde7e3f 100644 --- a/.github/tests/single_l2.yaml +++ b/.github/tests/single_l2.yaml @@ -7,4 +7,5 @@ ethereum_package: - el_type: reth network_params: preset: minimal - + additional_services: + - dora diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index a552840..f94d784 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -41,10 +41,10 @@ jobs: echo "Skipping ./.github/tests/mix-with-tools-mev.yaml" fi - # - name: Notify - # if: cancelled() || failure() - # uses: Ilshidur/action-discord@master - # env: - # DISCORD_WEBHOOK: ${{ secrets.DISCORD_WEBHOOK }} - # with: - # args: "The nightly test for ${{matrix.file_name}} on ethereum-package has failed find it here ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}" + - name: Notify + if: cancelled() || failure() + uses: Ilshidur/action-discord@master + env: + DISCORD_WEBHOOK: ${{ secrets.DISCORD_WEBHOOK }} + with: + args: "The nightly test for ${{matrix.file_name}} on ethereum-package has failed find it here ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}" diff --git a/README.md b/README.md index ecc84e2..8523085 100644 --- a/README.md +++ b/README.md @@ -45,18 +45,23 @@ optimism_package: participants: # EL(Execution Layer) Specific flags # The type of EL client that should be started - # Valid values are op-geth, op-reth + # Valid values are: + # op-geth + # op-reth + # op-erigon - el_type: geth # The Docker image that should be used for the EL client; leave blank to use the default for the client type # Defaults by client: # - op-geth: us-docker.pkg.dev/oplabs-tools-artifacts/images/op-geth:latest # - op-reth: parithoshj/op-reth:latest + # - op-erigon: testinprod/op-erigon:latest el_image: "" # CL(Consensus Layer) Specific flags # The type of CL client that should be started - # Valid values are op-node, ? + # Valid values are: + # op-node cl_type: op-node # The Docker image that should be used for the CL client; leave blank to use the default for the client type @@ -72,16 +77,21 @@ optimism_package: network_params: # Network name, used to enable syncing of alternative networks # Defaults to "kurtosis" - # You can sync any public network by setting this to the network name (e.g. "mainnet", "sepolia", "holesky") - # You can sync any devnet by setting this to the network name (e.g. "dencun-devnet-12", "verkle-gen-devnet-2") network: "kurtosis" # The network ID of the network. + # Must be unique for each network (if you run multiple networks) + # Defaults to "2151908" network_id: "2151908" # Seconds per slots seconds_per_slot: 2 + # Name of your rollup. + # Must be unique for each rollup (if you run multiple rollups) + # Defaults to "op-kurtosis" + name: "op-kurtosis" + # Additional services to run alongside the network # Defaults to [] # Available services: diff --git a/main.star b/main.star index 0ffeaa2..7d03b30 100644 --- a/main.star +++ b/main.star @@ -20,7 +20,7 @@ def run(plan, args): # Deploy the L1 plan.print("Deploying a local L1") l1 = ethereum_package.run(plan, ethereum_args) - + plan.print(l1.network_params) # Get L1 info all_l1_participants = l1.all_participants l1_network_params = l1.network_params @@ -33,6 +33,7 @@ def run(plan, args): contract_deployer.deploy_factory_contract(plan, l1_priv_key, l1_config_env_vars) # Deploy L2s + plan.print("Deploying a local L2") if type(args["optimism_package"]) == "dict": l2_services_suffix = "" # no suffix if one l2 l2_launcher.launch_l2( diff --git a/network_params.yaml b/network_params.yaml index 63d698f..9583e57 100644 --- a/network_params.yaml +++ b/network_params.yaml @@ -2,6 +2,7 @@ optimism_package: participants: - el_type: op-geth - el_type: op-reth + - el_type: op-erigon additional_services: - blockscout ethereum_package: diff --git a/src/contracts/contract_deployer.star b/src/contracts/contract_deployer.star index 4f210f3..eb7b19f 100644 --- a/src/contracts/contract_deployer.star +++ b/src/contracts/contract_deployer.star @@ -82,8 +82,9 @@ def deploy_l2_contracts( "sleep 3", "cd /workspace/optimism/packages/contracts-bedrock", "./scripts/getting-started/config.sh", - "sleep 5", 'jq \'. + {"fundDevAccounts": true, "useInterop": true}\' $DEPLOY_CONFIG_PATH > tmp.$$.json && mv tmp.$$.json $DEPLOY_CONFIG_PATH', + # sleep till gs_admin_address is funded + "while true; do sleep 1; echo 'GS_ADMIN_ADDRESS is not yet funded...'; if [ \"$(web3 balance $GS_ADMIN_ADDRESS)\" != \"0\" ]; then echo 'GS_ADMIN_ADDRESS is funded!'; break; fi; done", "forge script scripts/Deploy.s.sol:Deploy --private-key $GS_ADMIN_PRIVATE_KEY --broadcast --rpc-url $L1_RPC_URL", "sleep 3", "CONTRACT_ADDRESSES_PATH=$DEPLOYMENT_OUTFILE forge script scripts/L2Genesis.s.sol:L2Genesis --sig 'runWithStateDump()' --chain-id $L2_CHAIN_ID", diff --git a/src/el/op-erigon/op_erigon_launcher.star b/src/el/op-erigon/op_erigon_launcher.star new file mode 100644 index 0000000..f3d1e73 --- /dev/null +++ b/src/el/op-erigon/op_erigon_launcher.star @@ -0,0 +1,227 @@ +shared_utils = import_module( + "github.com/ethpandaops/ethereum-package/src/shared_utils/shared_utils.star" +) +# input_parser = import_module("../../package_io/input_parser.star") +el_context = import_module( + "github.com/ethpandaops/ethereum-package/src/el/el_context.star" +) +el_admin_node_info = import_module( + "github.com/ethpandaops/ethereum-package/src/el/el_admin_node_info.star" +) + +node_metrics = import_module( + "github.com/ethpandaops/ethereum-package/src/node_metrics_info.star" +) +constants = import_module( + "github.com/ethpandaops/ethereum-package/src/package_io/constants.star" +) + +RPC_PORT_NUM = 8545 +WS_PORT_NUM = 8546 +DISCOVERY_PORT_NUM = 30303 +ENGINE_RPC_PORT_NUM = 8551 +METRICS_PORT_NUM = 9001 + +# The min/max CPU/memory that the execution node can use +EXECUTION_MIN_CPU = 300 +EXECUTION_MIN_MEMORY = 512 + +# Port IDs +RPC_PORT_ID = "rpc" +WS_PORT_ID = "ws" +TCP_DISCOVERY_PORT_ID = "tcp-discovery" +UDP_DISCOVERY_PORT_ID = "udp-discovery" +ENGINE_RPC_PORT_ID = "engine-rpc" +ENGINE_WS_PORT_ID = "engineWs" +METRICS_PORT_ID = "metrics" + +METRICS_PATH = "/debug/metrics/prometheus" + +# The dirpath of the execution data directory on the client container +EXECUTION_DATA_DIRPATH_ON_CLIENT_CONTAINER = "/data/op-erigon/execution-data" + + +def get_used_ports(discovery_port=DISCOVERY_PORT_NUM): + used_ports = { + RPC_PORT_ID: shared_utils.new_port_spec( + RPC_PORT_NUM, + shared_utils.TCP_PROTOCOL, + shared_utils.HTTP_APPLICATION_PROTOCOL, + ), + WS_PORT_ID: shared_utils.new_port_spec(WS_PORT_NUM, shared_utils.TCP_PROTOCOL), + TCP_DISCOVERY_PORT_ID: shared_utils.new_port_spec( + discovery_port, shared_utils.TCP_PROTOCOL + ), + UDP_DISCOVERY_PORT_ID: shared_utils.new_port_spec( + discovery_port, shared_utils.UDP_PROTOCOL + ), + ENGINE_RPC_PORT_ID: shared_utils.new_port_spec( + ENGINE_RPC_PORT_NUM, + shared_utils.TCP_PROTOCOL, + ), + METRICS_PORT_ID: shared_utils.new_port_spec( + METRICS_PORT_NUM, shared_utils.TCP_PROTOCOL + ), + } + return used_ports + + +ENTRYPOINT_ARGS = ["sh", "-c"] + +VERBOSITY_LEVELS = { + constants.GLOBAL_LOG_LEVEL.error: "1", + constants.GLOBAL_LOG_LEVEL.warn: "2", + constants.GLOBAL_LOG_LEVEL.info: "3", + constants.GLOBAL_LOG_LEVEL.debug: "4", + constants.GLOBAL_LOG_LEVEL.trace: "5", +} + + +def launch( + plan, + launcher, + service_name, + image, + existing_el_clients, + sequencer_enabled, + sequencer_context, +): + network_name = shared_utils.get_network_name(launcher.network) + + config = get_config( + plan, + launcher.el_cl_genesis_data, + launcher.jwt_file, + launcher.network, + launcher.network_id, + image, + service_name, + existing_el_clients, + sequencer_enabled, + sequencer_context, + ) + + service = plan.add_service(service_name, config) + + enode, enr = el_admin_node_info.get_enode_enr_for_node( + plan, service_name, RPC_PORT_ID + ) + + metrics_url = "{0}:{1}".format(service.ip_address, METRICS_PORT_NUM) + erigon_metrics_info = node_metrics.new_node_metrics_info( + service_name, METRICS_PATH, metrics_url + ) + + http_url = "http://{0}:{1}".format(service.ip_address, RPC_PORT_NUM) + + return el_context.new_el_context( + "op-erigon", + enr, + enode, + service.ip_address, + RPC_PORT_NUM, + WS_PORT_NUM, + ENGINE_RPC_PORT_NUM, + http_url, + service_name, + [erigon_metrics_info], + ) + + +def get_config( + plan, + el_cl_genesis_data, + jwt_file, + network, + network_id, + image, + service_name, + existing_el_clients, + sequencer_enabled, + sequencer_context, +): + init_datadir_cmd_str = "erigon init --datadir={0} {1}".format( + EXECUTION_DATA_DIRPATH_ON_CLIENT_CONTAINER, + constants.GENESIS_CONFIG_MOUNT_PATH_ON_CONTAINER + "/genesis.json", + ) + + discovery_port = DISCOVERY_PORT_NUM + used_ports = get_used_ports(discovery_port) + + cmd = [ + "erigon", + "--datadir=" + EXECUTION_DATA_DIRPATH_ON_CLIENT_CONTAINER, + "--networkid={0}".format(network_id), + "--http", + "--http.addr=0.0.0.0", + "--http.vhosts=*", + "--http.corsdomain=*", + "--http.api=admin,engine,net,eth,web3,debug", + "--ws", + "--ws.port={0}".format(WS_PORT_NUM), + "--allow-insecure-unlock", + "--authrpc.port={0}".format(ENGINE_RPC_PORT_NUM), + "--authrpc.addr=0.0.0.0", + "--authrpc.vhosts=*", + "--authrpc.jwtsecret=" + constants.JWT_MOUNT_PATH_ON_CONTAINER, + "--nat=extip:" + constants.PRIVATE_IP_ADDRESS_PLACEHOLDER, + "--rpc.allow-unprotected-txs", + "--metrics", + "--metrics.addr=0.0.0.0", + "--metrics.port={0}".format(METRICS_PORT_NUM), + "--port={0}".format(discovery_port), + ] + + if not sequencer_enabled: + cmd.append( + "--rollup.sequencerhttp={0}".format(sequencer_context.beacon_http_url) + ) + + if len(existing_el_clients) > 0: + cmd.append( + "--bootnodes=" + + ",".join( + [ + ctx.enode + for ctx in existing_el_clients[: constants.MAX_ENODE_ENTRIES] + ] + ) + ) + + cmd_str = " ".join(cmd) + if network not in constants.PUBLIC_NETWORKS: + subcommand_strs = [ + init_datadir_cmd_str, + cmd_str, + ] + command_str = " && ".join(subcommand_strs) + else: + command_str = cmd_str + + files = { + constants.GENESIS_DATA_MOUNTPOINT_ON_CLIENTS: el_cl_genesis_data, + constants.JWT_MOUNTPOINT_ON_CLIENTS: jwt_file, + } + + return ServiceConfig( + image=image, + ports=used_ports, + cmd=[command_str], + files=files, + entrypoint=ENTRYPOINT_ARGS, + private_ip_address_placeholder=constants.PRIVATE_IP_ADDRESS_PLACEHOLDER, + ) + + +def new_op_erigon_launcher( + el_cl_genesis_data, + jwt_file, + network, + network_id, +): + return struct( + el_cl_genesis_data=el_cl_genesis_data, + jwt_file=jwt_file, + network=network, + network_id=network_id, + ) diff --git a/src/el_cl_launcher.star b/src/el_cl_launcher.star index 750f3fb..7dc838f 100644 --- a/src/el_cl_launcher.star +++ b/src/el_cl_launcher.star @@ -7,6 +7,7 @@ shared_utils = import_module( # EL op_geth = import_module("./el/op-geth/op_geth_launcher.star") op_reth = import_module("./el/op-reth/op_reth_launcher.star") +op_erigon = import_module("./el/op-erigon/op_erigon_launcher.star") # CL op_node = import_module("./cl/op-node/op_node_launcher.star") @@ -41,6 +42,15 @@ def launch( ), "launch_method": op_reth.launch, }, + "op-erigon": { + "launcher": op_erigon.new_op_erigon_launcher( + el_cl_data, + jwt_file, + network_params.network, + network_params.network_id, + ), + "launch_method": op_erigon.launch, + }, } cl_launchers = { diff --git a/src/package_io/input_parser.star b/src/package_io/input_parser.star index 20a1257..24edf14 100644 --- a/src/package_io/input_parser.star +++ b/src/package_io/input_parser.star @@ -5,6 +5,7 @@ ethereum_package_input_parser = import_module( DEFAULT_EL_IMAGES = { "op-geth": "us-docker.pkg.dev/oplabs-tools-artifacts/images/op-geth:latest", "op-reth": "parithoshj/op-reth:latest", + "op-erigon": "testinprod/op-erigon:latest", } DEFAULT_CL_IMAGES = {