Skip to content

Instantly share code, notes, and snippets.

@miguelmota
Last active February 28, 2023 02:10
Show Gist options
  • Save miguelmota/973e62c8f3da0571fc2c469b65c54d71 to your computer and use it in GitHub Desktop.
Save miguelmota/973e62c8f3da0571fc2c469b65c54d71 to your computer and use it in GitHub Desktop.
Deploy custom Optimism rollup instructions

Instructions

Unofficial guide on deploying a custom Optimism rollup on Kovan

⚠️ Notice: Guide updated April 2021. Check out the Optimism discord for additional help and support.

Clone optimism contracts:

git clone git@github.com:ethereum-optimism/optimism.git
cd optimism/packages/contracts/

Build optimism contracts:

yarn
yarn build:kovan

Deploy optimism contracts to kovan (replace YOUR_PRIVATE_KEY and L1_NODE_WEB3_URL to your own):

DEPLOYER_PRIVATE_KEY=YOUR_PRIVATE_KEY \
SEQUENCER_PRIVATE_KEY=YOUR_PRIVATE_KEY \
L1_NODE_WEB3_URL=https://kovan.infura.io/v3/PROJECT_ID \
WAIT_FOR_RECEIPTS=true \
WHITELIST_ALLOW_ARBITRARY_CONTRACT_DEPLOYMENT=true \
CHAIN_ID=420 \
RELAYER_PRIVATE_KEY=YOUR_PRIVATE_KEY \
MAX_TRANSACTION_GAS_LIMIT=9000000 \
MIN_TRANSACTION_GAS_LIMIT=0 \
FRAUD_PROOF_WINDOW_SECONDS=604800 \
yarn deploy

The deployment script will write a JSON file to dist/dumps/addresses.json with the contract addresses (your addresses will be different):

{
  "AddressManager": "0xf920d5576C96e9b89f329146b6Cc3E6c6Bb9d614",
  "OVM_CanonicalTransactionChain": "0x6Da275Dcaa1e90B07f0BFff245067d706E16c2F5",
  "OVM_ChainStorageContainer:CTC:batches": "0x885DfCeF2fDb61e05531d8898FE26aC75c64aD86",
  "OVM_ChainStorageContainer:CTC:queue": "0x32692c512D98780545b619b837ae254c7cde4D31",
  "OVM_ChainStorageContainer:SCC:batches": "0x0577A1dC50e93e14c94B11816e152F10C54388Ab",
  "OVM_ExecutionManager": "0x2A01739daDE5450283b605c9aea91a1CF9303972",
  "OVM_FraudVerifier": "0x448E3876e06e58283094090D1752feeA52E05021",
  "OVM_L1CrossDomainMessenger": "0xE5a1BD7476Ea1E9105A7e1e82226207853b52fDB",
  "OVM_L1ETHGateway": "0x64974Ae6b99B0803C1d8e0528E49BeF0F2344f6D",
  "OVM_L1MultiMessageRelayer": "0xCdD55f0e27478eBf4297684d0f262D5b367A1043",
  "OVM_SafetyChecker": "0x215FaA481B191Fe714a7DBaaf968F25871298BC1",
  "OVM_StateCommitmentChain": "0xEA5405f789b3A98BFDeae8E7aBeeA2C066006dE7",
  "OVM_StateManagerFactory": "0x29f1D16Ecc7Fc0e791c1525D7e3385016B9FA671",
  "OVM_StateTransitionerFactory": "0x47994998cAf4383fe9b145AbBf2bbF17BCe0Ebe9",
  "Proxy__OVM_L1CrossDomainMessenger": "0x206DdaDE27215137ebC67f66948cD5384a0ff8Fe",
  "Proxy__OVM_L1ETHGateway": "0xc17b9807De38004cf4EFd4AA69A31aA74a3c74D4",
  "OVM_BondManager": "0x0db9aDf5fB972503076c2A12F751a54D0EcE4352"
}

Create docker-compose.yml:

version: '3'

services:
  geth_l2:
    image: ethereumoptimism/go-ethereum:latest
    restart: unless-stopped
    volumes:
      - geth:/root/.ethereum:rw
    env_file:
      - docker-compose.env
    ports:
      - 8545:8545
      - 8546:8546

  batch_submitter:
    image: ethereumoptimism/batch-submitter:latest
    restart: unless-stopped
    env_file:
      - docker-compose.env

  data_transport_layer:
    image: ethereumoptimism/data-transport-layer:latest
    restart: unless-stopped
    env_file:
      - docker-compose.env
    ports:
      - 7878:7878

