Layer2 —— OP Stack 部署指南

简介

OP Stack 是 Optimism 开发的模块化区块链技术栈,允许开发者轻松创建自己的 Layer2 网络。本指南提供了在 Ubuntu 环境下从零开始搭建一个完整的 Layer2 网络,包括环境配置、合约部署、节点启动和基本操作验证。

一、准备系统环境

1.1 安装 Ubuntu

打开 Windows PowerShell 终端

1
2
3
4
5
# 查看可用的 Ubuntu 发行版
wsl --list --online

# 安装指定版本的 Ubuntu
wsl --install -d Ubuntu-24.04

1.2 安装软件依赖

打开 Ubuntu-24.04 子系统(在安装 pnpm 和 mise 时,需修改自己环境变量加载的路径)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
# 更新系统
sudo apt update && sudo apt upgrade -y

# 安装基础依赖
sudo apt install -y curl wget git build-essential

# 安装 go
wget https://go.dev/dl/go1.25.0.linux-amd64.tar.gz
sudo tar -C /usr/local -xzf go1.25.0.linux-amd64.tar.gz
rm go1.25.0.linux-amd64.tar.gz
echo -e '\n# Go Language\nexport PATH=$PATH:/usr/local/go/bin' >> ~/.bashrc
source ~/.bashrc

# 安装 node.js
curl -fsSL https://deb.nodesource.com/setup_22.x | sudo -E bash -
sudo apt-get install -y nodejs

# 安装 pnpm
curl -fsSL https://get.pnpm.io/install.sh | sh
source /home/eth/.bashrc

# 安装 foundry
curl -L https://foundry.paradigm.xyz | bash
source ~/.bashrc
~/.foundry/bin/foundryup

# 安装 make
sudo apt install -y make

# 安装 jq
sudo apt install -y jq

# 安装 direnv
sudo apt install -y direnv
echo -e '\n# Direnv hook\neval "$(direnv hook bash)"' >> ~/.bashrc
source ~/.bashrc

# 安装 just
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y
. "$HOME/.cargo/env"
cargo install just

# 安装 mise
curl https://mise.run | sh
echo "eval \"\$(/home/eth/.local/bin/mise activate bash)\"" >> ~/.bashrc
source ~/.bashrc

1.3 验证安装

1
2
3
4
5
6
7
8
9
10
11
12
# 检查所需软件依赖是否正确安装
git --version # git version 2.43.0
go version # go version go1.25.0 linux/amd64
node --version # v22.19.0
pnpm --version # 10.16.1
forge --version # forge Version: 1.3.5-stable
make --version # GNU Make 4.3
jq --version # jq-1.7
direnv --version # 2.32.1
rustc --version # rustc 1.89.0 (29483883e 2025-08-04)
just --version # just 1.42.4
mise --version # 2025.9.10 linux-x64 (2025-09-13)

二、获取 Sepolia 测试网资源

2.1 获取 Sepolia RPC URL

从以下服务之一获取 Sepolia RPC URL:

2.2 获取测试 ETH

在以下链接中获取测试币 SepoliaETH。

三、构建 OP-Stack 组件

3.1 克隆 optimism 和 op-geth 仓库

1
2
3
4
5
6
7
8
9
10
# 克隆 optimism 并切换到最新 release 分支
cd ~
git clone https://github.com/ethereum-optimism/optimism.git
cd optimism
git checkout v1.13.6 -b v1.13.6

# 克隆 op-geth 到 optimism 目录下并切换到最新 release 分支
git clone https://github.com/ethereum-optimism/op-geth.git
cd op-geth
git checkout v1.101602.0 -b v1.101602.0

3.2 构建 op-geth,op-node,op-batcher,op-proposer

1
2
3
4
5
6
7
8
9
10
11
cd ~/optimism/op-geth
make geth

cd ..
make op-node op-batcher op-proposer

# 检查组件是否构建成功
./op-geth/build/bin/geth --version
./op-node/bin/op-node --version
./op-batcher/bin/op-batcher --version
./op-proposer/bin/op-proposer --version

四、配置环境变量

4.1 生成账户

1
2
cd ~/optimism
./packages/contracts-bedrock/scripts/getting-started/wallets.sh

此命令会生成五个地址及其私钥:

  • Admin(管理员)
  • Batcher(批处理者)
  • Proposer(提议者)
  • Sequencer(排序者)
  • Challenger(挑战者)

