Skip to content

Setting Up Production zkNode

In this tutorial we extend the developer's exploration of the Polygon zkEVM on their local machines to launching their own node on the zkEVM Public Testnet.

First note that this document assumes familiarity with Docker and CLI.

After setting up your zkNode instance, you will be able to run the Synchronizer.

Although the Sequencer and Aggregator functions are still centralized at this stage of development, anyone can run a Synchronizer that allows accessing a trustless RPC node.

CAUTION!

Currently the zkProver does not run on ARM-powered Macs. 
For Windows users, using WSL/WSL2 is not recommended.

Unfortunately, Apple M1 chips are not supported for now 
- since some optimizations on the zkProver require specific Intel instructions. 
This means some non-M1 computers won't work regardless of the OS, for example: AMD.

Prerequisites

This tutorial assumes that you have docker-compose already installed. If you need any help with the installation, please check the official docker-compose installation guide.

Minimum System Requirements

  • 16GB RAM
  • 4-core CPU

It is highly recommeneded that you create a separate folder for installing and working around the zkNode. We won't be cloning any repository (unlike local zkNode setup) so it's better to create a folder before starting the zkNode setup: mkdir -p /$HOME/zkevm-node

Network Components

Here is a list of crucial components that are required before you can run the zkNode:

  • Ethereum Node - L1 Network

  • zkEVM-Node (or zkNode) - L2 Network

  • JSON RPC Server - Interface to L2 network

  • Synchronizer - Responsible for synchronizing data between L1 and L2
  • Sequencer - Responsible for selecting transactions from the pool and propose new batches
  • Aggregator - Responsible for consolidating the changes in the state proposed by the Sequencers

  • zkProver - Zero knowledge proof generator

Optional components:

  • Metamask - Wallet to manage blockchain accounts
  • Block Scout Explorer - Web UI to interact with the network information

Next we set up each of the above components.

Ethereum Node Setup

The Ethereum Node will be the first component to set up. It is the first because synchronizing the Ethereum network will take a long time, so we will keep it synchronized while we set up the other components to take advantage of this required time.

BEFORE WE START

There are numerous ways to set up an Ethereum L1 environment; 
we will use Geth for this. We recommend Geth, but any Goerli node should do.

If you plan to have more than one zkNode in your infrastructure, 
we advise using a machine that is specifically dedicated to this component.

First of all, we need to create a folder to store the Ethereum node data outside of the Docker container, in order to not lose all the data if the container is restarted.

mkdir -p /$HOME/zkevm-node/.ethereum

In order to configure the Ethereum node instance, create a file called docker-compose.yml inside the zkevm-node folder:

docker-compose.yml
version: '3'

services:

  eth-node:
    container_name: eth-node
    image: ethereum/client-go:stable
    ports:
        - 8545:8545
        - 8546:8546
        - 30303:30303
    volumes:
        - /$HOME/zkevm-node/.ethereum:/$HOME/geth/.ethereum
    command: [
        "--goerli",
        "--http",
        "--http.addr=0.0.0.0",
        "--http.corsdomain=*",
        "--http.vhosts=*",
        "--http.api=admin,eth,debug,miner,net,txpool,personal,web3",
        "--ws",
        "--ws.addr=0.0.0.0",
        "--ws.origins=*", 
        "--graphql", 
        "--graphql.corsdomain=*", 
        "--graphql.vhosts=*", 
        "--vmdebug", 
        "--metrics",
        "--datadir=/$HOME/geth/.ethereum"
    ]

To run the Ethereum node instance, go to the zkevm-node folder in your terminal and run the following command:

docker-compose up -d

If you want to follow the logs of the synchronization, run the following command:

docker logs -f eth-node

Postgres Setup

INFO

Running Postgres instances in a Docker container is an option 
but we recommend you to use a specialized infrastructure for 
the database, such as AWS RDS, an on-site server, or any other 
Postgres DB dedicated infrastructure.

It is not necessary to have a backup because all data is available 
on L1 and can be resynchronized if it is lost. 
However, having a backup is strongly advised in order to avoid 
resynchronizing the entire network in the event of a DB problem.

In order to set up the databases for zkNode, we must set up several Postgres instances to be shared between the Node and the Prover/Executor.

  • Node requires a root access to run the migrations and control the data.
  • Prover only needs a read-only user access to the Merkle tree data and compute the proofs. Executor will need read/write access. Migration file init_prover_db.sql will create the Merkle tree table in State DB.