volumes:
  geth:

Create docker-compose.env (replace YOUR_PRIVATE_KEY, YOUR_PRIVATE_KEY_ADDRESS, YOUR_ADDRESS_MANAGER_ADDRESS, _YOUR_PROXY_OVM_L1_CROSS_DOMAIN_MESSENGER_ADDRESS to your own)

######### L2 GETH VARS #########
CHAIN_ID=420
NETWORK_ID=420
DEV=true
DATADIR=/root/.ethereum
RPC_ENABLE=true
RPC_ADDR=geth_l2
RPC_CORS_DOMAIN='*'
RPC_VHOSTS='*'
RPC_PORT=8545
WS=true
WS_ADDR=0.0.0.0
WS_PORT=8546
IPC_DISABLE=true
TARGET_GAS_LIMIT=9000000
RPC_API='eth,net,rollup,web3'
WS_API='eth,net,rollup,web3'
WS_ORIGINS='*'
GASPRICE=0
NO_USB=true
GCMODE=archive
NO_DISCOVER=true
USING_OVM=true

ETH1_SYNC_SERVICE_ENABLE=true
ETH1_CTC_DEPLOYMENT_HEIGHT=24400000
ETH1_HTTP=https://kovan.infura.io/v3/PROJECT_ID
ETH1_CONFIRMATION_DEPTH=1
ETH1_CHAINID=42
ETH1_NETWORKID=42

# This is "AddressManager" address from deployed contracts
ETH1_ADDRESS_RESOLVER_ADDRESS=YOUR_ADDRESS_MANAGER_ADDRESS

# This is "Proxy__OVM_L1CrossDomainMessenger" address from deployed contracts
ETH1_L1_CROSS_DOMAIN_MESSENGER_ADDRESS=YOUR_PROXY_OVM_L1_CROSS_DOMAIN_MESSENGER_ADDRESS

# This should be public address of private key that deployed contracts
ROLLUP_ADDRESS_MANAGER_OWNER_ADDRESS=YOUR_PRIVATE_KEY_ADDRESS

ROLLUP_STATE_DUMP_PATH=https://raw.githubusercontent.com/ethereum-optimism/regenesis/master/kovan/2.json
ROLLUP_DIFFDB_CACHE=1
ROLLUP_CLIENT_HTTP=http://data_transport_layer:7878

######### Batch Submitter #########
# Logging
DEBUG=info*,error*,warn*,debug*
DEPLOYER_PRIVATE_KEY=YOUR_PRIVATE_KEY
SEQUENCER_PRIVATE_KEY=YOUR_PRIVATE_KEY
TX_INGESTION_SIGNER_KEY=YOUR_PRIVATE_KEY
TX_INGESTION_SIGNER_ADDRESS=YOUR_PRIVATE_KEY_ADDRESS
MAX_TX_SIZE=90000
MIN_TX_SIZE=0
MAX_BATCH_SIZE=50
POLL_INTERVAL=15000
NUM_CONFIRMATIONS=1
RESUBMISSION_TIMEOUT=1000000
FINALITY_CONFIRMATIONS=1
RUN_TX_BATCH_SUBMITTER=true
RUN_STATE_BATCH_SUBMITTER=true
MAX_BATCH_SUBMISSION_TIME=1000000
SAFE_MINIMUM_ETHER_BALANCE=0
MAX_L1_TX_SIZE=90000
MIN_L1_TX_SIZE=0
MAX_TX_BATCH_COUNT=50
MAX_STATE_BATCH_COUNT=50

L1_NODE_WEB3_URL=https://kovan.infura.io/v3/PROJECT_ID
L2_NODE_WEB3_URL=http://geth_l2:8545
CLEAR_PENDING_TXS=false

ADDRESS_MANAGER_ADDRESS=YOUR_ADDRESS_MANAGER_ADDRESS

