This document outlines the steps to create your own L2 rollup testnet using Phalcon Fork as the L1 blockchain. These instructions are based on the Optimism documentation. Ensure you have installed the necessary software dependencies from the Optimism docs before proceeding.
Get Access to Phalcon Fork
To deploy the OP Stack Rollup into Phalcon Fork, you must create a Fork and obtain the following parameters.
Create a Fork
Log into https://phalcon.blocksec.com/fork. Register an account if you do not have one.
Click the created Fork and click ‘Settings’ button inside the Fork.
Obtain the following information.
- RPC: the RPC of this Fork. We use [FORK_RPC] in the following.
- RPC ID: the id of this Fork RPC. We use [RPC_ID] in the following.
We also need the API create of your account to verify the contracts. Click the account icon on the left bottom and click Account Settings. Get the Access Key
(DO NOT SHARE THIS WITH ANYONE).
- Access Key: The key used to verify the contracts. We use [API_KEY] in the following.
Build the Source Code
Build the Optimism Monorepo
cd ~
git clone https://github.com/ethereum-optimism/optimism.git
cd optimism
git checkout tutorials/chain
Install dependencies and build the packages.
git submodule update --init --recursive
./packages/contracts-bedrock/scripts/getting-started/versions.sh
pnpm install
make op-node op-batcher op-proposer
pnpm build
Build op-geth
Clone the repository and build op-geth.
cd ~
git clone https://github.com/ethereum-optimism/op-geth.git
cd op-geth
make geth
Fill Out Environment Variables
cd ~/optimism
cp .envrc.example .envrc
Edit .envrc
using a text editor of your choice. Modify the L1_RPC_URL
to the RPC URL
you obtained from Phalcon Fork and set L1_RPC_KIND
to basic
.
Generate Addresses
Follow the link to generate addresses. Copy the address to .envrc
.
Fund these address using the Faucet in Phalcon Fork. In this blog, the addresses are:
- export GS_ADMIN_ADDRESS=0x5E7AfB127cf0Bfbd7f259D1a5Bd05a53F7f1cC89
- export GS_BATCHER_ADDRESS=0xed6DCC6B20Ee9d850B56C2b474BE5c666D7C44DB
- export GS_PROPOSER_ADDRESS=0xf4425AdF3F4fD45dEb4E768A4F32FEa0b774a63E
- export GS_SEQUENCER_ADDRESS=0x2012d9D7cc85Bc1d9231123B506a99C56d722A60
I added 100 Ether to each address using the Faucet
tool.
Load Environment variables
cd ~/optimism
direnv allow
You need to confirm the variables were loaded!
Configure the network
cd ~/optimism
cd packages/contracts-bedrock
We need to change the L1 chainID to 1 in ./scripts/getting-started/config.sh .
"l1ChainID": 1,
"l2ChainID": 42069,
Now execute the config script.
./scripts/getting-started/config.sh
Deploy the Create2 Factory (Optional)
Since the Create2 factory is already deployed in the Ethereum mainnet (and is forked inside our Fork), we do not need to deploy this factory. We can use the following command to double confirm that.
cast codesize 0x4e59b44847b379578588920cA78FbF26c0B4956C --rpc-url $L1_RPC_URL
The output is 69
.
Deploy and verify the L1 contracts.
If you do not need to verify the contracts, the parameters after --slow
can be removed.
cd ~/optimism
cd packages/contracts-bedrock
forge script scripts/Deploy.s.sol:Deploy --private-key $GS_ADMIN_PRIVATE_KEY --broadcast --rpc-url $L1_RPC_URL --slow --verify --verifier-url https://api.phalcon.blocksec.com/api/[RPC_ID] --etherscan-api-key [API_KEY]
Note compared with the original article, I added a couple of parameters in the command.
- — slow: Makes sure a transaction is sent, only after its previous one has been confirmed and succeeded. See this link.
- — verify: Verify the deployed contracts
- — verifier-url: the verifier URL in Phalcon Fork
- — etherscan-api-key: the API key used to verify contracts in Phalcon Fork (not Etherscan)
forge script scripts/Deploy.s.sol:Deploy --sig 'sync()' --rpc-url $L1_RPC_URL
See all the deployed and verified smart contracts.
Generate the L2 config files
cd ~/optimism/op-node
go run cmd/main.go genesis l2 \
--deploy-config ../packages/contracts-bedrock/deploy-config/getting-started.json \
--deployment-dir ../packages/contracts-bedrock/deployments/getting-started/ \
--outfile.l2 genesis.json \
--outfile.rollup rollup.json \
--l1-rpc $L1_RPC_URL
openssl rand -hex 32 > jwt.txt
cp genesis.json ~/op-geth
cp jwt.txt ~/op-geth
Initialize op-geth
cd ~/op-geth
mkdir datadir
build/bin/geth init --datadir=datadir genesis.json
Start op-geth
cd ~/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 \
--ws \
--ws.addr=0.0.0.0 \
--ws.port=8546 \
--ws.origins="*" \
--ws.api=debug,eth,txpool,net,engine \
--syncmode=full \
--gcmode=archive \
--nodiscover \
--maxpeers=0 \
--networkid=42069 \
--authrpc.vhosts="*" \
--authrpc.addr=0.0.0.0 \
--authrpc.port=8551 \
--authrpc.jwtsecret=./jwt.txt \
--rollup.disabletxpoolgossip=true
Make Phalcon Fork Automatically Generate Block (Important!)
Different from Ethereum, Phalcon Fork does not automatically generate a new block every 12 seconds. However, we can use the evm_mine
method to generate an empty block to simulate this behaviro.
Create a script called newblock.sh
curl --location [FORK_RPC] \
--header 'Content-Type: application/json' \
--data '{
"jsonrpc": "2.0",
"method": "evm_mine",
"params": [],
"id": 1
}'
Then use watch to execute this script every 12 seconds.
chmod a+x newblock.sh
watch -n 12 -x ./newblock.sh
In Phalcon Block dashboard, we can see that the next block number changes every 12 seconds (if we refresh the page.) We can also see the transactions, blocks inside the Phalcon Block Scan.
Start op-node
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=./rollup.json \
--rpc.addr=0.0.0.0 \
--rpc.port=8547 \
--p2p.disable \
--rpc.enable-admin \
--p2p.sequencer.key=$GS_SEQUENCER_PRIVATE_KEY \
--l1=$L1_RPC_URL \
--l1.rpckind=$L1_RPC_KIND
--l1.trustrpc
**Note that, we added --l1.trustrpc
in the command. **That's because Phalcon Block does not support the eth_getProof
method in the op-node code.
Start op-batcher
cd ~/optimism/op-batcher
./bin/op-batcher \
--l2-eth-rpc=http://localhost:8545 \
--rollup-rpc=http://localhost:8547 \
--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=1 \
--l1-eth-rpc=$L1_RPC_URL \
--private-key=$GS_BATCHER_PRIVATE_KEY
Start op-proposer
cd ~/optimism/op-proposer
./bin/op-proposer \
--poll-interval=12s \
--rpc.port=8560 \
--rollup-rpc=http://localhost:8547 \
--l2oo-address=$(cat ../packages/contracts-bedrock/deployments/getting-started/L2OutputOracleProxy.json | jq -r .address) \
--private-key=$GS_PROPOSER_PRIVATE_KEY \
--l1-eth-rpc=$L1_RPC_URL
Now we have a working l2 Rollup Testnet based on Phalcon Fork as L1.
Connect Your Wallet to Your Chain
We manually add a new network in MetaMask, with the following parameters:
- Network Name: L2_ON_Phalcon_Fork (or anyname you want)
- New RPC URL: http://localhost:8545 (or a publiciP:8545 )
- Chain ID: 42069
- Currency: Ether (ETH)
- Explorer: leave blank
We also need to add the L1 network (Phalcon Fork) into the metamask. You can click “Add to MetaMask” button in the Fork dashboard.
Get ETH On Your Chain
We can then get ETH on the L2 chain by sending Ether from L1 (Phalcon Block) to the L1StandardBridgeProxy
. In this blog, I sent 88 Ether to the L2. See this transaction.
And in L2, we can see the bridged 88 Ether. Please take a look at the following transactions.
0x0c2ddabdfa935fe0f7d47f6aed24cbdb57582c50810b46e164f0903001e7b14b
View in Phalcon Explorer.
Summary
The Fork used in this blog can be found in this Phalcon Fork Scan
In summary, we create a L2 rollup testnet based on OP stack using a forked mainnet as L1. By doing so, we can learn how the L2 works, and make further changes if necessary.
Access Phalcon Fork today to make your own L2 rollup testnet!