4.2 编辑环境变量文件

创建.envrc 文件

1
nano .envrc

填写以下变量:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
# Admin account
export GS_ADMIN_ADDRESS=
export GS_ADMIN_PRIVATE_KEY=

# Batcher account
export GS_BATCHER_ADDRESS=
export GS_BATCHER_PRIVATE_KEY=

# Proposer account
export GS_PROPOSER_ADDRESS=
export GS_PROPOSER_PRIVATE_KEY=

# Sequencer account
export GS_SEQUENCER_ADDRESS=
export GS_SEQUENCER_PRIVATE_KEY=

# Challenger account
export GS_CHALLENGER_ADDRESS=
export GS_CHALLENGER_PRIVATE_KEY=

##################################################
# Layer1 RPC Configuration #
##################################################

# RPC URL for the L1 network to interact with
export L1_RPC_URL=
export L1_BEACON_URL="https://ethereum-sepolia-beacon-api.publicnode.com"

# The kind of RPC provider, used to inform optimal transactions receipts
# fetching. Valid options: alchemy, quicknode, infura, parity, nethermind,
# debug_geth, erigon, basic, any.
export L1_RPC_KIND=

##################################################
# Chain Configuration #
##################################################

# The unique chain ID of the Layer 1 network(e.g., Sepolia = 11155111)
export L1_CHAIN_ID=11155111
# The unique chain ID you assign to your Layer 2 network (custom value)
export L2_CHAIN_ID=
# The average block time of the Layer 1 network (in seconds)
export L1_BLOCK_TIME=12
# The block time you configure for your Layer 2 network (in seconds)
export L2_BLOCK_TIME=2

保存文件(Ctrl+O, Enter, Ctrl+X)

4.3 加载环境变量

1
direnv allow

验证环境变量是否加载

1
2
3
4
5
6
7
8
9
10
11
12
13
echo "=== 环境变量检查 ==="
echo "GS_ADMIN_ADDRESS: $GS_ADMIN_ADDRESS"
echo "GS_BATCHER_ADDRESS: $GS_BATCHER_ADDRESS"
echo "GS_PROPOSER_ADDRESS: $GS_PROPOSER_ADDRESS"
echo "GS_SEQUENCER_ADDRESS: $GS_SEQUENCER_ADDRESS"
echo "GS_CHALLENGER_ADDRESS: $GS_CHALLENGER_ADDRESS"
echo "L1_RPC_KIND: $L1_RPC_KIND"
echo "L1_RPC_URL: $L1_RPC_URL"
echo "L1_BEACON_URL: $L1_BEACON_URL"
echo "L1_CHAIN_ID: $L1_CHAIN_ID"
echo "L2_CHAIN_ID: $L2_CHAIN_ID"
echo "L1_BLOCK_TIME: $L1_BLOCK_TIME"
echo "L2_BLOCK_TIME: $L2_BLOCK_TIME"

4.4 为账户充值

为以下地址充值 SepoliaETH:

  • Admin — 0.5 SepoliaETH
  • Batcher — 0.1 SepoliaETH
  • Proposer — 0.2 SepoliaETH
1
2
3
4
# 查看账户余额
cast balance $GS_ADMIN_ADDRESS --rpc-url $L1_RPC_URL
cast balance $GS_BATCHER_ADDRESS --rpc-url $L1_RPC_URL
cast balance $GS_PROPOSER_ADDRESS --rpc-url $L1_RPC_URL

五、部署 L1 合约

5.1 获取 op-deployer

1
2
3
4
5
6
7
8
cd ~/optimism
mkdir -p bin
wget https://github.com/ethereum-optimism/optimism/releases/download/op-deployer%2Fv0.2.6/op-deployer-0.2.6-linux-amd64.tar.gz
sudo tar -C ./bin -xzf op-deployer-0.2.6-linux-amd64.tar.gz --strip-components=1
rm op-deployer-0.2.6-linux-amd64.tar.gz

# 验证是否下载解压成功
./bin/op-deployer --version

5.2 初始化 op-deployer 配置

1
2
mkdir -p ~/.deployer
./bin/op-deployer init --l1-chain-id $L1_CHAIN_ID --l2-chain-ids $L2_CHAIN_ID --workdir .deployer

