diff --git a/.github/tests/external-l1/deploy-local-l1.yml b/.github/tests/external-l1/deploy-local-l1.yml index 50be6cd1..b81e14c6 100644 --- a/.github/tests/external-l1/deploy-local-l1.yml +++ b/.github/tests/external-l1/deploy-local-l1.yml @@ -6,3 +6,4 @@ deployment_stages: deploy_cdk_bridge_infra: false deploy_agglayer: false deploy_cdk_erigon_node: false + deploy_l2_contracts: false diff --git a/README.md b/README.md index e88033b2..9deddb97 100644 --- a/README.md +++ b/README.md @@ -27,14 +27,14 @@ The package is flexible and supports various configurations for deploying and te > The team is actively working on enabling the use cases that are currently not possible. -| Stack | Sequencer | Sequence Sender / Aggregator | Supported by Kurtosis? | -| ----- | --------- | ---------------------------- | ---------------------- | -| New CDK stack | [cdk-erigon](https://github.com/0xPolygonHermez/cdk-erigon) | [cdk-node](https://github.com/0xPolygon/cdk) | ✅ | -| New sequencer with new zkevm stack | [cdk-erigon](https://github.com/0xPolygonHermez/cdk-erigon) | [zkevm-sequence-sender](https://github.com/0xPolygonHermez/zkevm-sequence-sender) + [zkevm-aggregator](https://github.com/0xPolygonHermez/zkevm-aggregator) | ❌ (WIP) - Check the [kurtosis-cdk-erigon](https://github.com/xavier-romero/kurtosis-cdk-erigon) package | -| New sequencer with legacy zkevm stack | [cdk-erigon](https://github.com/0xPolygonHermez/cdk-erigon) | [zkevm-node](https://github.com/0xPolygonHermez/zkevm-node) | ❌ (WIP) | -| Legacy sequencer with new cdk stack | [zkevm-node](https://github.com/0xPolygonHermez/zkevm-node) | [cdk-node](https://github.com/0xPolygon/cdk) | ❌ (WIP) | -| Legacy sequencer with new zkevm stack | [zkevm-node](https://github.com/0xPolygonHermez/zkevm-node) | [zkevm-sequence-sender](https://github.com/0xPolygonHermez/zkevm-sequence-sender) + [zkevm-aggregator](https://github.com/0xPolygonHermez/zkevm-aggregator) | ❌ (WIP) | -| Legacy zkevm stack | [zkevm-node](https://github.com/0xPolygonHermez/zkevm-node) | [zkevm-node](https://github.com/0xPolygonHermez/zkevm-node) | ✅ | +| Stack | Sequencer | Sequence Sender / Aggregator | Supported by Kurtosis? | +| ------------------------------------- | ----------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------- | +| New CDK stack | [cdk-erigon](https://github.com/0xPolygonHermez/cdk-erigon) | [cdk-node](https://github.com/0xPolygon/cdk) | ✅ | +| New sequencer with new zkevm stack | [cdk-erigon](https://github.com/0xPolygonHermez/cdk-erigon) | [zkevm-sequence-sender](https://github.com/0xPolygonHermez/zkevm-sequence-sender) + [zkevm-aggregator](https://github.com/0xPolygonHermez/zkevm-aggregator) | ❌ (WIP) - Check the [kurtosis-cdk-erigon](https://github.com/xavier-romero/kurtosis-cdk-erigon) package | +| New sequencer with legacy zkevm stack | [cdk-erigon](https://github.com/0xPolygonHermez/cdk-erigon) | [zkevm-node](https://github.com/0xPolygonHermez/zkevm-node) | ❌ (WIP) | +| Legacy sequencer with new cdk stack | [zkevm-node](https://github.com/0xPolygonHermez/zkevm-node) | [cdk-node](https://github.com/0xPolygon/cdk) | ❌ (WIP) | +| Legacy sequencer with new zkevm stack | [zkevm-node](https://github.com/0xPolygonHermez/zkevm-node) | [zkevm-sequence-sender](https://github.com/0xPolygonHermez/zkevm-sequence-sender) + [zkevm-aggregator](https://github.com/0xPolygonHermez/zkevm-aggregator) | ❌ (WIP) | +| Legacy zkevm stack | [zkevm-node](https://github.com/0xPolygonHermez/zkevm-node) | [zkevm-node](https://github.com/0xPolygonHermez/zkevm-node) | ✅ | To understand how to configure Kurtosis for these use cases, refer to the [documentation](.github/tests/README.md) and review the test files located in the `.github/tests/` directory. @@ -44,6 +44,8 @@ To understand how to configure Kurtosis for these use cases, refer to the [docum To begin, you will need to install [Docker](https://docs.docker.com/get-docker/) (>= [v4.27.0](https://docs.docker.com/desktop/release-notes/#4270) for Mac users) and [Kurtosis](https://docs.kurtosis.com/install/). +- If you notice some services, such as the `zkevm-stateless-executor` or `zkevm-prover`, consistently having the status of `STOPPED`, try increasing the Docker memory allocation. + If you intend to interact with and debug the stack, you may also want to consider a few additional optional tools such as: - [jq](https://github.com/jqlang/jq) @@ -59,8 +61,7 @@ Once that is good and installed on your system, you can run the following comman kurtosis run --enclave cdk github.com/0xPolygon/kurtosis-cdk ``` -The default deployment includes [cdk-erigon](https://github.com/0xPolygonHermez/cdk-erigon) as the sequencer, and [cdk-node](https://github.com/0xPolygon/cdk) functioning as the sequence sender and aggregator. You can verify the default versions of these components and the default fork ID by reviewing input_parser.star. You can check the default versions of the deployed components and the default fork ID by looking at -[input_parser.star](./input_parser.star). +The default deployment includes [cdk-erigon](https://github.com/0xPolygonHermez/cdk-erigon) as the sequencer, and [cdk-node](https://github.com/0xPolygon/cdk) functioning as the sequence sender and aggregator. You can verify the default versions of these components and the default fork ID by reviewing input_parser.star. You can check the default versions of the deployed components and the default fork ID by looking at [input_parser.star](./input_parser.star). To make customizations to the CDK environment, clone this repo, make any desired configuration changes, and then run: @@ -178,6 +179,7 @@ This section features documentation specifically designed for advanced users, ou - How to [run a debugger](docs/running-a-debugger/running-a-debugger.org). - How to work with the [timelock](docs/timelock.org). - How to [trigger a reorg](docs/trigger-a-reorg/trigger-a-reorg.md). +- How to [deploy contracts with the deterministic deployment proxy](docs/deterministic-deployment-proxy.md). ## Contact diff --git a/deploy_l2_contracts.star b/deploy_l2_contracts.star new file mode 100644 index 00000000..83b358f1 --- /dev/null +++ b/deploy_l2_contracts.star @@ -0,0 +1,26 @@ +service_package = import_module("./lib/service.star") + + +def run(plan, args): + l2_rpc_url = service_package.get_l2_rpc_url(plan, args) + + # When funding accounts and deploying the contracts on l2, the + # zkevm-contracts service is reused to reduce startup time. Since the l2 + # doesn't exist at the time the service is added to kurtosis, the + # `l2_rpc_url` can't be templated. Therefore, the `l2_rpc_url` is exported + # as an environment variable before running the `run-l2-contract-setup.sh`. + + plan.exec( + description="Deploying contracts on L2", + service_name="contracts" + args["deployment_suffix"], + recipe=ExecRecipe( + command=[ + "/bin/sh", + "-c", + "export l2_rpc_url={0} && chmod +x {1} && {1}".format( + l2_rpc_url.http, + "/opt/contract-deploy/run-l2-contract-setup.sh", + ), + ] + ), + ) diff --git a/deploy_zkevm_contracts.star b/deploy_zkevm_contracts.star index 21db2a9c..bcdbe974 100644 --- a/deploy_zkevm_contracts.star +++ b/deploy_zkevm_contracts.star @@ -21,6 +21,10 @@ ARTIFACTS = [ "name": "update-ger.sh", "file": "./templates/contract-deploy/update-ger.sh", }, + { + "name": "run-l2-contract-setup.sh", + "file": "./templates/contract-deploy/run-l2-contract-setup.sh", + }, ] diff --git a/docker/toolbox.Dockerfile b/docker/toolbox.Dockerfile index 26fea5e8..664acdf7 100644 --- a/docker/toolbox.Dockerfile +++ b/docker/toolbox.Dockerfile @@ -1,4 +1,4 @@ -FROM golang:1.21 AS polycli-builder +FROM golang:1.22 AS polycli-builder ARG POLYCLI_VERSION WORKDIR /opt/polygon-cli RUN git clone --branch ${POLYCLI_VERSION} https://github.com/maticnetwork/polygon-cli.git . \ diff --git a/docker/zkevm-contracts.Dockerfile b/docker/zkevm-contracts.Dockerfile index 92ea5622..e26d1bf3 100644 --- a/docker/zkevm-contracts.Dockerfile +++ b/docker/zkevm-contracts.Dockerfile @@ -1,4 +1,4 @@ -FROM golang:1.21 AS polycli-builder +FROM golang:1.22 AS polycli-builder ARG POLYCLI_VERSION WORKDIR /opt/polygon-cli RUN git clone --branch ${POLYCLI_VERSION} https://github.com/maticnetwork/polygon-cli.git . \ @@ -12,7 +12,7 @@ LABEL description="Helper image to deploy zkevm contracts" # STEP 1: Download zkevm contracts dependencies and compile contracts. ARG ZKEVM_CONTRACTS_BRANCH WORKDIR /opt/zkevm-contracts -RUN git clone https://github.com/0xPolygonHermez/zkevm-contracts . \ +RUN git clone https://github.com/0xPolygonHermez/zkevm-contracts . \ && git checkout ${ZKEVM_CONTRACTS_BRANCH} \ && npm install --global npm@10.9.0 \ && npm install \ diff --git a/docs/deterministic-deployment-proxy.md b/docs/deterministic-deployment-proxy.md new file mode 100644 index 00000000..787777b6 --- /dev/null +++ b/docs/deterministic-deployment-proxy.md @@ -0,0 +1,113 @@ +# Deploy Contracts with the Deterministic Deployment Proxy + +A guide to deploy contracts using the [deterministic deployment proxy](https://github.com/Arachnid/deterministic-deployment-proxy). + +## Introduction + +You can deploy contracts to both L1 and L2 using the deterministic deployment +proxy. Deploying the same contract to multiple chains will result in the same +contract address. + +There are two ways to go about deploying contracts: + +1. Manually in your local environment. This requires you to have [`foundry/cast`](https://github.com/foundry-rs/foundry) installed. +2. Using the [`run-l2-contract-setup.sh`](/templates/contract-deploy/run-l2-contract-setup.sh) script. This ensures that the contracts will be deployed with every `kurtosis run`. + +## Deploying Contracts Locally + +For this example, we will be deploying this contract: + +```solidity +pragma solidity 0.5.8; +contract Apple { + function banana() external pure returns (uint8) { + return 42; + } +} +``` + +To determine the contract address of the above contract, compile the bytecode +and run: + +```bash +cast create2 --salt $salt --init-code $bytecode +``` + +To deploy a contract, send the salt and bytecode to the deterministic deployment +proxy deployer address which should be `0x4e59b44847b379578588920ca78fbf26c0b4956c`. + +### Deploy Contracts on L1 + +The accounts using the `code code code code code code code code code code code quality` +mnemonic are pre-funded on L1, so you can use those accounts to for the contract +deployments. + +```bash +polycli wallet inspect --mnemonic "code code code code code code code code code code code quality" | jq -r ".Addresses[0].HexPrivateKey" +``` + +```bash +cast send \ + --legacy \ + --rpc-url "http://$(kurtosis port print cdk el-1-geth-lighthouse rpc)" \ + --private-key "0x42b6e34dc21598a807dc19d7784c71b2a7a01f6480dc6f58258f78e539f1a1fa" \ + "0x4e59b44847b379578588920ca78fbf26c0b4956c" \ + "$salt$bytecode" +``` + +### Deploy Contracts on L2 + +This is similar to L1, just that the major difference is the pre-funded account +on L2 is the `zkevm_l2_admin_private_key`. + +```bash +cast send \ + --legacy \ + --rpc-url "$(kurtosis port print cdk cdk-erigon-node-001 rpc)" \ + --private-key "0x12d7de8621a77640c9241b2595ba78ce443d05e94090365ab3bb5e19df82c625" \ + "0x4e59b44847b379578588920ca78fbf26c0b4956c" \ + "$salt$bytecode" +``` + +## Deploying Contracts using `run-l2-contract-setup.sh` + +Most of the same concepts from above apply, you just now have access to some +different variables provided through the kurtosis such as `l1_rpc_url` and +`l2_rpc_url`. + +Here's a complete example that could be appended to the `run-l2-contract-setup.sh`: + +```bash +contract_method_signature="banana()(uint8)" +expected="42" +salt="0x0000000000000000000000000000000000000000000000000000000000000000" +# contract: pragma solidity 0.5.8; contract Apple {function banana() external pure returns (uint8) {return 42;}} +bytecode="6080604052348015600f57600080fd5b5060848061001e6000396000f3fe6080604052348015600f57600080fd5b506004361060285760003560e01c8063c3cafc6f14602d575b600080fd5b6033604f565b604051808260ff1660ff16815260200191505060405180910390f35b6000602a90509056fea165627a7a72305820ab7651cb86b8c1487590004c2444f26ae30077a6b96c6bc62dda37f1328539250029" +contract_address=$(cast create2 --salt $salt --init-code $bytecode) + +echo_ts "Testing deterministic deployment proxy on l1" +cast send \ + --legacy \ + --rpc-url "{{.l1_rpc_url}}" \ + --private-key "$l1_private_key" \ + "$deployer_address" \ + "$salt$bytecode" +l1_actual=$(cast call --rpc-url "{{.l1_rpc_url}}" "$contract_address" "$contract_method_signature") +if [[ "$expected" != "$l1_actual" ]]; then + echo_ts "Failed to deploy deterministic deployment proxy on l1 (expected: $expected, actual $l1_actual)" + exit 1 +fi + +echo_ts "Testing deterministic deployment proxy on l2" +cast send \ + --legacy \ + --rpc-url "{{.l2_rpc_url}}" \ + --private-key "{{.zkevm_l2_admin_private_key}}" \ + "$deployer_address" \ + "$salt$bytecode" +l2_actual=$(cast call --rpc-url "{{.l2_rpc_url}}" "$contract_address" "$contract_method_signature") +if [[ "$expected" != "$l2_actual" ]]; then + echo_ts "Failed to deploy deterministic deployment proxy on l2 (expected: $expected, actual $l2_actual)" + exit 1 +fi +``` diff --git a/docs/trigger-a-reorg/network-helper.Dockerfile b/docs/trigger-a-reorg/network-helper.Dockerfile index 0a5c3324..8f17df46 100644 --- a/docs/trigger-a-reorg/network-helper.Dockerfile +++ b/docs/trigger-a-reorg/network-helper.Dockerfile @@ -1,4 +1,4 @@ -FROM golang:1.21 AS polycli-builder +FROM golang:1.22 AS polycli-builder WORKDIR /opt/polygon-cli RUN git clone https://github.com/maticnetwork/polygon-cli.git . \ && make build diff --git a/input_parser.star b/input_parser.star index eab20a33..6054710f 100644 --- a/input_parser.star +++ b/input_parser.star @@ -23,6 +23,8 @@ DEFAULT_DEPLOYMENT_STAGES = { # Deploy cdk-erigon node. # TODO: Remove this parameter to incorporate cdk-erigon inside the central environment. "deploy_cdk_erigon_node": True, + # Deploy contracts on L2 (as well as fund accounts). + "deploy_l2_contracts": True, } DEFAULT_IMAGES = { @@ -33,7 +35,7 @@ DEFAULT_IMAGES = { "zkevm_bridge_proxy_image": "haproxy:3.0-bookworm", # https://hub.docker.com/_/haproxy/tags "zkevm_bridge_service_image": "hermeznetwork/zkevm-bridge-service:v0.6.0-RC1", # https://hub.docker.com/r/hermeznetwork/zkevm-bridge-service/tags "zkevm_bridge_ui_image": "leovct/zkevm-bridge-ui:multi-network-2", # https://hub.docker.com/r/leovct/zkevm-bridge-ui/tags - "zkevm_contracts_image": "leovct/zkevm-contracts:v8.0.0-rc.4-fork.12", # https://hub.docker.com/repository/docker/leovct/zkevm-contracts/tags + "zkevm_contracts_image": "minhdvu/zkevm-contracts:v8.0.0-rc.4-fork.12", # https://hub.docker.com/repository/docker/leovct/zkevm-contracts/tags "zkevm_da_image": "0xpolygon/cdk-data-availability:0.0.10", # https://hub.docker.com/r/0xpolygon/cdk-data-availability/tags "zkevm_node_image": "hermeznetwork/zkevm-node:v0.7.3", # https://hub.docker.com/r/hermeznetwork/zkevm-node/tags "zkevm_pool_manager_image": "hermeznetwork/zkevm-pool-manager:v0.1.1", # https://hub.docker.com/r/hermeznetwork/zkevm-pool-manager/tags @@ -126,7 +128,7 @@ DEFAULT_L1_ARGS = { # - blutgang # - forky # - apache - # - tracoor + # - tracoor # Check the ethereum-package for more details: https://github.com/ethpandaops/ethereum-package "l1_additional_services": [], # Preset for the network. @@ -145,6 +147,14 @@ DEFAULT_L1_ARGS = { "l1_funding_amount": "100ether", } +DEFAULT_L2_ARGS = { + # The number of accounts to fund on L2. The accounts will be derived from: + # polycli wallet inspect --mnemonic '{{.l1_preallocated_mnemonic}}' + "l2_accounts_to_fund": 10, + # The amount of ETH sent to each of the prefunded l2 accounts. + "l2_funding_amount": "100ether", +} + DEFAULT_ROLLUP_ARGS = { # The keystore password. "zkevm_l2_keystore_password": "pSnv6Dh5s9ahuzGzH9RoCDrKAMddaX3m", @@ -209,6 +219,7 @@ DEFAULT_ARGS = ( | DEFAULT_L1_ARGS | DEFAULT_ROLLUP_ARGS | DEFAULT_PLESS_ZKEVM_NODE_ARGS + | DEFAULT_L2_ARGS ) # A list of fork identifiers currently supported by Kurtosis CDK. diff --git a/main.star b/main.star index a24081fd..d06c80ea 100644 --- a/main.star +++ b/main.star @@ -10,6 +10,7 @@ databases_package = "./databases.star" deploy_zkevm_contracts_package = "./deploy_zkevm_contracts.star" ethereum_package = "./ethereum.star" zkevm_pool_manager_package = "./zkevm_pool_manager.star" +deploy_l2_contracts_package = "./deploy_l2_contracts.star" # Additional service packages. arpeggio_package = "./src/additional_services/arpeggio.star" @@ -79,7 +80,7 @@ def run(plan, args={}): # Deploy cdk central/trusted environment. if deployment_stages.get("deploy_cdk_central_environment", False): # Deploy cdk-erigon sequencer node. - # TODO this is a little weird if the erigon sequencer is deployed before the exector? + # TODO this is a little weird if the erigon sequencer is deployed before the executor? if args["sequencer_type"] == "erigon": plan.print("Deploying cdk-erigon sequencer") import_module(cdk_erigon_package).run_sequencer(plan, args) @@ -125,6 +126,13 @@ def run(plan, args={}): else: plan.print("Skipping the deployment of the agglayer") + # Deploy contracts on L2. + if deployment_stages.get("deploy_l2_contracts", False): + plan.print("Deploying contracts on L2") + import_module(deploy_l2_contracts_package).run(plan, args) + else: + plan.print("Skipping the deployment of contracts on L2") + # Launching additional services. additional_services = args["additional_services"] diff --git a/templates/contract-deploy/run-l2-contract-setup.sh b/templates/contract-deploy/run-l2-contract-setup.sh new file mode 100644 index 00000000..254a9dfa --- /dev/null +++ b/templates/contract-deploy/run-l2-contract-setup.sh @@ -0,0 +1,106 @@ +#!/bin/bash + +global_log_level="{{.global_log_level}}" +if [[ $global_log_level == "debug" ]]; then + set -x +fi + +echo_ts() { + local green="\e[32m" + local end_color="\e[0m" + local timestamp + timestamp=$(date +"[%Y-%m-%d %H:%M:%S]") + + echo -e "$green$timestamp$end_color $1" >&2 +} + +wait_for_rpc_to_be_available() { + local counter=0 + local max_retries=20 + local retry_interval=5 + + until cast send --legacy \ + --rpc-url "$l2_rpc_url" \ + --private-key "{{.zkevm_l2_admin_private_key}}" \ + --value 0 "{{.zkevm_l2_sequencer_address}}" &> /dev/null; do + ((counter++)) + echo_ts "Can't send L2 transfers yet... Retrying ($counter)..." + if [[ $counter -ge $max_retries ]]; then + echo_ts "Exceeded maximum retry attempts. Exiting." + exit 1 + fi + sleep $retry_interval + done +} + +fund_account_on_l2() { + local address="$1" + echo_ts "Funding $address" + cast send \ + --legacy \ + --rpc-url "$l2_rpc_url" \ + --private-key "{{.zkevm_l2_admin_private_key}}" \ + --value "{{.l2_funding_amount}}" \ + "$address" +} + +if [[ -e "/opt/zkevm/.init-l2-complete{{.deployment_suffix}}.lock" ]]; then + echo_ts "This script has already been executed" + exit 1 +fi + +if [[ -z "$l2_rpc_url" ]]; then + echo "Error: l2_rpc_url is not set. Exiting." + exit 1 +fi + +echo_ts "Waiting for the L2 RPC to be available" +wait_for_rpc_to_be_available +echo_ts "L2 RPC is now available" + +echo_ts "Funding bridge autoclaimer account on l2" +fund_account_on_l2 "{{.zkevm_l2_claimtxmanager_address}}" + +echo_ts "Funding accounts on l2" +accounts=$( + polycli wallet inspect \ + --mnemonic "{{.l1_preallocated_mnemonic}}" \ + --addresses "{{.l2_accounts_to_fund}}" +) +echo "$accounts" | jq -r ".Addresses[].ETHAddress" | while read -r address; do + fund_account_on_l2 "$address" +done + +signer_address="0x3fab184622dc19b6109349b94811493bf2a45362" +gas_cost="0.01ether" +transaction="0xf8a58085174876e800830186a08080b853604580600e600039806000f350fe7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe03601600081602082378035828234f58015156039578182fd5b8082525050506014600cf31ba02222222222222222222222222222222222222222222222222222222222222222a02222222222222222222222222222222222222222222222222222222222222222" +deployer_address="0x4e59b44847b379578588920ca78fbf26c0b4956c" +l1_private_key=$(polycli wallet inspect --mnemonic "{{.l1_preallocated_mnemonic}}" | jq -r ".Addresses[0].HexPrivateKey") + +echo_ts "Deploying deterministic deployment proxy on l1" +cast send \ + --rpc-url "{{.l1_rpc_url}}" \ + --private-key "$l1_private_key" \ + --value "$gas_cost" \ + "$signer_address" +cast publish --rpc-url "{{.l1_rpc_url}}" "$transaction" +if [[ $(cast code --rpc-url "{{.l1_rpc_url}}" $deployer_address) == "0x" ]]; then + echo_ts "No code at expected l1 address: $deployer_address" + exit 1; +fi + +echo_ts "Deploying deterministic deployment proxy on l2" +cast send \ + --legacy \ + --rpc-url "$l2_rpc_url" \ + --private-key "{{.zkevm_l2_admin_private_key}}" \ + --value "$gas_cost" \ + "$signer_address" +cast publish --rpc-url "$l2_rpc_url" "$transaction" +if [[ $(cast code --rpc-url "$l2_rpc_url" $deployer_address) == "0x" ]]; then + echo_ts "No code at expected l2 address: $deployer_address" + exit 1; +fi + +# The contract setup is done! +touch "/opt/zkevm/.init-l2-complete{{.deployment_suffix}}.lock"