Build on X Layer
Setup production ZKNode

Setup production ZKNode#

X Layer is now available on the Mainnet and Testnet for developers to launch smart contracts, execute transactions, and experiment with the network. This tutorial extends the exploration by allowing developers to launch their own node on the Public network. Before we begin, this document is fairly technical and requires prior exposure to Docker and CLI. Post spinning up your ZKNode instance, you will be able to run the Synchronizer and utilize the JSON-RPC interface.

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#

CAUTION
ZKProver does not work on ARM-based Macs yet, and using WSL/WSL2 on Windows is not advisable. Currently, ZKProver optimizations require CPUs that support the AVX2 instruction, which means some non-M1 computers, such as AMD, won’t work with the software regardless of the OS.
  • 16GB RAM
  • 4-core CPU
  • 1 TB Storage (This will increase over time)

Network components#

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

  • Ethereum Node - Use geth or any service providing a JSON RPC interface for accessing the layer 1 network
  • X Layer-Node (or ZKNode) - layer 2 network
    • Synchronizer - Responsible for synchronizing data between layer 1 and layer 2
    • JSON RPC Server - Interface to layer 2 network
    • State DB - Save the layer 2 account, block and tx data.

Let’s set up each of the above components!

Ethereum node setup#

The Ethereum RPC Node is the first component to be deployed because ZKNode needs to synchronize blocks and transactions on layer 1. You can invoke the ETH RPC (Mainnet: Ethereum OR Testnet: Sepolia) service through any of the following methods:

Installing#

Once the layer 1 RPC component is complete, we can start the ZKNode setup. This is the most straightforward way to run a ZKNode and it’s fine for most use cases. Furthermore, this method is purely subjective and feel free to run this software in a different manner. For example, Docker is not required, you could simply use the Go binaries directly. Let’s start setting up our ZKNode:

  1. Download the installation script
mkdir -p ./xlayer-node && cd ./xlayer-node

# mainnet
curl -fsSL https://raw.githubusercontent.com/okx/Deploy/main/setup/zknode/run_xlayer_mainnet.sh | bash -s init && cp ./mainnet/example.env ./mainnet/.env
# testnet
curl -fsSL https://raw.githubusercontent.com/okx/Deploy/main/setup/zknode/run_xlayer_testnet.sh | bash -s init && cp ./testnet/example.env ./testnet/.env
  1. The example.env file must be modified according to your configurations. Edit the .env file with your favourite editor (we’ll use vim in this guide):
# mainnet
vim ./mainnet/.env

# testnet
vim ./testnet/.env
# URL of a JSON RPC for Ethereum mainnet or Sepolia testnet
XLAYER_NODE_ETHERMAN_URL = "http://your.L1node.url"

# PATH WHERE THE STATEDB POSTGRES CONTAINER WILL STORE PERSISTENT DATA
XLAYER_NODE_STATEDB_DATA_DIR = "./xlayer_mainnet_data/statedb" # OR ./xlayer_testnet_datastatedb/ for testnet

# PATH WHERE THE POOLDB POSTGRES CONTAINER WILL STORE PERSISTENT DATA #
XLAYER_NODE_POOLDB_DATA_DIR = "./xlayer_mainnet_data/pooldb" # OR ./xlayer_testnet_data/pooldb/ for testnet
  1. Restore the latest layer 2 snapshot locally database for synchronizing layer 2 data quickly.
# mainnet
./run_xlayer_mainnet.sh restore 

# testnet
./run_xlayer_testnet.sh restore 

Starting#

Use the below command to start the ZKNode instance:

# mainnet
./run_xlayer_mainnet.sh start

# testnet
./run_xlayer_testnet.sh start

docker ps -a

You will see a list of the following containers :

  • xlayer-rpc
  • xlayer-sync
  • xlayer-state-db
  • xlayer-pool-db
  • xlayer-prover

You should now be able to run queries to the JSON-RPC endpoint at http://localhost:8545. Run the following query to get the most recently synchronized layer 2 block; if you call it every few seconds, you should see the number grow:

curl -H "Content-Type: application/json" -X POST --data '{"jsonrpc":"2.0","method":"eth_blockNumber","params":[],"id":83}' http://localhost:8545

Stopping#

Use the below command to stop the ZKNode instance:

# mainnet
./run_xlayer_mainnet.sh stop

# testnet
./run_xlayer_testnet.sh stop

Restarting#

Use the below command to stop the ZKNode instance:

# mainnet
./run_xlayer_mainnet.sh restart

# testnet
./run_xlayer_testnet.sh restart

Updating#

To update the ZKNode software, run the below command, and the file ./mainnet(or testnet)/.env will be retained, the other config will be deleted.

# mainnet
./run_xlayer_mainnet.sh update

# testnet
./run_xlayer_testnet.sh update

Troubleshooting#

  • It’s possible that the machine you’re using already uses some of the necessary ports. In this case, you can change them directly ./mainnet(testnet)/docker-compose.yml.
  • If one or more containers are crashing, please check the logs using the command below:
docker ps -a

docker logs <cointainer_name>

Force resync From specific batch#

  1. Stop xlayer-sync and xlayer-rpc services
docker stop xlayer-sync
docker stop xlayer-rpc
  1. Select max verified batch
PGPASSWORD=state_password psql -h 127.0.0.1 -p 5432 -d state_db -U state_user

SELECT max(batch_num) FROM state.verified_batch;
# Use the batch_num above  to perform the resync from a specific batch (e.g. 330000):
  1. Look for the target block and batch to delete
  • Look for this batch in OK Link and get "Sequence Tx Hash" value (0xf5bcff8bc5e03be47e36d642d26f0551ff4a66094e1fb67c9e02ec739c7fca82)
  • Go to previous batches (you can use "<" button) until you reach the first batch sequenced with the same "Sequence Tx Hash" (in this example 329992).
  • Look for the "Sequence Tx Hash" in etherscan to get the layer 1 block where that tx was confirmed (in this example 5517146).
  1. Delete the block and batch
delete from state.block where block_num >= 5517146; 
delete from state.batch where batch_num >= 329992;
  1. Start the sync service to sync again.