此命令会生成 intend.jsonstate.json

5.3 修改 intend.json 配置

1
nano .deployer/intent.toml

确保配置中包含以下内容并替换相应的地址:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
configType = "standard"
l1ChainID = 11155111
opcmAddress = "0x6b6f9129efb1b7a48f84e3b787333d1dca02ee34" # L1 上的 OP Chain Manager 合约地址
fundDevAccounts = false
useInterop = false
l1ContractsLocator = "tag://op-contracts/v2.2.0"
l2ContractsLocator = "tag://op-contracts/v1.7.0-beta.1+l2-contracts"

[[chains]]
id = "0x00000000000000000000000000000000000000000000000000000000004f5da2" # L2_CHAIN_ID 的十六进制
baseFeeVaultRecipient = "YOUR_ADMIN_ADDRESS"
l1FeeVaultRecipient = "YOUR_ADMIN_ADDRESS"
sequencerFeeVaultRecipient = "YOUR_ADMIN_ADDRESS"
eip1559DenominatorCanyon = 250
eip1559Denominator = 50
eip1559Elasticity = 6
[chains.roles]
l1ProxyAdminOwner = "0x1eb2ffc903729a0f03966b917003800b145f56e2"
l2ProxyAdminOwner = "0x2fc3ffc903729a0f03966b917003800b145f67f3"
systemConfigOwner = "YOUR_ADMIN_ADDRESS"
unsafeBlockSigner = "YOUR_SEQUENCER_ADDRESS"
batcher = "YOUR_BATCHER_ADDRESS"
proposer = "YOUR_PROPOSER_ADDRESS"
challenger = "0xfd1d2e729ae8eee2e146c033bf4400fe75284301"

5.4 部署 L1 合约

1
2
3
4
5
# 查询 L1 gas fee,判断 L1 RPC 是否连接成功
cast gas-price --rpc-url $L1_RPC_URL

# 部署合约
./bin/op-deployer apply --workdir .deployer --l1-rpc-url $L1_RPC_URL --private-key $GS_ADMIN_PRIVATE_KEY

5.5 生成 L2 配置文件

1
2
3
4
5
# 生成 genesis.json(用于 op-geth)
./bin/op-deployer inspect genesis --workdir .deployer $L2_CHAIN_ID > .deployer/genesis.json

# 生成 rollup.json(用于 op-node)
./bin/op-deployer inspect rollup --workdir .deployer $L2_CHAIN_ID > .deployer/rollup.json

六、启动 Layer2

6.1 初始化并启动 op-geth

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
# 生成 jwt 密钥用于 op-geth 与 op-node 通信
cd ~/optimism/op-geth
openssl rand -hex 32 > jwt.txt
cp jwt.txt ../op-node/

# 初始化 op-geth
mkdir -p datadir
build/bin/geth init --state.scheme=hash --datadir=datadir ../.deployer/genesis.json

#启动 op-geth
./build/bin/geth \
--datadir ./datadir \
--http \
--http.corsdomain="*" \
--http.vhosts="*" \
--http.addr=0.0.0.0 \
--http.api=web3,debug,eth,txpool,net,engine,miner \
--ws \
--ws.addr=0.0.0.0 \
--ws.port=8546 \
--ws.origins="*" \
--ws.api=debug,eth,txpool,net,engine,miner \
--syncmode=full \
--gcmode=archive \
--nodiscover \
--maxpeers=0 \
--networkid=$L2_CHAIN_ID \
--authrpc.vhosts="*" \
--authrpc.addr=0.0.0.0 \
--authrpc.port=8551 \
--authrpc.jwtsecret=./jwt.txt \
--rollup.disabletxpoolgossip=true

6.2 启动 op-node

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
cd ~/optimism/op-node

./bin/op-node \
--l2=http://localhost:8551 \
--l2.jwt-secret=./jwt.txt \
--sequencer.enabled \
--sequencer.l1-confs=5 \
--verifier.l1-confs=4 \
--rollup.config=../.deployer/rollup.json \
--rpc.addr=0.0.0.0 \
--rpc.port=9545 \
--p2p.disable \
--rpc.enable-admin \
--p2p.sequencer.key=$GS_SEQUENCER_PRIVATE_KEY \
--l1=$L1_RPC_URL \
--l1.rpckind=$L1_RPC_KIND \
--l1.beacon=$L1_BEACON_URL