# Data transport layer
DATA_TRANSPORT_LAYER__SYNC_FROM_L1=true
DATA_TRANSPORT_LAYER__SYNC_FROM_L2=false
DATA_TRANSPORT_LAYER__L2_RPC_ENDPOINT=http://geth_l2:8545
DATA_TRANSPORT_LAYER__L2_CHAIN_ID=420
DATA_TRANSPORT_LAYER__DB_PATH=/db
DATA_TRANSPORT_LAYER__SERVER_PORT=7878
DATA_TRANSPORT_LAYER__TRANSACTIONS_PER_POLLING_INTERVAL=1000
DATA_TRANSPORT_LAYER__L1_RPC_ENDPOINT=https://kovan.infura.io/v3/PROJECT_ID
DATA_TRANSPORT_LAYER__CONFIRMATIONS=1
DATA_TRANSPORT_LAYER__POLLING_INTERVAL=500
DATA_TRANSPORT_LAYER__LOGS_PER_POLLING_INTERVAL=2000
DATA_TRANSPORT_LAYER__DANGEROUSLY_CATCH_ALL_ERRORS=true
DATA_TRANSPORT_LAYER__SERVER_HOSTNAME=0.0.0.0
DATA_TRANSPORT_LAYER__ADDRESS_MANAGER=YOUR_ADDRESS_MANAGER_ADDRESS
RETRIES=50

Run docker compose services:

docker-compose up

L2 node will be accessible on http://localhost:8545

L2 messenger will be 0x4200000000000000000000000000000000000007 (see this readme)

@liamzebedee
Copy link

" This is "Proxy__OVM_L1CrossDomainMessenger" address from deployed contracts could use a #.

For others using Hardhat - it appears there's a bug if you specify CHAIN_ID as decimal. I get this error -

geth_l2_1 | Fatal: Failed to start syncservice: Wrong network: Received incorrect chain id 31337, expected 31377

Instead, specify 31337 as hex -

ETH1_CHAINID=0x7a69
ETH1_NETWORKID=0x7a69

@liamzebedee
Copy link

Just Ctrl+C'd on the wrong tab and fucked if I'm redeploying it all before bed. But might have something to post here later this week. Cheers @miguelmota for this awesome setup though

@uxname
Copy link

uxname commented Feb 16, 2021

Could anyone tell me please how I can use a simple contract in OVM so that the state in L1 changes?
According to your guide, I deployed contracts for L1 (Kovan) and received addresses (AddressManager, etc.), launched L2, compiled the hello world contract:

pragma solidity ^0.7.3;

contract HelloWorld {
    uint256 value;

    function getValue() public view returns (uint256) {
        return value;
    }

    function setValue(uint256 newValue) public returns (bool) {
        value = newValue;
        return true;
    }
}

Received 2 artifacts:

  • HelloWorld.ovm.json
  • HelloWorld.json

HelloWorld.json deployed to Kovan (tx nonce 57 if it matters)
HelloWorld.ovm.json deployed to OVM (tx nonce 58 if it matters)

Sending setValue transaction to OVM - no effect. But the transaction went away successfully, I received the contract address, then
I tried to call the created contract (getValue method) and I get this error:
Error: call revert exception (method="getValue()", errorSignature=null, errorArgs=[null], reason=null, code=CALL_EXCEPTION, version=abi/5.0.10)

@miguelmota
Copy link
Author

@liamzebedee thanks for the fix and good to know!

@miguelmota
Copy link
Author

@uxname verify that the contracts got deployed with provider.getCode(address) using ethers.

You'll need to call the respective cross-domain messengers to send L1<>L2. Here's an example tutorial repo for reference: https://github.com/syuukawa/Buidler-Deposit-Withdraw-Example/blob/def44173f996590918a4c0f7a6015966b06a33d9/contracts/ERC20/L2ERC20.sol#L44

@uxname
Copy link

uxname commented Feb 16, 2021

@uxname verify that the contracts got deployed with provider.getCode(address) using ethers.

You'll need to call the respective cross-domain messengers to send L1<>L2. Here's an example tutorial repo for reference: https://github.com/syuukawa/Buidler-Deposit-Withdraw-Example/blob/def44173f996590918a4c0f7a6015966b06a33d9/contracts/ERC20/L2ERC20.sol#L44

Thanks, getCode showed byte code on L1 (kovan), but showed 0x on L2. I figured out why: L2 chain was new, clear, it needed to set nonce not 57/58/etc. but 0. After I set nonce to zero and redeployed contract to brand new L2 - deploy transaction stucked in pending transactions in OVM, and batch submitter repeatedly showed this error:
image