To achieve that, we need to create several directories for storing the Postgres data outside of the Docker container (so that we don't lose all the data if the container is restarted).

mkdir -p /$HOME/zkevm-node/.postgres-state
mkdir -p /$HOME/zkevm-node/.postgres-pool
mkdir -p /$HOME/zkevm-node/.postgres-rpc

Next, download init schema for the Prover DB from Github and store this file in the zkevm-node folder.

In order to configure the Postgres instance, create a file called docker-compose.yml inside zkevm-node.

docker-compose.yml
# We recommend that you customize the ENVIRONMENT variables values to your preference

version: '3'

services:
  zkevm-state-db:
    container_name: zkevm-state-db
    image: postgres
    deploy:
      resources:
        limits:
          memory: 2G
        reservations:
          memory: 1G
    ports:
      - 5432:5432
    volumes:
      - ./init_prover_db.sql:/docker-entrypoint-initdb.d/init.sql
      - /$HOME/zkevm-node/.postgres-state:/var/lib/postgresql/data
    environment:
      - POSTGRES_USER=state_user
      - POSTGRES_PASSWORD=state_password
      - POSTGRES_DB=state_db
    command: ["postgres", "-N", "500"]

  zkevm-pool-db:
    container_name: zkevm-pool-db
    image: postgres
    deploy:
      resources:
        limits:
          memory: 2G
        reservations:
          memory: 1G
    ports:
      - 5433:5432
    volumes:
      - /$HOME/zkevm-node/.postgres-pool:/var/lib/postgresql/data
    environment:
      - POSTGRES_USER=pool_user
      - POSTGRES_PASSWORD=pool_password
      - POSTGRES_DB=pool_db
    command: ["postgres", "-N", "500"]

  zkevm-rpc-db:
    container_name: zkevm-rpc-db
    image: postgres
    deploy:
      resources:
        limits:
          memory: 2G
        reservations:
          memory: 1G
    ports:
      - 5434:5432
    volumes:
      - /$HOME/zkevm-node/.postgres-rpc:/var/lib/postgresql/data
    environment:
      - POSTGRES_USER=rpc_user
      - POSTGRES_PASSWORD=rpc_password
      - POSTGRES_DB=rpc_db
    command: ["postgres", "-N", "500"]

To run the Postgres instance, go to the zkevm-node folder in your terminal and run the following command:

docker-compose up -d

Tags to be used for the different docker images available for the node components can be found here.

Executor & StateDB Setup

The zkEVM Prover is available on Docker registry. You can simply start by pulling the image:

docker pull hermeznetwork/zkevm-prover

Download the sample Prover config file and store it as prover-config.json inside the zkevm-node folder.

Finally, add the following to the docker-compose.yml file:

docker-compose.yml
  zkevm-prover:
    container_name: zkevm-prover
    image: hermeznetwork/zkevm-prover:develop
    ports:
      - 50061:50061 # StateDB or Merkle Tree
      - 50071:50071 # Executor
    volumes:
      - ./prover-config.json:/usr/src/app/config.json
    command: >
      zkProver -c /usr/src/app/config.json

This will spin up the Executor and StateDB (or Merkle Tree). For more information, check out the zkProver repository on Github.

zkNode Setup

After completing the above steps, we have the Postgres DBs, Prover and Ethereum Node instances running. Now is the perfect time to setup the zkNode.

INFO

The zkNode depends on Postgres, Prover and Ethereum Node instances. 
Make sure it has network access to them. 
It's advised to setup a dedicated machine for the zkNode.

Before we start, the zkNode requires an Ethereum account with:

  • Funds on L1 in order to propose new batches and consolidate the state
  • Tokens to pay the collateral for batch proposal
  • Approval of these tokens to be used by the Rollup Smart Contract on behalf of the Ethereum account owner
  • Register this account as a Sequencer

We have to start with creating a config file to provide the configurations to the node. To do that,

  • Create a file called config.toml inside the zkevm-node folder.
  • Go to the example config file available on Github and copy its content and paste into the config.toml that we just created inside zkevm-node.

Similarly, create a genesis.json file inside the zkevm-node folder and copy the contents of the sample genesis file available on Github.

REMEMBER TO


- Replace the DB information if you set it differently while setting up the Postgres instance
- Set the `Database Host` with the Postgres instance IP
- Set the `Etherman URL` with the JSON RPC URL of the Ethereum node that you created 
  earlier or use any L1 Goerli service
- Set the `Etherman Password` (`config.json` => `PrivateKeyPassword` field, defaults 
  to `testonly`) to allow the node to decrypt the keystore file
- Set the `MT/Executor URIs` and the `IP and Port` of the MT/Executor Instances and 
  change the array of Provers if a prover was spun up

Now, we are going to put everything together in order to run the Polygon zkEVM node instance on the public testnet. Simply add the following entries to the docker-compose.yml file:

docker-compose.yml
  zkevm-rpc:
    container_name: zkevm-rpc
    image: zkevm-node
    ports:
      - 8545:8545
    environment:
      - ZKEVM_NODE_STATEDB_HOST=zkevm-state-db
      - ZKEVM_NODE_POOL_HOST=zkevm-pool-db
      - ZKEVM_NODE_RPC_DB_HOST=zkevm-rpc-db
      - ZKEVM_NODE_RPC_BROADCASTURI=public-grpc.zkevm-test.net:61090
    volumes:
      - ./config.toml:/app/config.toml
      - ./genesis.json:/app/genesis.json
    command:
      - "/bin/sh"
      - "-c"
      - "/app/zkevm-node run --genesis /app/genesis.json --cfg /app/config.toml --components rpc"

  zkevm-sync:
    container_name: zkevm-sync
    image: zkevm-node
    environment:
      - ZKEVM_NODE_STATEDB_HOST=zkevm-state-db
    volumes:
      - ./acc.keystore:/pk/keystore
      - ./config.toml:/app/config.toml
      - ./genesis.json:/app/genesis.json
    command:
      - "/bin/sh"
      - "-c"
      - "/app/zkevm-node run --genesis /app/genesis.json --cfg /app/config.toml --components synchronizer"

To run the zkNode instance, go to the zkevm-node folder in your terminal and run the following command:

docker-compose up -d

Set up Block Explorer

To get a visual access to the network and stats, we need to set up a Blockscout instance. For more details about Blockscout, check out their documentation.

Blockscout requires access to its own zkNode RPC-only instance to access the network via JSON RPC Server, and a dedicated Postgres instance in order to save its data.

Feel free to customize the environment variables to set the user, password and database for the Explore Postgres instance. Make sure to update the URL to connect to the DB in the Explorer environment variable: DATABASE_URL.

docker-compose.yml
version: '3'

services:

    zkevm-explorer-db:
        container_name: zkevm-explorer-db
        image: postgres
        ports:
            - 5432:5432
        environment:
            - POSTGRES_USER=test_user
            - POSTGRES_PASSWORD=test_password
            - POSTGRES_DB=explorer

    zkevm-explorer:
        container_name: zkevm-explorer
        image: hermeznetwork/hermez-node-blockscout:latest
        ports:
            - 4000:4000
        environment:
            - NETWORK=POE
            - SUBNETWORK=Polygon Hermez
            - COIN=ETH
            - ETHEREUM_JSONRPC_VARIANT=geth
            - ETHEREUM_JSONRPC_HTTP_URL=http://zkevm-explorer-zknode:8124
            - DATABASE_URL=postgres://test_user:[email protected]:5432/explorer
            - ECTO_USE_SSL=false
            - MIX_ENV=prod
            - LOGO=/images/blockscout_logo.svg
            - LOGO_FOOTER=/images/blockscout_logo.svg
        command: ["/bin/sh", "-c", "mix do ecto.create, ecto.migrate; mix phx.server"]

    zkevm-explorer-zknode:
      container_name: zkevm-explorer-zknode
      image: zkevm-node
      ports:
        - 8124:8124
      environment:
        - ZKEVM_NODE_STATEDB_HOST=zkevm-state-db
        - ZKEVM_NODE_POOL_HOST=zkevm-pool-db
        - ZKEVM_NODE_RPC_DB_HOST=zkevm-rpc-db
        - ZKEVM_NODE_RPC_PORT=8124
      volumes:
        - ./config/test.node.config.toml:/app/config.toml
        - ./config/test.genesis.config.json:/app/genesis.json
      command:
        - "/bin/sh"
        - "-c"
        - "/app/zkevm-node run --genesis /app/genesis.json --cfg /app/config.toml --components rpc --http.api eth,net,debug,zkevm,txpool,web3"

To run the Block Explorer, execute the following command:

docker-compose up -d zkevm-explorer-db
sleep 5
docker-compose up -d zkevm-explorer
sleep 5
docker-compose up -d zkevm-explorer-zknode

Connecting to Metamask

INFO

Metamask requires the network to be running while configuring it, so make sure 
your network is up.

To configure your Metamask to use your custom zkEVM network, follow these steps:

  1. Log in to your Metamask wallet
  2. Click on your account picture and then on Settings
  3. On the left menu, click on Networks
  4. Click on Add Network button
  5. Fill up the L2 network information
  6. Network Name: Polygon zkEVM - Goerli
  7. New RPC URL: http://IP-and-Port-of-zkEVM-Node-Instance
  8. Chain ID: 1422
  9. Currency Symbol: ETH
  10. Block Explorer URL: http://IP-and-Port-of-Explorer-Instance
  11. Click on Save and close the Settings
  12. Click on the list of networks in the top right corner
  13. Select Polygon zkEVM - Goerli