6.3 启动 op-batcher

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
cd ~/optimism/op-batcher

./bin/op-batcher \
--l2-eth-rpc=http://localhost:8545 \
--rollup-rpc=http://localhost:9545 \
--poll-interval=1s \
--sub-safety-margin=6 \
--num-confirmations=1 \
--safe-abort-nonce-too-low-count=3 \
--resubmission-timeout=30s \
--rpc.addr=0.0.0.0 \
--rpc.port=8548 \
--rpc.enable-admin \
--max-channel-duration=25 \
--l1-eth-rpc=$L1_RPC_URL \
--private-key=$GS_BATCHER_PRIVATE_KEY

6.4 启动 op-proposer

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 加载 op-proposer 配置变量(也可加到 .envrc 里面)
export OP_PROPOSER_WAIT_NODE_SYNC=true
export OP_PROPOSER_PROPOSAL_INTERVAL=15m
export OP_PROPOSER_GAME_FACTORY_ADDRESS=$(cat ~/.deployer/state.json | jq -r '.opChainDeployments[0].disputeGameFactoryProxyAddress')
export OP_PROPOSER_GAME_TYPE=1


cd ~/optimism/op-proposer

./bin/op-proposer \
--poll-interval=12s \
--rpc.port=8560 \
--rollup-rpc=http://localhost:9545 \
--private-key=$GS_PROPOSER_PRIVATE_KEY \
--l1-eth-rpc=$L1_RPC_URL

七、验证部署

7.1 检查 L2 链状态

1
2
3
curl -X POST -H "Content-Type: application/json" \
--data '{"jsonrpc":"2.0","method":"eth_blockNumber","params":[],"id":1}' \
$L2_RPC_URL

7.2 连接钱包到 Layer2

在 MetaMask 中添加自定义网络:

7.3 将 SepoliaETH 发送到 Bridge 合约

1
2
3
# 获取 L1StandardBridge 地址
L1StandardBridge=$(cat ~/optimism/.deployer/state.json | jq -r '.opChainDeployments[0].l1StandardBridgeProxyAddress')
echo "L1StandardBridge 地址: $L1StandardBridge"

通过 Metamask 向你的 桥接地址 发送(0.0001 SepoliaETH),发送成功后大约需要 5 分钟才能在 Layer2 上看到 ETH.

Hooray!Op Stack 部署成功!!!

八、基本转账 CLI 操作实例

8.1 从 L1 的 Admin 桥接到 L2 的 admin

1
2
3
4
5
6
7
8
9
10
11
cast send $L1StandardBridge \
--rpc-url $L1_RPC_URL \
--private-key $GS_ADMIN_PRIVATE_KEY \
--value 0.0001ether \
"depositETH(uint32,bytes)" \
200000 \
"0x"

# 查看 Admin L1 和 L2 的余额
cast balance $GS_ADMIN_ADDRESS --rpc-url $L1_RPC_URL
cast balance $GS_ADMIN_ADDRESS --rpc-url $L2_RPC_URL

8.2 从 L1 的 Admin 桥接到 L2 的 Batcher

1
2
3
4
5
6
7
8
9
10
11
12
cast send $L1StandardBridge \
--rpc-url $L1_RPC_URL \
--private-key $GS_ADMIN_PRIVATE_KEY \
--value 0.0001ether \
"depositETHTo(address,uint32,bytes)" \
$GS_BATCHER_ADDRESS \
200000 \
"0x"

# 查看 Admin L1 和 Batcher L2 的余额
cast balance $GS_ADMIN_ADDRESS --rpc-url $L1_RPC_URL
cast balance $GS_BATCHER_ADDRESS --rpc-url $L2_RPC_URL

8.3 L2 转账

1
2
3
4
5
6
7
8
9
# L2 从 Batcher 转账到 Admin
cast send $GS_ADMIN_ADDRESS \
--rpc-url $L2_RPC_URL \
--private-key $GS_BATCHER_PRIVATE_KEY \
--value 0.00001ether

# 查看 Admin L2 和 Batcher L2 的余额
cast balance $GS_ADMIN_ADDRESS --rpc-url $L2_RPC_URL
cast balance $GS_BATCHER_ADDRESS --rpc-url $L2_RPC_URL