If it matters - here code for contract deploy to L2:

const {ethers, ContractFactory} = require('ethers');

const ABI_OVM = require('../artifacts/contracts/HelloWorld.sol/HelloWorld.ovm.json').abi;
const BYTECODE_OVM = require('../artifacts/contracts/HelloWorld.sol/HelloWorld.ovm.json').bytecode;

let provider = new ethers.providers.JsonRpcProvider('http://localhost:8545');

let privateKey = '0x12345.....54321';
let wallet = new ethers.Wallet(privateKey, provider);

const factory = new ContractFactory(ABI_OVM, BYTECODE_OVM, wallet);

const contract = await factory.deploy({
    gasLimit: 9000000,
    gasPrice: 0,
    nonce: 0,
});

console.log('ADDRESS:', contract.address);
console.log('DEPLOYTRANSACTION:', contract.deployTransaction);

Any idea why deploying doesn't work?

@miguelmota
Copy link
Author

@uxname the code looks right so maybe it's an issue with the node configuration? Not sure.

I've been using hardhat and the optimism ethers plugin instead of ethers directly so there might be some differences there. Here's a hardhat example: https://github.com/miguelmota/hardhat-optimism-example/

Saw you asked in the discord channel so we'll see what they have to say.

@rphansen91
Copy link

How much KETH does it cost? Faucet not working if anyone can help me out?

0xd49389837f1b616C931C3663BcbAeb48D2ba858c

@miguelmota
Copy link
Author

@rphansen91 1 kETH sent (receipt)

@rphansen91
Copy link

rphansen91 commented Apr 3, 2021

@miguelmota Thank you!

Have you seen this Transaction nonce is too low issue on deploy?

