{"content":{"title":"构建optimism私链","body":"**目的是要搭建一条optimism链，其中L1为以太坊goerli testnet。**\r\n\r\n1、软件依赖\r\n\r\n| 软件 |版本  |安装命令|\r\n| --- | --- | --- |\r\n|  ubuntu| 20.04 LTS |\r\n| git, curl, make||\r\n|go||\r\n|node|16.19.0|\r\n|yarn||\r\n|foundry|0.2.0| curl -L [https://foundry.paradigm.xyz](https://foundry.paradigm.xyz/)  |  bash . \\~/.bashrc  foundryup |\r\n\r\n2、编译源码\r\noptimism\r\n\r\n```\r\ngit clone https\\://github.com/ethereum-optimism/optimism.git\r\ncd  optimism\r\nyarn install\r\nmake op-node op-batcher\r\nyarn build\r\n```\r\nop-geth\r\n```\r\ngit clone https\\://github.com/ethereum-optimism/op-geth.git\r\ncd op-geth\r\nmake geth\r\n```\r\n3、通过alchemy获取访问goerli L1 节点的url。\r\n4、准备4个有资金的地址\r\n\r\n```\r\n1、Admin有能力更新合约的地址，部署合约\r\nAdmin: 0xb51076f56ce3b72c53a6e47c6097fc0145b6fec6\r\nPrivate Key: fb8c944efea1076f3d952639adfede19d810eb948cdc6************\r\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t  \r\n2、Proposer: 将L2的交易结果推送给L1\r\nProposer: 0xc420cd834d4e238de5ca1f9fa43dfea55b65ab4f      \r\nPrivate Key: 2c30ebec582167d4e1721696efdf30b576d991077fd6b************\r\n\r\n3、Batcher: 将sequencer中的交易数据推送到L1\r\nBatcher: 0xfa7d40f2cb3ac6ee27fa7ed6967ad47a7dd61eae       \r\nPrivate Key: 81587c1bf618c1b5acf637768327e81e0e1e4ae28aba3************\r\n\r\n4、Sequencer:签名p2p网络上的区块\r\nSequencer: 0x81db1a08cf0cda61582453b6146cb9c72bc261c1     \r\nPrivate Key: 6b795e64b7db54b36f593182331efab7bd2e6a274ab18************\r\n```\r\nadmin地址需要充goerli eth，因为需要用它部署智能合约。proposer和batcher也需要充钱，其中batcher因为要推送交易数据到L1，它会燃烧掉很多eth\r\n建议的账户资金\r\n\r\n```admin 0.2eth\r\nproposer 0.5eth\r\nbatcher 1.0 eth\r\n```\r\n5、配置网络\r\n- 当下链相关配置在contract-bedrock目录\r\n`cd \\~/optimism/packages/contract-bedrock\r\n`\r\n- 先选定一个L1 块作为我们rollup的起点。最好是选定一个finalized区块。使用foundry提供的cast命令来获取所需的信息。rpc为goerli node上的。\r\n`cast block finalized --rpc-url <RPC> | grep -E \"(timestamp|hash|number)\"`\r\n获得起点信息\r\n\r\n```\r\nubuntu@ubuntu:optimism/packages/contracts-bedrock$ cast block finalized --rpc-url https://eth-goerli.g.alchemy.com/v2/zkhmESllhO2QYoXuUje99N9_4gFqezsW  | grep -E \"(timestamp|hash|number)\"\r\nhash                 0x938c8f11dfb4cd7fda2b91312bfcdfe85c4ecd2c57e42bfb8dfbed8d11c19e40\r\nnumber               8743286\r\ntimestamp            1680168288\r\n```\r\n- 修改配置文件deploy-config/getting-started.json\r\n\r\n```\r\n* Replace \"ADMIN\" with the address of the Admin account you generated earlier.\r\n* Replace \"PROPOSER\" with the address of the Proposer account you generated earlier.\r\n* Replace \"BATCHER\" with the address of the Batcher account you generated earlier.\r\n* Replace \"SEQUENCER\" with the address of the Sequencer account you generated earlier.\r\n* Replace \"BLOCKHASH\" with the blockhash you got from the cast command.\r\n* Replace TIMESTAMP with the timestamp you got from the cast command. Note that although all the other fields are strings, this field is a number! Don’t include the quotation marks.\r\n```\r\n6、部署L1合约\r\n- 网络配置好后就可以部署L1合约了。在contracts-bedrock中，复制.env.example到.env中\r\n- .env文件中修改如下两个值\r\n\r\n```\r\n* L1_RPC — URL for your L1 node.\r\n* PRIVATE_KEY_DEPLOYER — Private key of the Admin account.\r\n```\r\n- 部署L1智能合约，这一步大概要执行15分钟，等待所有的合约部署完成后再进行下一步。\r\n`npx hardhat deploy --network getting-started`\r\n部署成功，输出日志（日志很长~）\r\n7、生成L2的配置文件，在L2这一层，我们需要生成3个重要的文件：genesis.json, rollup.json, jwt.json(JSON WEB TOKEN,它允许op-node和op-geth安全交流)\r\n进入op-node目录，替换RPC为自己的L1 RPC URL，执行如下命令\r\n\r\n```\r\ngo run cmd/main.go genesis l2 \\\r\n    --deploy-config ../packages/contracts-bedrock/deploy-config/getting-started.json \\\r\n    --deployment-dir ../packages/contracts-bedrock/deployments/getting-started/ \\\r\n    --outfile.l2 genesis.json \\\r\n    --outfile.rollup rollup.json \\\r\n    --l1-rpc https://eth-goerli.g.alchemy.com/v2/ov3CnhRMyIfiJ9eg5h1qUwdksgWc7XqK\r\n```\r\n执行成功的话，在op-node目录下会看到genesis.json和rollup.json文件。\r\n- 生成jwt.txt\r\n`openssl rand -hex 32 > jwt.json`\r\n将genesis.json和jwt.json文件拷贝到op-geth，这样我们等下才能用它来初始化和运行op-geth\r\n8、初始化op-geth\r\n我们将要运行一个sequencer node，需要导入sequencer的私钥，sequencer会用这个私钥来给block签名。\r\n- 进入op-geth目录，创建数据文件夹\r\n`mkdir datadir`\r\n- 保存一个密码\r\n`echo \"pwd\" > datadir/password`\r\n- 将squencer的秘钥放到datadir里面（秘钥不需要携带0x前缀）\r\n`echo \"<SEQUENCER KEY HERE>\" > datadir/block-signer-key`\r\n- 将秘钥导入op-geth中\r\n\r\n```\r\n./build/bin/geth account import --datadir=datadir --password=datadir/password datadir/block-signer-key\r\nINFO [03-30|19:32:00.604] Maximum peer count                       ETH=50 LES=0 total=50\r\nINFO [03-30|19:32:00.606] Smartcard socket not found, disabling    err=\"stat /run/pcscd/pcscd.comm: no such file or directory\"\r\nINFO [03-30|19:32:00.611] Set global gas cap                       cap=50,000,000\r\nAddress: {81db1a08cf0cda61582453b6146cb9c72bc261c1}\r\n```\r\n- 使用genesis.json来初始化op-geth\r\n\r\n```\r\nbuild/bin/geth init --datadir=datadir genesis.json\r\nINFO [03-30|19:32:37.431] Maximum peer count                       ETH=50 LES=0 total=50\r\nINFO [03-30|19:32:37.438] Smartcard socket not found, disabling    err=\"stat /run/pcscd/pcscd.comm: no such file or directory\"\r\nINFO [03-30|19:32:37.445] Set global gas cap                       cap=50,000,000\r\nINFO [03-30|19:32:37.448] Using leveldb as the backing database\r\nINFO [03-30|19:32:37.450] Allocated cache and file handles         database=/home/ubuntu/code/layer2/op/op-geth/datadir/geth/chaindata cache=16.00MiB handles=16\r\nINFO [03-30|19:32:37.464] Using LevelDB as the backing database\r\nINFO [03-30|19:32:37.479] Opened ancient database                  database=/home/ubuntu/code/layer2/op/op-geth/datadir/geth/chaindata/ancient/chain readonly=false\r\nINFO [03-30|19:32:37.479] Writing custom genesis block\r\nINFO [03-30|19:32:37.864] Persisted trie from memory database      nodes=3116 size=448.22KiB time=9.737762ms gcnodes=0 gcsize=0.00B gctime=0s livenodes=1 livesize=0.00B\r\nINFO [03-30|19:32:38.165] Successfully wrote genesis state         database=chaindata hash=e36ec8..6da447\r\nINFO [03-30|19:32:38.165] Using leveldb as the backing database\r\nINFO [03-30|19:32:38.165] Allocated cache and file handles         database=/home/ubuntu/code/layer2/op/op-geth/datadir/geth/lightchaindata cache=16.00MiB handles=16\r\nINFO [03-30|19:32:38.179] Using LevelDB as the backing database\r\nINFO [03-30|19:32:38.230] Opened ancient database                  database=/home/ubuntu/code/layer2/op/op-geth/datadir/geth/lightchaindata/ancient/chain readonly=false\r\nINFO [03-30|19:32:38.234] Writing custom genesis block\r\nINFO [03-30|19:32:38.592] Persisted trie from memory database      nodes=3116 size=448.22KiB time=15.243075ms gcnodes=0 gcsize=0.00B gctime=0s livenodes=1 livesize=0.00B\r\nINFO [03-30|19:32:38.809] Successfully wrote genesis state         database=lightchaindata hash=e36ec8..6da447\r\n```\r\n9、运行op-geth，将如下命令中的<SEQUENCER>替换成sequencer对应的地址\r\n    \r\n```\r\n    ./build/bin/geth \\\r\n    --datadir ./datadir \\\r\n    --http \\\r\n    --http.corsdomain=\"*\" \\\r\n    --http.vhosts=\"*\" \\\r\n    --http.addr=0.0.0.0 \\\r\n    --http.api=web3,debug,eth,txpool,net,engine \\\r\n    --ws \\\r\n    --ws.addr=0.0.0.0 \\\r\n    --ws.port=8546 \\\r\n    --ws.origins=\"*\" \\\r\n    --ws.api=debug,eth,txpool,net,engine \\\r\n    --syncmode=full \\\r\n    --gcmode=full \\\r\n    --nodiscover \\\r\n    --maxpeers=0 \\\r\n    --networkid=42069 \\\r\n    --authrpc.vhosts=\"*\" \\\r\n    --authrpc.addr=0.0.0.0 \\\r\n    --authrpc.port=8551 \\\r\n    --authrpc.jwtsecret=./jwt.txt \\\r\n    --rollup.disabletxpoolgossip=true \\\r\n    --password=./datadir/password \\\r\n    --allow-insecure-unlock \\\r\n    --mine \\\r\n    --miner.etherbase=<SEQUENCER> \\\r\n    --unlock=<SEQUENCER>\r\n```\r\n   运行成功后还不会有任何区块生成，因为op-geth是由op-node驱动的，接下来我们还需要启动op-node\r\n    10、运行一个op-node\r\n就像以太坊一样，op也有一个共识客户端（op-node）、一个执行客户端（op-geth），共识客户端通过engine api驱动执行客户端。\r\n进入op-node包下，使用如下命令启动，<SEQUENCER>替换为sequencer账号，<RPC>替换为L1的URL\r\n    \r\n```\r\n    ./bin/op-node \\\r\n    --l2=http://localhost:8551 \\\r\n    --l2.jwt-secret=./jwt.txt \\\r\n    --sequencer.enabled \\\r\n    --sequencer.l1-confs=3 \\\r\n    --verifier.l1-confs=3 \\\r\n    --rollup.config=./rollup.json \\\r\n    --rpc.addr=0.0.0.0 \\\r\n    --rpc.port=8547 \\\r\n    --p2p.disable \\\r\n    --rpc.enable-admin \\\r\n    --p2p.sequencer.key=<SEQUENCERKEY> \\\r\n    --l1=<RPC> \\\r\n    --l1.rpckind=<RPCKIND>\r\n```\r\n该命令执行成功后，op-node开始处理L1上选定的起始块之后的所有信息，一旦op-node有了足够的信息，它就开始发送消息给op-geth，这时，将会看到op-geth上有区块被创建，成功了。\r\n    11、运行op-batcher\r\n    op-batcher将sequencer上的交易发布到L1上，一旦交易到达L1，他们就成了Rollup的一部分。没有op-batcher,发送到sequencer的交易就不会被放到L1上也不会成为标准链的一部分。\r\n- 进入op-batcher目录\r\n`cd ~/optimism/op-batcher`\r\n- 使用如下命令运行op-batcher，同样的需要替换<RPC>和<BATCHERKEY>，需要保证batcher地址里至少有1eth\r\n    \r\n```\r\n    ./bin/op-batcher \\\r\n    --l2-eth-rpc=http://localhost:8545 \\\r\n    --rollup-rpc=http://localhost:8547 \\\r\n    --poll-interval=1s \\\r\n    --sub-safety-margin=6 \\\r\n    --num-confirmations=1 \\\r\n    --safe-abort-nonce-too-low-count=3 \\\r\n    --resubmission-timeout=30s \\\r\n    --rpc.addr=0.0.0.0 \\\r\n    --rpc.port=8548 \\\r\n    --target-l1-tx-size-bytes=2048 \\\r\n    --l1-eth-rpc=<RPC> \\\r\n    --private-key=<BATCHERKEY>\r\n```\r\n12、get some eth on your rollup\r\n    当连上你的钱包，你会发现你的rollup里面没有任何的钱。你需要在你的rollup里面存放一点eth用于支付gas。在你的连上最容易的质押eth方式就是往这个 OptimismPortalProxy合约里发送资金。找到这个合约的地址\r\n    \r\n```\r\n    cd ~/optimism/packages/contracts-bedrock\r\ncat deployments/getting-started/Proxy__OVM_L1StandardBridge.json.json | grep \\\"address\\\":\r\n```\r\n大致会得到这样的输出\r\n    \r\n```\r\n    \"address\": \"0x874f2E16D803c044F10314A978322da3c9b075c7\",\r\n        \"internalType\": \"address\",\r\n        \"type\": \"address\"\r\n        \"internalType\": \"address\",\r\n        \"type\": \"address\"\r\n        \"internalType\": \"address\",\r\n        \"type\": \"address\"\r\n        \"internalType\": \"address\",\r\n        \"type\": \"address\"\r\n```    \r\n拿到这个L1桥代理合约地址，使用你想在你的rollup上拥有eth的钱包，向这个地址发送少量的eth，大概5分钟后你l2钱包的地址上就会收到eth\r\n13、现在你拥有了一个完整的基于evm的op stack。"},"author":{"user":"https://learnblockchain.cn/people/6119","address":null},"history":null,"timestamp":1684161915,"version":1}