Add Optimism Fixturenet stack (#266)

* Initial version

* Update readme

* Build op-geth container

* Add optimism go code containers

* Add optimism contracts container

* Update optimism contracts container build

* Add fixturenet-optimism-contracts service to deploy L1 contracts

* Add fixturenet-optimism op-node and op-geth

* Avoid reading addresses from a file when sending balances

* Fixes for running op-geth container

* Fix image name and command in optimism-contracts service

* Add a healthcheck to lighthouse bootnode to avoid failing eth txs

* Avoid using hardhat ethers to send balances from an account

* Update script to send balance to L1 bridge proxy contract

* Implement op-node container

* Wait for a finalized L1 block to exist

* Fix for running op-batcher

* Add a todo for restart support

* Integrate optimism-contracts service and update instructions

* Update clean-up to remove docker volumes

* Update volume access permissions

* Add a todo to replace foundry usage with web3 js

* Add known issues

* Fix README

* Fix indentation

* Update known issues

---------

Co-authored-by: David Boreham <david@bozemanpas.com>
Co-authored-by: David Boreham <david@bozemanpass.com>
Co-authored-by: nabarun <nabarun@deepstacksoft.com>
This commit is contained in:
prathamesh0
2023-04-03 12:33:47 +05:30
committed by GitHub
co-authored by David Boreham dboreham nabarun
parent 432fc4755b
commit fc522140ba
23 changed files with 599 additions and 3 deletions
+11
View File
@@ -0,0 +1,11 @@
#!/bin/sh
set -e
op-node genesis l2 \
--deploy-config /contracts-bedrock/deploy-config/getting-started.json \
--deployment-dir /contracts-bedrock/deployments/getting-started/ \
--outfile.l2 /app/genesis.json \
--outfile.rollup /app/rollup.json \
--l1-rpc $L1_RPC
openssl rand -hex 32 > /app/jwt.txt
@@ -0,0 +1,28 @@
import fs from 'fs'
import { task } from 'hardhat/config'
import { hdkey } from 'ethereumjs-wallet'
import * as bip39 from 'bip39'
task('rekey-json', 'Generates a new set of keys for a test network')
.addParam('output', 'JSON file to output accounts to')
.setAction(async ({ output: outputFile }) => {
const mnemonic = bip39.generateMnemonic()
const pathPrefix = "m/44'/60'/0'/0"
const labels = ['Admin', 'Proposer', 'Batcher', 'Sequencer']
const hdwallet = hdkey.fromMasterSeed(await bip39.mnemonicToSeed(mnemonic))
const output = {}
for (let i = 0; i < labels.length; i++) {
const label = labels[i]
const wallet = hdwallet.derivePath(`${pathPrefix}/${i}`).getWallet()
const addr = '0x' + wallet.getAddress().toString('hex')
const pk = wallet.getPrivateKey().toString('hex')
output[label] = { address: addr, privateKey: pk }
}
fs.writeFileSync(outputFile, JSON.stringify(output, null, 2))
console.log(`L2 account keys written to ${outputFile}`)
})
@@ -0,0 +1,81 @@
#!/bin/bash
set -e
# TODO Support restarts; fixturenet-eth-geth currently starts fresh on a restart
# Exit if a deployment already exists (on restarts)
# if [ -d "deployments/getting-started" ]; then
# echo "Deployment directory deployments/getting-started already exists, exiting"
# exit 0
# fi
# Append tasks/index.ts file
echo "import './rekey-json'" >> tasks/index.ts
echo "import './send-balance'" >> tasks/index.ts
# Update the chainId in the hardhat config
sed -i "/getting-started/ {n; s/.*chainId.*/ chainId: $CHAIN_ID,/}" hardhat.config.ts
# Generate the L2 account addresses
yarn hardhat rekey-json --output /l2-accounts/keys.json
# Read JSON file into variable
KEYS_JSON=$(cat /l2-accounts/keys.json)
# Parse JSON into variables
ADMIN_ADDRESS=$(echo "$KEYS_JSON" | jq -r '.Admin.address')
ADMIN_PRIV_KEY=$(echo "$KEYS_JSON" | jq -r '.Admin.privateKey')
PROPOSER_ADDRESS=$(echo "$KEYS_JSON" | jq -r '.Proposer.address')
BATCHER_ADDRESS=$(echo "$KEYS_JSON" | jq -r '.Batcher.address')
SEQUENCER_ADDRESS=$(echo "$KEYS_JSON" | jq -r '.Sequencer.address')
# Read the private key of a L1 account
# TODO: Take from env if /geth-accounts volume doesn't exist to allow using separately running L1
L1_ADDRESS=$(head -n 1 /geth-accounts/accounts.csv | cut -d ',' -f 2)
L1_PRIV_KEY=$(head -n 1 /geth-accounts/accounts.csv | cut -d ',' -f 3)
# Send balances to the above L2 addresses
yarn hardhat send-balance --to "${ADMIN_ADDRESS}" --amount 2 --private-key "${L1_PRIV_KEY}" --network getting-started
yarn hardhat send-balance --to "${PROPOSER_ADDRESS}" --amount 5 --private-key "${L1_PRIV_KEY}" --network getting-started
yarn hardhat send-balance --to "${BATCHER_ADDRESS}" --amount 1000 --private-key "${L1_PRIV_KEY}" --network getting-started
echo "Balances sent to L2 accounts"
# Select a finalized L1 block as the starting point for roll ups
# TODO Use web3.js to get the latest finalized block
until CAST_OUTPUT=$(cast block finalized --rpc-url "$L1_RPC"); do
echo "Waiting for a finalized L1 block to exist, retrying after 10s"
sleep 10
done
L1_BLOCKHASH=$(echo "$CAST_OUTPUT" | awk '/hash/{print $2}')
L1_BLOCKTIMESTAMP=$(echo "$CAST_OUTPUT" | awk '/timestamp/{print $2}')
# Update the deployment config
sed -i 's/"l2OutputOracleStartingTimestamp": TIMESTAMP/"l2OutputOracleStartingTimestamp": '"$L1_BLOCKTIMESTAMP"'/g' deploy-config/getting-started.json
jq --arg chainid "$CHAIN_ID" '.l1ChainID = ($chainid | tonumber)' deploy-config/getting-started.json > tmp.json && mv tmp.json deploy-config/getting-started.json
node update-config.js deploy-config/getting-started.json "$ADMIN_ADDRESS" "$PROPOSER_ADDRESS" "$BATCHER_ADDRESS" "$SEQUENCER_ADDRESS" "$L1_BLOCKHASH"
echo "Updated the deployment config"
# Create a .env file
echo "L1_RPC=$L1_RPC" > .env
echo "PRIVATE_KEY_DEPLOYER=$ADMIN_PRIV_KEY" >> .env
echo "Deploying the L1 smart contracts, this will take a while..."
# Deploy the L1 smart contracts
yarn hardhat deploy --network getting-started
echo "Deployed the L1 smart contracts"
# Read Proxy contarct's JSON and get the address
PROXY_JSON=$(cat deployments/getting-started/Proxy__OVM_L1StandardBridge.json)
PROXY_ADDRESS=$(echo "$PROXY_JSON" | jq -r '.address')
# Send balance to the above L2 address
yarn hardhat send-balance --to "${PROXY_ADDRESS}" --amount 1 --private-key "${L1_PRIV_KEY}" --network getting-started
echo "Balance sent to Proxy L2 contract"
echo "Use account ${L1_ADDRESS} to deploy contracts to L2"
echo "Done"
@@ -0,0 +1,22 @@
import { task } from 'hardhat/config'
import '@nomiclabs/hardhat-ethers'
import { ethers } from 'ethers'
task('send-balance', 'Sends Ether to a specified Ethereum account')
.addParam('to', 'The Ethereum address to send Ether to')
.addParam('amount', 'The amount of Ether to send, in Ether')
.addParam('privateKey', 'The private key of the sender')
.setAction(async ({ to, amount, privateKey }, {}) => {
// Open the wallet using sender's private key
const provider = new ethers.providers.JsonRpcProvider(`${process.env.L1_RPC}`)
const wallet = new ethers.Wallet(privateKey, provider)
// Send amount to the specified address
const tx = await wallet.sendTransaction({
to,
value: ethers.utils.parseEther(amount),
})
console.log(`Balance sent to: ${to}, from: ${wallet.address}`)
console.log(`Transaction hash: ${tx.hash}`)
})
@@ -0,0 +1,36 @@
const fs = require('fs')
// Get the command-line argument
const configFile = process.argv[2]
const adminAddress = process.argv[3]
const proposerAddress = process.argv[4]
const batcherAddress = process.argv[5]
const sequencerAddress = process.argv[6]
const blockHash = process.argv[7]
// Read the JSON file
const configData = fs.readFileSync(configFile)
const configObj = JSON.parse(configData)
// Update the finalSystemOwner property with the ADMIN_ADDRESS value
configObj.finalSystemOwner =
configObj.portalGuardian =
configObj.controller =
configObj.l2OutputOracleChallenger =
configObj.proxyAdminOwner =
configObj.baseFeeVaultRecipient =
configObj.l1FeeVaultRecipient =
configObj.sequencerFeeVaultRecipient =
configObj.governanceTokenOwner =
adminAddress
configObj.l2OutputOracleProposer = proposerAddress
configObj.batchSenderAddress = batcherAddress
configObj.p2pSequencerAddress = sequencerAddress
configObj.l1StartingBlockTag = blockHash
// Write the updated JSON object back to the file
fs.writeFileSync(configFile, JSON.stringify(configObj, null, 2))
+21
View File
@@ -0,0 +1,21 @@
#!/bin/sh
set -e
# Get BACTHER_KEY from keys.json
BATCHER_KEY=$(jq -r '.Batcher.privateKey' /l2-accounts/keys.json | tr -d '"')
op-batcher \
--l2-eth-rpc=http://op-geth:8545 \
--rollup-rpc=http://op-node: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 \
--target-l1-tx-size-bytes=2048 \
--l1-eth-rpc=$L1_RPC \
--private-key=$BATCHER_KEY
+58
View File
@@ -0,0 +1,58 @@
#!/bin/sh
set -e
mkdir datadir
echo "pwd" > datadir/password
# TODO: Add in container build or use other tool
echo "installing jq"
apk update && apk add jq
# Get SEQUENCER KEY from keys.json
SEQUENCER_KEY=$(jq -r '.Sequencer.privateKey' /l2-accounts/keys.json | tr -d '"')
echo $SEQUENCER_KEY > datadir/block-signer-key
geth account import --datadir=datadir --password=datadir/password datadir/block-signer-key
while [ ! -f "/op-node/jwt.txt" ]
do
echo "Config files not created. Checking after 5 seconds."
sleep 5
done
echo "Config files created by op-node, proceeding with script..."
cp /op-node/genesis.json ./
geth init --datadir=datadir genesis.json
SEQUENCER_ADDRESS=$(jq -r '.Sequencer.address' /l2-accounts/keys.json | tr -d '"')
echo "SEQUENCER_ADDRESS: ${SEQUENCER_ADDRESS}"
cp /op-node/jwt.txt ./
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=full \
--nodiscover \
--maxpeers=0 \
--networkid=42069 \
--authrpc.vhosts="*" \
--authrpc.addr=0.0.0.0 \
--authrpc.port=8551 \
--authrpc.jwtsecret=./jwt.txt \
--rollup.disabletxpoolgossip=true \
--password=./datadir/password \
--allow-insecure-unlock \
--mine \
--miner.etherbase=$SEQUENCER_ADDRESS \
--unlock=$SEQUENCER_ADDRESS
+20
View File
@@ -0,0 +1,20 @@
#!/bin/sh
set -e
# Get SEQUENCER KEY from keys.json
SEQUENCER_KEY=$(jq -r '.Sequencer.privateKey' /l2-accounts/keys.json | tr -d '"')
op-node \
--l2=http://op-geth:8551 \
--l2.jwt-secret=/app/jwt.txt \
--sequencer.enabled \
--sequencer.l1-confs=3 \
--verifier.l1-confs=3 \
--rollup.config=/app/rollup.json \
--rpc.addr=0.0.0.0 \
--rpc.port=8547 \
--p2p.disable \
--rpc.enable-admin \
--p2p.sequencer.key=$SEQUENCER_KEY \
--l1=$L1_RPC \
--l1.rpckind=any