Error deploying OVM_L1MessageSender: Error: processing response error (body="{\"jsonrpc\":\"2.0\",\"id\":2026,\"error\":{\"code\":-32010,\"message\":\"Transaction nonce is too low. Try incrementing the nonce.\"}}"

The contracts do seem to have deployed successfully however when looking at blockexplorer

https://kovan.etherscan.io/address/0xd49389837f1b616c931c3663bcbaeb48d2ba858c

@miguelmota
Copy link
Author

miguelmota commented Apr 3, 2021

@rphansen91 are you using WAIT_FOR_RECEIPTS=true? this would give enough time between deployments so it doesn't use the same nonce

@rphansen91
Copy link

I am @miguelmota and just doubled checked the correct spelling was correct

@miguelmota
Copy link
Author

The error is coming from the deploy script here but not sure where it would attempt to re-use the nonce since it's using the waitForReceipts option. The Optimism team in the discord could have more insight @rphansen91

@rphansen91
Copy link

rphansen91 commented Apr 4, 2021

@miguelmota thank you for the help! I was running the deploy script on a remote Ubuntu instance, could that have been the issue? When running from my local machine the contract addresses were output successfully.

@rphansen91
Copy link

@miguelmota It seems like the ETH1_HTTP env var has changed to ROLLUP_CLIENT_HTTP

Screen Shot 2021-04-04 at 8 38 47 AM

@rphansen91
Copy link

rphansen91 commented Apr 4, 2021

@miguelmota

I was able to get the geth_l2 and batch_submitter process running, But running into the issue

curl --silent --fail http://localhost:8545 -H "Content-Type: application/json" --data '{"method":"eth_chainId","params":[],"id":1,"jsonrpc":"2.0"}'

{"jsonrpc":"2.0","id":1,"error":{"code":-32601,"message":"the method eth_chainId does not exist/is not available"}}

I can confirm that the net version responds success however

curl --silent --fail http://localhost:8545 -H "Content-Type: application/json" --data '{"method":"net_version","params":[],"id":1,"jsonrpc":"2.0"}'


{"jsonrpc":"2.0","id":1,"result":"69"}

It is interesting because I get responses for net_* and rollup_* methods but not web3_* or eth_* when connecting to geth_l2

I also know it is correctly using my env file because if I remove rollup from RPC_API I receive the following response

{"jsonrpc":"2.0","id":1,"error":{"code":-32601,"message":"the method rollup_getInfo does not exist/is not available"}}

@taijusanagi
Copy link

@rphansen91

Hi, I'm also trying this tutorial, and thank you for mentioning env change!

It seems like the ETH1_HTTP env var has changed to ROLLUP_CLIENT_HTTP

My batch_submitter is working, but geth_l2 is still not able to connect infura node...
Putting infura url with infura key for ROLLUP_CLIENT_HTTP is correct?

Screen Shot 2021-04-05 at 13 15 05

@taijusanagi
Copy link

@rphansen91

above question is self solved by checking official Optimisms discord suport.

I comment outed below, and now ok to run l2 node.
https://github.com/ethereum-optimism/docker/blob/master/go-ethereum/wait-for-l1.sh

# RETRIES=${RETRIES:-20}
# until $(curl --silent --fail \
#     --output /dev/null \
#     "$ROLLUP_CLIENT_HTTP/eth/syncing"); do
#   sleep 1
#   echo "Will wait $((RETRIES--)) more times for $ROLLUP_CLIENT_HTTP to be up..."

#   if [ "$RETRIES" -lt 0 ]; then
#     echo "Timeout waiting for layer one node at $ROLLUP_CLIENT_HTTP"
#     exit 1
#   fi
# done

@taijusanagi
Copy link

I was able to run l2_geth and batch submitter, but I encountered below issue.

  reason: 'processing response error',
  code: 'SERVER_ERROR',
  body: `{"jsonrpc":"2.0","id":44,"error":{"code":-32000,"message":"Cannot pack simulateMessage: method 'simulateMessage' not found"}}\n`,

This can be solved by

ROLLUP_STATE_DUMP_PATH=https://raw.githubusercontent.com/ethereum-optimism/regenesis/master/kovan/1.json

change to 

ROLLUP_STATE_DUMP_PATH=https://raw.githubusercontent.com/ethereum-optimism/regenesis/master/kovan/2.json

this instruction is suggested in discord.

@taijusanagi
Copy link

I faced error that element block number is undefined, and batch cannot be submitted. I fixed this error by adding data-transport layer in cocker compose. I don't know why this fix, but it works so I post here for others.

docker-compose:

  data_transport_layer:
    image: ethereumoptimism/data-transport-layer:latest
    restart: unless-stopped
    env_file:
      - docker-compose.env
    ports:
      - 7878:7878

docker-compose.env

######### L2 GETH VARS #########
# ROLLUP_CLIENT_HTTP=https://kovan.infura.io/v3/infuraid
ROLLUP_CLIENT_HTTP=http://data_transport_layer:7878


# Data transport layer
DATA_TRANSPORT_LAYER__SYNC_FROM_L1=true
DATA_TRANSPORT_LAYER__SYNC_FROM_L2=false
DATA_TRANSPORT_LAYER__L2_RPC_ENDPOINT=http://geth_l2:8545
DATA_TRANSPORT_LAYER__L2_CHAIN_ID=420
DATA_TRANSPORT_LAYER__DB_PATH=/db
DATA_TRANSPORT_LAYER__SERVER_PORT=7878
DATA_TRANSPORT_LAYER__TRANSACTIONS_PER_POLLING_INTERVAL=1000
DATA_TRANSPORT_LAYER__L1_RPC_ENDPOINT=https://kovan.infura.io/v3/infuraId
DATA_TRANSPORT_LAYER__CONFIRMATIONS=0
DATA_TRANSPORT_LAYER__POLLING_INTERVAL=500
DATA_TRANSPORT_LAYER__LOGS_PER_POLLING_INTERVAL=2000
DATA_TRANSPORT_LAYER__DANGEROUSLY_CATCH_ALL_ERRORS=true
DATA_TRANSPORT_LAYER__SERVER_HOSTNAME=0.0.0.0
DATA_TRANSPORT_LAYER__ADDRESS_MANAGER=0x25Ca9DC75712F41ecDFba2Ac22dC6878c596dD3d
L1_NODE_WEB3_URL=https://kovan.infura.io/v3/infuraId
RETRIES=50

@miguelmota
Copy link
Author

Guide has been updated based on latest changes. Thanks @rphansen91 @taijusanagi

@ducnh1022
Copy link

is there any update.
I got error when run "yarn build:kovan"

error Command "build:copy" not found.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.
error Command failed with exit code 1.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment