Commit 75055b51 authored by Matthew Slipper's avatar Matthew Slipper Committed by GitHub

Merge pull request #2359 from ethereum-optimism/develop

Develop -> Master
parents 1c858502 0645cd7c
---
'@eth-optimism/replica-healthcheck': patch
---
Fixes a bug in the replica-healthcheck docker file
---
'@eth-optimism/teleportr': patch
---
Add metrics for balances
---
'@eth-optimism/l2geth-exporter': patch
---
Bump to go-ethereum v1.10.16
---
'@eth-optimism/common-ts': patch
---
Properly exposes metrics as part of a metrics server at port 7300
---
'@eth-optimism/integration-tests': patch
---
Add integration test for healthcheck server
---
'@eth-optimism/replica-healthcheck': patch
---
Add checks and metrics for dead networks
---
'@eth-optimism/gas-oracle': patch
---
Allow configurable base fee update poll time with `GAS_PRICE_ORACLE_L1_BASE_FEE_EPOCH_LENGTH_SECONDS`
This diff is collapsed.
...@@ -50,7 +50,7 @@ jobs: ...@@ -50,7 +50,7 @@ jobs:
working-directory: ./ops working-directory: ./ops
run: | run: |
./scripts/stats.sh & ./scripts/stats.sh &
docker-compose -f docker-compose.yml up -d docker-compose -f docker-compose.yml up -d --scale replica-healthcheck=1
- name: Wait for the Sequencer node - name: Wait for the Sequencer node
working-directory: ./ops working-directory: ./ops
...@@ -64,7 +64,6 @@ jobs: ...@@ -64,7 +64,6 @@ jobs:
if: failure() if: failure()
uses: jwalton/gh-docker-logs@v1 uses: jwalton/gh-docker-logs@v1
with: with:
images: 'ethereumoptimism/hardhat,ops_deployer,ops_dtl,ops_l2geth,ethereumoptimism/message-relayer,ops_batch_submitter,ops_replica,ops_integration_tests'
dest: '/home/runner/logs' dest: '/home/runner/logs'
- name: Tar logs - name: Tar logs
......
...@@ -5,7 +5,7 @@ go 1.16 ...@@ -5,7 +5,7 @@ go 1.16
require ( require (
github.com/btcsuite/btcd v0.22.0-beta // indirect github.com/btcsuite/btcd v0.22.0-beta // indirect
github.com/decred/dcrd/hdkeychain/v3 v3.0.0 github.com/decred/dcrd/hdkeychain/v3 v3.0.0
github.com/ethereum/go-ethereum v1.10.12 github.com/ethereum/go-ethereum v1.10.16
github.com/getsentry/sentry-go v0.11.0 github.com/getsentry/sentry-go v0.11.0
github.com/prometheus/client_golang v1.11.0 github.com/prometheus/client_golang v1.11.0
github.com/stretchr/testify v1.7.0 github.com/stretchr/testify v1.7.0
......
...@@ -115,8 +115,8 @@ github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2 ...@@ -115,8 +115,8 @@ github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/deckarep/golang-set v0.0.0-20180603214616-504e848d77ea h1:j4317fAZh7X6GqbFowYdYdI0L9bwxL07jyPZIdepyZ0= github.com/deckarep/golang-set v1.8.0 h1:sk9/l/KqpunDwP7pSjUg0keiOOLEnOBHzykLrsPppp4=
github.com/deckarep/golang-set v0.0.0-20180603214616-504e848d77ea/go.mod h1:93vsz/8Wt4joVM7c2AVqh+YRMiUSc14yDtF28KmMOgQ= github.com/deckarep/golang-set v1.8.0/go.mod h1:5nI87KwE7wgsBU1F4GKAw2Qod7p5kyS383rP6+o6qqo=
github.com/decred/base58 v1.0.3 h1:KGZuh8d1WEMIrK0leQRM47W85KqCAdl2N+uagbctdDI= github.com/decred/base58 v1.0.3 h1:KGZuh8d1WEMIrK0leQRM47W85KqCAdl2N+uagbctdDI=
github.com/decred/base58 v1.0.3/go.mod h1:pXP9cXCfM2sFLb2viz2FNIdeMWmZDBKG3ZBYbiSM78E= github.com/decred/base58 v1.0.3/go.mod h1:pXP9cXCfM2sFLb2viz2FNIdeMWmZDBKG3ZBYbiSM78E=
github.com/decred/dcrd/chaincfg/chainhash v1.0.2 h1:rt5Vlq/jM3ZawwiacWjPa+smINyLRN07EO0cNBV6DGU= github.com/decred/dcrd/chaincfg/chainhash v1.0.2 h1:rt5Vlq/jM3ZawwiacWjPa+smINyLRN07EO0cNBV6DGU=
...@@ -159,8 +159,8 @@ github.com/eknkc/amber v0.0.0-20171010120322-cdade1c07385/go.mod h1:0vRUJqYpeSZi ...@@ -159,8 +159,8 @@ github.com/eknkc/amber v0.0.0-20171010120322-cdade1c07385/go.mod h1:0vRUJqYpeSZi
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/etcd-io/bbolt v1.3.3/go.mod h1:ZF2nL25h33cCyBtcyWeZ2/I3HQOfTP+0PIEvHjkjCrw= github.com/etcd-io/bbolt v1.3.3/go.mod h1:ZF2nL25h33cCyBtcyWeZ2/I3HQOfTP+0PIEvHjkjCrw=
github.com/ethereum/go-ethereum v1.10.12 h1:el/KddB3gLEsnNgGQ3SQuZuiZjwnFTYHe5TwUet5Om4= github.com/ethereum/go-ethereum v1.10.16 h1:3oPrumn0bCW/idjcxMn5YYVCdK7VzJYIvwGZUGLEaoc=
github.com/ethereum/go-ethereum v1.10.12/go.mod h1:W3yfrFyL9C1pHcwY5hmRHVDaorTiQxhYBkKyu5mEDHw= github.com/ethereum/go-ethereum v1.10.16/go.mod h1:Anj6cxczl+AHy63o4X9O8yWNHuN5wMpfb8MAnHkWn7Y=
github.com/fasthttp-contrib/websocket v0.0.0-20160511215533-1f3b11f56072/go.mod h1:duJ4Jxv5lDcvg4QuQr0oowTf7dz4/CR8NtyCooz9HL8= github.com/fasthttp-contrib/websocket v0.0.0-20160511215533-1f3b11f56072/go.mod h1:duJ4Jxv5lDcvg4QuQr0oowTf7dz4/CR8NtyCooz9HL8=
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M=
...@@ -264,7 +264,7 @@ github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB7 ...@@ -264,7 +264,7 @@ github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB7
github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc= github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc=
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/graph-gophers/graphql-go v0.0.0-20201113091052-beb923fada29/go.mod h1:9CQHMSxwO4MprSdzoIEobiHpoLtHm77vfxsvsIN5Vuc= github.com/graph-gophers/graphql-go v1.3.0/go.mod h1:9CQHMSxwO4MprSdzoIEobiHpoLtHm77vfxsvsIN5Vuc=
github.com/hashicorp/go-bexpr v0.1.10 h1:9kuI5PFotCboP3dkDYFr/wi0gg0QVbSNz5oFRpxn4uE= github.com/hashicorp/go-bexpr v0.1.10 h1:9kuI5PFotCboP3dkDYFr/wi0gg0QVbSNz5oFRpxn4uE=
github.com/hashicorp/go-bexpr v0.1.10/go.mod h1:oxlubA2vC/gFVfX1A6JGp7ls7uCDlfJn732ehYYg+g0= github.com/hashicorp/go-bexpr v0.1.10/go.mod h1:oxlubA2vC/gFVfX1A6JGp7ls7uCDlfJn732ehYYg+g0=
github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
...@@ -300,8 +300,8 @@ github.com/iris-contrib/go.uuid v2.0.0+incompatible/go.mod h1:iz2lgM/1UnEf1kP0L/ ...@@ -300,8 +300,8 @@ github.com/iris-contrib/go.uuid v2.0.0+incompatible/go.mod h1:iz2lgM/1UnEf1kP0L/
github.com/iris-contrib/jade v1.1.3/go.mod h1:H/geBymxJhShH5kecoiOCSssPX7QWYH7UaeZTSWddIk= github.com/iris-contrib/jade v1.1.3/go.mod h1:H/geBymxJhShH5kecoiOCSssPX7QWYH7UaeZTSWddIk=
github.com/iris-contrib/pongo2 v0.0.1/go.mod h1:Ssh+00+3GAZqSQb30AvBRNxBx7rf0GqwkjqxNd0u65g= github.com/iris-contrib/pongo2 v0.0.1/go.mod h1:Ssh+00+3GAZqSQb30AvBRNxBx7rf0GqwkjqxNd0u65g=
github.com/iris-contrib/schema v0.0.1/go.mod h1:urYA3uvUNG1TIIjOSCzHr9/LmbQo8LrOcOqfqxa4hXw= github.com/iris-contrib/schema v0.0.1/go.mod h1:urYA3uvUNG1TIIjOSCzHr9/LmbQo8LrOcOqfqxa4hXw=
github.com/jackpal/go-nat-pmp v1.0.2-0.20160603034137-1fa385a6f458 h1:6OvNmYgJyexcZ3pYbTI9jWx5tHo1Dee/tWbLMfPe2TA= github.com/jackpal/go-nat-pmp v1.0.2 h1:KzKSgb7qkJvOUTqYl9/Hg/me3pWgBmERKrTGD7BdWus=
github.com/jackpal/go-nat-pmp v1.0.2-0.20160603034137-1fa385a6f458/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc= github.com/jackpal/go-nat-pmp v1.0.2/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc=
github.com/jedisct1/go-minisign v0.0.0-20190909160543-45766022959e/go.mod h1:G1CVv03EnqU1wYL2dFwXxW2An0az9JTl/ZsqXQeBlkU= github.com/jedisct1/go-minisign v0.0.0-20190909160543-45766022959e/go.mod h1:G1CVv03EnqU1wYL2dFwXxW2An0az9JTl/ZsqXQeBlkU=
github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
...@@ -322,7 +322,7 @@ github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8 ...@@ -322,7 +322,7 @@ github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8
github.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes= github.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes=
github.com/jwilder/encoding v0.0.0-20170811194829-b4e1701a28ef/go.mod h1:Ct9fl0F6iIOGgxJ5npU/IUOhOhqlVrGjyIZc8/MagT0= github.com/jwilder/encoding v0.0.0-20170811194829-b4e1701a28ef/go.mod h1:Ct9fl0F6iIOGgxJ5npU/IUOhOhqlVrGjyIZc8/MagT0=
github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88/go.mod h1:3w7q1U84EfirKl04SVQ/s7nPm1ZPhiXd34z40TNz36k= github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88/go.mod h1:3w7q1U84EfirKl04SVQ/s7nPm1ZPhiXd34z40TNz36k=
github.com/karalabe/usb v0.0.0-20211005121534-4c5740d64559/go.mod h1:Od972xHfMJowv7NGVDiWVxk2zxnWgjLlJzE+F4F7AGU= github.com/karalabe/usb v0.0.2/go.mod h1:Od972xHfMJowv7NGVDiWVxk2zxnWgjLlJzE+F4F7AGU=
github.com/kataras/golog v0.0.10/go.mod h1:yJ8YKCmyL+nWjERB90Qwn+bdyBZsaQwU3bTVFgkFIp8= github.com/kataras/golog v0.0.10/go.mod h1:yJ8YKCmyL+nWjERB90Qwn+bdyBZsaQwU3bTVFgkFIp8=
github.com/kataras/iris/v12 v12.1.8/go.mod h1:LMYy4VlP67TQ3Zgriz8RE2h2kMZV2SgMYbq3UhfoFmE= github.com/kataras/iris/v12 v12.1.8/go.mod h1:LMYy4VlP67TQ3Zgriz8RE2h2kMZV2SgMYbq3UhfoFmE=
github.com/kataras/neffos v0.0.14/go.mod h1:8lqADm8PnbeFfL7CLXh1WHw53dG27MC3pgi2R1rmoTE= github.com/kataras/neffos v0.0.14/go.mod h1:8lqADm8PnbeFfL7CLXh1WHw53dG27MC3pgi2R1rmoTE=
......
...@@ -89,6 +89,12 @@ var ( ...@@ -89,6 +89,12 @@ var (
Usage: "length of epochs in seconds", Usage: "length of epochs in seconds",
EnvVar: "GAS_PRICE_ORACLE_EPOCH_LENGTH_SECONDS", EnvVar: "GAS_PRICE_ORACLE_EPOCH_LENGTH_SECONDS",
} }
L1BaseFeeEpochLengthSecondsFlag = cli.Uint64Flag{
Name: "l1-base-fee-epoch-length-seconds",
Value: 15,
Usage: "polling time for updating the L1 base fee",
EnvVar: "GAS_PRICE_ORACLE_L1_BASE_FEE_EPOCH_LENGTH_SECONDS",
}
L1BaseFeeSignificanceFactorFlag = cli.Float64Flag{ L1BaseFeeSignificanceFactorFlag = cli.Float64Flag{
Name: "l1-base-fee-significant-factor", Name: "l1-base-fee-significant-factor",
Value: 0.10, Value: 0.10,
...@@ -169,6 +175,7 @@ var Flags = []cli.Flag{ ...@@ -169,6 +175,7 @@ var Flags = []cli.Flag{
MaxPercentChangePerEpochFlag, MaxPercentChangePerEpochFlag,
AverageBlockGasLimitPerEpochFlag, AverageBlockGasLimitPerEpochFlag,
EpochLengthSecondsFlag, EpochLengthSecondsFlag,
L1BaseFeeEpochLengthSecondsFlag,
L2GasPriceSignificanceFactorFlag, L2GasPriceSignificanceFactorFlag,
WaitForReceiptFlag, WaitForReceiptFlag,
EnableL1BaseFeeFlag, EnableL1BaseFeeFlag,
......
...@@ -28,6 +28,7 @@ type Config struct { ...@@ -28,6 +28,7 @@ type Config struct {
maxPercentChangePerEpoch float64 maxPercentChangePerEpoch float64
averageBlockGasLimitPerEpoch uint64 averageBlockGasLimitPerEpoch uint64
epochLengthSeconds uint64 epochLengthSeconds uint64
l1BaseFeeEpochLengthSeconds uint64
l2GasPriceSignificanceFactor float64 l2GasPriceSignificanceFactor float64
l1BaseFeeSignificanceFactor float64 l1BaseFeeSignificanceFactor float64
enableL1BaseFee bool enableL1BaseFee bool
...@@ -54,6 +55,7 @@ func NewConfig(ctx *cli.Context) *Config { ...@@ -54,6 +55,7 @@ func NewConfig(ctx *cli.Context) *Config {
cfg.maxPercentChangePerEpoch = ctx.GlobalFloat64(flags.MaxPercentChangePerEpochFlag.Name) cfg.maxPercentChangePerEpoch = ctx.GlobalFloat64(flags.MaxPercentChangePerEpochFlag.Name)
cfg.averageBlockGasLimitPerEpoch = ctx.GlobalUint64(flags.AverageBlockGasLimitPerEpochFlag.Name) cfg.averageBlockGasLimitPerEpoch = ctx.GlobalUint64(flags.AverageBlockGasLimitPerEpochFlag.Name)
cfg.epochLengthSeconds = ctx.GlobalUint64(flags.EpochLengthSecondsFlag.Name) cfg.epochLengthSeconds = ctx.GlobalUint64(flags.EpochLengthSecondsFlag.Name)
cfg.l1BaseFeeEpochLengthSeconds = ctx.GlobalUint64(flags.L1BaseFeeEpochLengthSecondsFlag.Name)
cfg.l2GasPriceSignificanceFactor = ctx.GlobalFloat64(flags.L2GasPriceSignificanceFactorFlag.Name) cfg.l2GasPriceSignificanceFactor = ctx.GlobalFloat64(flags.L2GasPriceSignificanceFactorFlag.Name)
cfg.floorPrice = ctx.GlobalUint64(flags.FloorPriceFlag.Name) cfg.floorPrice = ctx.GlobalUint64(flags.FloorPriceFlag.Name)
cfg.l1BaseFeeSignificanceFactor = ctx.GlobalFloat64(flags.L1BaseFeeSignificanceFactorFlag.Name) cfg.l1BaseFeeSignificanceFactor = ctx.GlobalFloat64(flags.L1BaseFeeSignificanceFactorFlag.Name)
......
...@@ -111,6 +111,7 @@ func (g *GasPriceOracle) ensure() error { ...@@ -111,6 +111,7 @@ func (g *GasPriceOracle) ensure() error {
func (g *GasPriceOracle) Loop() { func (g *GasPriceOracle) Loop() {
timer := time.NewTicker(time.Duration(g.config.epochLengthSeconds) * time.Second) timer := time.NewTicker(time.Duration(g.config.epochLengthSeconds) * time.Second)
defer timer.Stop() defer timer.Stop()
for { for {
select { select {
case <-timer.C: case <-timer.C:
...@@ -126,7 +127,7 @@ func (g *GasPriceOracle) Loop() { ...@@ -126,7 +127,7 @@ func (g *GasPriceOracle) Loop() {
} }
func (g *GasPriceOracle) BaseFeeLoop() { func (g *GasPriceOracle) BaseFeeLoop() {
timer := time.NewTicker(15 * time.Second) timer := time.NewTicker(time.Duration(g.config.l1BaseFeeEpochLengthSeconds) * time.Second)
defer timer.Stop() defer timer.Stop()
updateBaseFee, err := wrapUpdateBaseFee(g.l1Backend, g.l2Backend, g.config) updateBaseFee, err := wrapUpdateBaseFee(g.l1Backend, g.l2Backend, g.config)
......
This diff is collapsed.
...@@ -2,12 +2,13 @@ package metrics ...@@ -2,12 +2,13 @@ package metrics
import ( import (
"fmt" "fmt"
"net/http"
l2common "github.com/ethereum-optimism/optimism/l2geth/common" l2common "github.com/ethereum-optimism/optimism/l2geth/common"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promauto" "github.com/prometheus/client_golang/prometheus/promauto"
"github.com/prometheus/client_golang/prometheus/promhttp" "github.com/prometheus/client_golang/prometheus/promhttp"
"net/http"
) )
const metricsNamespace = "indexer" const metricsNamespace = "indexer"
......
...@@ -2,6 +2,7 @@ package bridge ...@@ -2,6 +2,7 @@ package bridge
import ( import (
"fmt" "fmt"
"github.com/ethereum-optimism/optimism/go/indexer/bindings/address_manager" "github.com/ethereum-optimism/optimism/go/indexer/bindings/address_manager"
"github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
......
...@@ -2,6 +2,7 @@ package bridge ...@@ -2,6 +2,7 @@ package bridge
import ( import (
"context" "context"
"github.com/ethereum-optimism/optimism/go/indexer/bindings/l1bridge" "github.com/ethereum-optimism/optimism/go/indexer/bindings/l1bridge"
"github.com/ethereum-optimism/optimism/go/indexer/db" "github.com/ethereum-optimism/optimism/go/indexer/db"
"github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/accounts/abi/bind"
......
...@@ -2,6 +2,7 @@ package l1 ...@@ -2,6 +2,7 @@ package l1
import ( import (
"context" "context"
"github.com/ethereum-optimism/optimism/go/indexer/bindings/l1erc20" "github.com/ethereum-optimism/optimism/go/indexer/bindings/l1erc20"
"github.com/ethereum/go-ethereum/ethclient" "github.com/ethereum/go-ethereum/ethclient"
...@@ -40,7 +41,6 @@ func QueryERC20(address common.Address, client *ethclient.Client) (*db.Token, er ...@@ -40,7 +41,6 @@ func QueryERC20(address common.Address, client *ethclient.Client) (*db.Token, er
}, nil }, nil
} }
func QueryStateBatches(filterer *scc.StateCommitmentChainFilterer, startHeight, endHeight uint64, ctx context.Context) (map[common.Hash][]db.StateBatch, error) { func QueryStateBatches(filterer *scc.StateCommitmentChainFilterer, startHeight, endHeight uint64, ctx context.Context) (map[common.Hash][]db.StateBatch, error) {
batches := make(map[common.Hash][]db.StateBatch) batches := make(map[common.Hash][]db.StateBatch)
......
...@@ -3,6 +3,6 @@ module github.com/ethereum-optimism/optimism/go/l2geth-exporter ...@@ -3,6 +3,6 @@ module github.com/ethereum-optimism/optimism/go/l2geth-exporter
go 1.16 go 1.16
require ( require (
github.com/ethereum/go-ethereum v1.10.8 github.com/ethereum/go-ethereum v1.10.16
github.com/prometheus/client_golang v1.11.0 github.com/prometheus/client_golang v1.11.0
) )
This diff is collapsed.
...@@ -255,7 +255,7 @@ func (b *Backend) ProxyWS(clientConn *websocket.Conn, methodWhitelist *StringSet ...@@ -255,7 +255,7 @@ func (b *Backend) ProxyWS(clientConn *websocket.Conn, methodWhitelist *StringSet
return nil, ErrBackendOverCapacity return nil, ErrBackendOverCapacity
} }
backendConn, _, err := b.dialer.Dial(b.wsURL, nil) backendConn, _, err := b.dialer.Dial(b.wsURL, nil) // nolint:bodyclose
if err != nil { if err != nil {
b.setOffline() b.setOffline()
if err := b.rateLimiter.DecBackendWSConns(b.Name); err != nil { if err := b.rateLimiter.DecBackendWSConns(b.Name); err != nil {
...@@ -513,7 +513,9 @@ func (w *WSProxier) clientPump(ctx context.Context, errC chan error) { ...@@ -513,7 +513,9 @@ func (w *WSProxier) clientPump(ctx context.Context, errC chan error) {
msgType, msg, err := w.clientConn.ReadMessage() msgType, msg, err := w.clientConn.ReadMessage()
if err != nil { if err != nil {
errC <- err errC <- err
outConn.WriteMessage(websocket.CloseMessage, formatWSError(err)) if err := outConn.WriteMessage(websocket.CloseMessage, formatWSError(err)); err != nil {
log.Error("error writing backendConn message", "err", err)
}
return return
} }
...@@ -575,7 +577,9 @@ func (w *WSProxier) backendPump(ctx context.Context, errC chan error) { ...@@ -575,7 +577,9 @@ func (w *WSProxier) backendPump(ctx context.Context, errC chan error) {
msgType, msg, err := w.backendConn.ReadMessage() msgType, msg, err := w.backendConn.ReadMessage()
if err != nil { if err != nil {
errC <- err errC <- err
w.clientConn.WriteMessage(websocket.CloseMessage, formatWSError(err)) if err := w.clientConn.WriteMessage(websocket.CloseMessage, formatWSError(err)); err != nil {
log.Error("error writing clientConn message", "err", err)
}
return return
} }
......
...@@ -3,12 +3,13 @@ package integration_tests ...@@ -3,12 +3,13 @@ package integration_tests
import ( import (
"bytes" "bytes"
"fmt" "fmt"
"github.com/alicebob/miniredis"
"github.com/ethereum-optimism/optimism/go/proxyd"
"github.com/stretchr/testify/require"
"os" "os"
"testing" "testing"
"time" "time"
"github.com/alicebob/miniredis"
"github.com/ethereum-optimism/optimism/go/proxyd"
"github.com/stretchr/testify/require"
) )
func TestCaching(t *testing.T) { func TestCaching(t *testing.T) {
......
...@@ -2,13 +2,14 @@ package integration_tests ...@@ -2,13 +2,14 @@ package integration_tests
import ( import (
"fmt" "fmt"
"github.com/ethereum-optimism/optimism/go/proxyd"
"github.com/stretchr/testify/require"
"net/http" "net/http"
"os" "os"
"sync/atomic" "sync/atomic"
"testing" "testing"
"time" "time"
"github.com/ethereum-optimism/optimism/go/proxyd"
"github.com/stretchr/testify/require"
) )
const ( const (
...@@ -39,7 +40,7 @@ func TestFailover(t *testing.T) { ...@@ -39,7 +40,7 @@ func TestFailover(t *testing.T) {
"backend responds 200 with non-JSON response", "backend responds 200 with non-JSON response",
http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(200) w.WriteHeader(200)
w.Write([]byte("this data is not JSON!")) _, _ = w.Write([]byte("this data is not JSON!"))
}), }),
}, },
{ {
...@@ -87,7 +88,7 @@ func TestFailover(t *testing.T) { ...@@ -87,7 +88,7 @@ func TestFailover(t *testing.T) {
t.Run("backend times out and falls back to another", func(t *testing.T) { t.Run("backend times out and falls back to another", func(t *testing.T) {
badBackend.SetHandler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { badBackend.SetHandler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
time.Sleep(2 * time.Second) time.Sleep(2 * time.Second)
w.Write([]byte("{}")) _, _ = w.Write([]byte("{}"))
})) }))
res, statusCode, err := client.SendRPC("eth_chainId", nil) res, statusCode, err := client.SendRPC("eth_chainId", nil)
require.NoError(t, err) require.NoError(t, err)
...@@ -133,7 +134,7 @@ func TestRetries(t *testing.T) { ...@@ -133,7 +134,7 @@ func TestRetries(t *testing.T) {
w.WriteHeader(500) w.WriteHeader(500)
return return
} }
w.Write([]byte(goodResponse)) _, _ = w.Write([]byte(goodResponse))
})) }))
// test case where request eventually succeeds // test case where request eventually succeeds
...@@ -169,7 +170,7 @@ func TestOutOfServiceInterval(t *testing.T) { ...@@ -169,7 +170,7 @@ func TestOutOfServiceInterval(t *testing.T) {
defer shutdown() defer shutdown()
okHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { okHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte(goodResponse)) _, _ = w.Write([]byte(goodResponse))
}) })
badBackend.SetHandler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { badBackend.SetHandler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(503) w.WriteHeader(503)
...@@ -190,10 +191,12 @@ func TestOutOfServiceInterval(t *testing.T) { ...@@ -190,10 +191,12 @@ func TestOutOfServiceInterval(t *testing.T) {
require.Equal(t, 2, len(badBackend.Requests())) require.Equal(t, 2, len(badBackend.Requests()))
require.Equal(t, 2, len(goodBackend.Requests())) require.Equal(t, 2, len(goodBackend.Requests()))
res, statusCode, err = client.SendBatchRPC( _, statusCode, err = client.SendBatchRPC(
NewRPCReq("1", "eth_chainId", nil), NewRPCReq("1", "eth_chainId", nil),
NewRPCReq("1", "eth_chainId", nil), NewRPCReq("1", "eth_chainId", nil),
) )
require.NoError(t, err)
require.Equal(t, 200, statusCode)
require.Equal(t, 2, len(badBackend.Requests())) require.Equal(t, 2, len(badBackend.Requests()))
require.Equal(t, 4, len(goodBackend.Requests())) require.Equal(t, 4, len(goodBackend.Requests()))
......
...@@ -4,11 +4,12 @@ import ( ...@@ -4,11 +4,12 @@ import (
"bytes" "bytes"
"context" "context"
"encoding/json" "encoding/json"
"github.com/ethereum-optimism/optimism/go/proxyd"
"io/ioutil" "io/ioutil"
"net/http" "net/http"
"net/http/httptest" "net/http/httptest"
"sync" "sync"
"github.com/ethereum-optimism/optimism/go/proxyd"
) )
type RecordedRequest struct { type RecordedRequest struct {
...@@ -27,7 +28,7 @@ type MockBackend struct { ...@@ -27,7 +28,7 @@ type MockBackend struct {
func SingleResponseHandler(code int, response string) http.HandlerFunc { func SingleResponseHandler(code int, response string) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(code) w.WriteHeader(code)
w.Write([]byte(response)) _, _ = w.Write([]byte(response))
} }
} }
......
package integration_tests package integration_tests
import ( import (
"github.com/ethereum-optimism/optimism/go/proxyd"
"github.com/stretchr/testify/require"
"os" "os"
"testing" "testing"
"github.com/ethereum-optimism/optimism/go/proxyd"
"github.com/stretchr/testify/require"
) )
type resWithCode struct { type resWithCode struct {
......
...@@ -4,12 +4,13 @@ import ( ...@@ -4,12 +4,13 @@ import (
"bytes" "bytes"
"encoding/json" "encoding/json"
"fmt" "fmt"
"github.com/BurntSushi/toml"
"github.com/ethereum-optimism/optimism/go/proxyd"
"github.com/stretchr/testify/require"
"io/ioutil" "io/ioutil"
"net/http" "net/http"
"testing" "testing"
"github.com/BurntSushi/toml"
"github.com/ethereum-optimism/optimism/go/proxyd"
"github.com/stretchr/testify/require"
) )
type ProxydClient struct { type ProxydClient struct {
......
package integration_tests package integration_tests
import ( import (
"github.com/ethereum-optimism/optimism/go/proxyd"
"github.com/stretchr/testify/require"
"os" "os"
"strings" "strings"
"testing" "testing"
"github.com/ethereum-optimism/optimism/go/proxyd"
"github.com/stretchr/testify/require"
) )
const ( const (
......
...@@ -217,7 +217,11 @@ func Start(config *Config) (func(), error) { ...@@ -217,7 +217,11 @@ func Start(config *Config) (func(), error) {
if config.Metrics.Enabled { if config.Metrics.Enabled {
addr := fmt.Sprintf("%s:%d", config.Metrics.Host, config.Metrics.Port) addr := fmt.Sprintf("%s:%d", config.Metrics.Host, config.Metrics.Port)
log.Info("starting metrics server", "addr", addr) log.Info("starting metrics server", "addr", addr)
go http.ListenAndServe(addr, promhttp.Handler()) go func() {
if err := http.ListenAndServe(addr, promhttp.Handler()); err != nil {
log.Error("error starting metrics server", "err", err)
}
}()
} }
// To allow integration tests to cleanly come up, wait // To allow integration tests to cleanly come up, wait
......
...@@ -5,10 +5,11 @@ import ( ...@@ -5,10 +5,11 @@ import (
"crypto/rand" "crypto/rand"
"encoding/hex" "encoding/hex"
"fmt" "fmt"
"github.com/ethereum/go-ethereum/log"
"github.com/go-redis/redis/v8"
"sync" "sync"
"time" "time"
"github.com/ethereum/go-ethereum/log"
"github.com/go-redis/redis/v8"
) )
const MaxRPSScript = ` const MaxRPSScript = `
......
...@@ -2,8 +2,9 @@ package proxyd ...@@ -2,8 +2,9 @@ package proxyd
import ( import (
"encoding/json" "encoding/json"
"github.com/stretchr/testify/require"
"testing" "testing"
"github.com/stretchr/testify/require"
) )
func TestRPCResJSON(t *testing.T) { func TestRPCResJSON(t *testing.T) {
......
...@@ -107,15 +107,15 @@ func (s *Server) WSListenAndServe(host string, port int) error { ...@@ -107,15 +107,15 @@ func (s *Server) WSListenAndServe(host string, port int) error {
func (s *Server) Shutdown() { func (s *Server) Shutdown() {
if s.rpcServer != nil { if s.rpcServer != nil {
s.rpcServer.Shutdown(context.Background()) _ = s.rpcServer.Shutdown(context.Background())
} }
if s.wsServer != nil { if s.wsServer != nil {
s.wsServer.Shutdown(context.Background()) _ = s.wsServer.Shutdown(context.Background())
} }
} }
func (s *Server) HandleHealthz(w http.ResponseWriter, r *http.Request) { func (s *Server) HandleHealthz(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("OK")) _, _ = w.Write([]byte("OK"))
} }
func (s *Server) HandleRPC(w http.ResponseWriter, r *http.Request) { func (s *Server) HandleRPC(w http.ResponseWriter, r *http.Request) {
...@@ -159,7 +159,7 @@ func (s *Server) HandleRPC(w http.ResponseWriter, r *http.Request) { ...@@ -159,7 +159,7 @@ func (s *Server) HandleRPC(w http.ResponseWriter, r *http.Request) {
return return
} }
batchRes := make([]*RPCRes, len(reqs), len(reqs)) batchRes := make([]*RPCRes, len(reqs))
var batchContainsCached bool var batchContainsCached bool
for i := 0; i < len(reqs); i++ { for i := 0; i < len(reqs); i++ {
req, err := ParseRPCReq(reqs[i]) req, err := ParseRPCReq(reqs[i])
...@@ -301,7 +301,7 @@ func (s *Server) populateContext(w http.ResponseWriter, r *http.Request) context ...@@ -301,7 +301,7 @@ func (s *Server) populateContext(w http.ResponseWriter, r *http.Request) context
} }
return context.WithValue( return context.WithValue(
r.Context(), r.Context(),
ContextKeyReqID, ContextKeyReqID, // nolint:staticcheck
randStr(10), randStr(10),
) )
} }
...@@ -321,11 +321,11 @@ func (s *Server) populateContext(w http.ResponseWriter, r *http.Request) context ...@@ -321,11 +321,11 @@ func (s *Server) populateContext(w http.ResponseWriter, r *http.Request) context
} }
} }
ctx := context.WithValue(r.Context(), ContextKeyAuth, s.authenticatedPaths[authorization]) ctx := context.WithValue(r.Context(), ContextKeyAuth, s.authenticatedPaths[authorization]) // nolint:staticcheck
ctx = context.WithValue(ctx, ContextKeyXForwardedFor, xff) ctx = context.WithValue(ctx, ContextKeyXForwardedFor, xff) // nolint:staticcheck
return context.WithValue( return context.WithValue(
ctx, ctx,
ContextKeyReqID, ContextKeyReqID, // nolint:staticcheck
randStr(10), randStr(10),
) )
} }
...@@ -413,17 +413,6 @@ func GetXForwardedFor(ctx context.Context) string { ...@@ -413,17 +413,6 @@ func GetXForwardedFor(ctx context.Context) string {
return xff return xff
} }
type recordLenReader struct {
io.Reader
Len int
}
func (r *recordLenReader) Read(p []byte) (n int, err error) {
n, err = r.Reader.Read(p)
r.Len += n
return
}
type recordLenWriter struct { type recordLenWriter struct {
io.Writer io.Writer
Len int Len int
......
...@@ -142,15 +142,15 @@ func NewConfig(ctx *cli.Context) (Config, error) { ...@@ -142,15 +142,15 @@ func NewConfig(ctx *cli.Context) (Config, error) {
return Config{ return Config{
Hostname: ctx.GlobalString(flags.APIHostnameFlag.Name), Hostname: ctx.GlobalString(flags.APIHostnameFlag.Name),
Port: uint16(ctx.GlobalUint64(flags.APIPortFlag.Name)), Port: uint16(ctx.GlobalUint64(flags.APIPortFlag.Name)),
L1EthRpc: ctx.GlobalString(flags.APIL1EthRpcFlag.Name), L1EthRpc: ctx.GlobalString(flags.L1EthRpcFlag.Name),
DepositAddress: ctx.GlobalString(flags.APIDepositAddressFlag.Name), DepositAddress: ctx.GlobalString(flags.DepositAddressFlag.Name),
NumConfirmations: ctx.GlobalUint64(flags.APINumConfirmationsFlag.Name), NumConfirmations: ctx.GlobalUint64(flags.NumDepositConfirmationsFlag.Name),
PostgresHost: ctx.GlobalString(flags.APIPostgresHostFlag.Name), PostgresHost: ctx.GlobalString(flags.PostgresHostFlag.Name),
PostgresPort: uint16(ctx.GlobalUint64(flags.APIPostgresPortFlag.Name)), PostgresPort: uint16(ctx.GlobalUint64(flags.PostgresPortFlag.Name)),
PostgresUser: ctx.GlobalString(flags.APIPostgresUserFlag.Name), PostgresUser: ctx.GlobalString(flags.PostgresUserFlag.Name),
PostgresPassword: ctx.GlobalString(flags.APIPostgresPasswordFlag.Name), PostgresPassword: ctx.GlobalString(flags.PostgresPasswordFlag.Name),
PostgresDBName: ctx.GlobalString(flags.APIPostgresDBNameFlag.Name), PostgresDBName: ctx.GlobalString(flags.PostgresDBNameFlag.Name),
PostgresEnableSSL: ctx.GlobalBool(flags.APIPostgresEnableSSLFlag.Name), PostgresEnableSSL: ctx.GlobalBool(flags.PostgresEnableSSLFlag.Name),
}, nil }, nil
} }
......
...@@ -33,6 +33,13 @@ func main() { ...@@ -33,6 +33,13 @@ func main() {
app.Name = "teleportr" app.Name = "teleportr"
app.Usage = "Teleportr" app.Usage = "Teleportr"
app.Description = "Teleportr bridge from L1 to L2" app.Description = "Teleportr bridge from L1 to L2"
app.Commands = []cli.Command{
{
Name: "migrate",
Usage: "Migrates teleportr's database",
Action: teleportr.Migrate(),
},
}
app.Action = teleportr.Main(GitVersion) app.Action = teleportr.Main(GitVersion)
err := app.Run(os.Args) err := app.Run(os.Args)
......
...@@ -390,7 +390,8 @@ dep.txn_hash, dep.block_number, dep.block_timestamp, ...@@ -390,7 +390,8 @@ dep.txn_hash, dep.block_number, dep.block_timestamp,
dis.txn_hash, dis.block_number, dis.block_timestamp dis.txn_hash, dis.block_number, dis.block_timestamp
FROM deposits AS dep FROM deposits AS dep
LEFT JOIN disbursements AS dis LEFT JOIN disbursements AS dis
ON dep.id = dis.id AND dep.txn_hash = $1 ON dep.id = dis.id
WHERE dep.txn_hash = $1
LIMIT 1 LIMIT 1
` `
...@@ -416,7 +417,8 @@ dep.txn_hash, dep.block_number, dep.block_timestamp, ...@@ -416,7 +417,8 @@ dep.txn_hash, dep.block_number, dep.block_timestamp,
dis.txn_hash, dis.block_number, dis.block_timestamp dis.txn_hash, dis.block_number, dis.block_timestamp
FROM deposits AS dep FROM deposits AS dep
LEFT JOIN disbursements AS dis LEFT JOIN disbursements AS dis
ON dep.id = dis.id AND dep.address = $1 ON dep.id = dis.id
WHERE dep.address = $1
ORDER BY dep.block_timestamp DESC, dep.id DESC ORDER BY dep.block_timestamp DESC, dep.id DESC
LIMIT 100 LIMIT 100
` `
......
...@@ -139,6 +139,9 @@ func (d *Driver) ClearPendingTx( ...@@ -139,6 +139,9 @@ func (d *Driver) ClearPendingTx(
func (d *Driver) GetBatchBlockRange( func (d *Driver) GetBatchBlockRange(
ctx context.Context) (*big.Int, *big.Int, error) { ctx context.Context) (*big.Int, *big.Int, error) {
// Update balance metrics on each iteration.
d.updateBalanceMetrics(ctx)
// Clear the current deposit IDs from any prior iteration. // Clear the current deposit IDs from any prior iteration.
d.currentDepositIDs = nil d.currentDepositIDs = nil
...@@ -234,6 +237,7 @@ func (d *Driver) CraftBatchTx( ...@@ -234,6 +237,7 @@ func (d *Driver) CraftBatchTx(
var disbursements []disburse.TeleportrDisburserDisbursement var disbursements []disburse.TeleportrDisburserDisbursement
var depositIDs []uint64 var depositIDs []uint64
value := new(big.Int)
for _, deposit := range confirmedDeposits { for _, deposit := range confirmedDeposits {
disbursement := disburse.TeleportrDisburserDisbursement{ disbursement := disburse.TeleportrDisburserDisbursement{
Amount: deposit.Amount, Amount: deposit.Amount,
...@@ -241,6 +245,7 @@ func (d *Driver) CraftBatchTx( ...@@ -241,6 +245,7 @@ func (d *Driver) CraftBatchTx(
} }
disbursements = append(disbursements, disbursement) disbursements = append(disbursements, disbursement)
depositIDs = append(depositIDs, deposit.ID) depositIDs = append(depositIDs, deposit.ID)
value = value.Add(value, deposit.Amount)
} }
log.Info(name+" crafting batch tx", "start", start, "end", end, log.Info(name+" crafting batch tx", "start", start, "end", end,
...@@ -250,7 +255,7 @@ func (d *Driver) CraftBatchTx( ...@@ -250,7 +255,7 @@ func (d *Driver) CraftBatchTx(
log.Info(name+" batch constructed", "num_disbursements", len(disbursements)) log.Info(name+" batch constructed", "num_disbursements", len(disbursements))
gasPrice, err := d.cfg.L1Client.SuggestGasPrice(ctx) gasPrice, err := d.cfg.L2Client.SuggestGasPrice(ctx)
if err != nil { if err != nil {
return nil, err return nil, err
} }
...@@ -265,6 +270,7 @@ func (d *Driver) CraftBatchTx( ...@@ -265,6 +270,7 @@ func (d *Driver) CraftBatchTx(
opts.Nonce = nonce opts.Nonce = nonce
opts.GasPrice = gasPrice opts.GasPrice = gasPrice
opts.NoSend = true opts.NoSend = true
opts.Value = value
tx, err := d.disburserContract.Disburse(opts, start, disbursements) tx, err := d.disburserContract.Disburse(opts, start, disbursements)
if err != nil { if err != nil {
...@@ -299,6 +305,7 @@ func (d *Driver) UpdateGasPrice( ...@@ -299,6 +305,7 @@ func (d *Driver) UpdateGasPrice(
opts.Context = ctx opts.Context = ctx
opts.Nonce = new(big.Int).SetUint64(tx.Nonce()) opts.Nonce = new(big.Int).SetUint64(tx.Nonce())
opts.GasPrice = gasPrice opts.GasPrice = gasPrice
opts.Value = tx.Value()
opts.NoSend = true opts.NoSend = true
return d.rawDisburserContract.RawTransact(opts, tx.Data()) return d.rawDisburserContract.RawTransact(opts, tx.Data())
...@@ -313,7 +320,7 @@ func (d *Driver) SendTransaction( ...@@ -313,7 +320,7 @@ func (d *Driver) SendTransaction(
txHash := tx.Hash() txHash := tx.Hash()
startID := d.currentDepositIDs[0] startID := d.currentDepositIDs[0]
endID := d.currentDepositIDs[len(d.currentDepositIDs)] + 1 endID := d.currentDepositIDs[len(d.currentDepositIDs)-1] + 1
// Record the pending transaction hash so that we can recover if we crash // Record the pending transaction hash so that we can recover if we crash
// after publishing. // after publishing.
...@@ -426,10 +433,10 @@ func (d *Driver) processPendingTxs(ctx context.Context) error { ...@@ -426,10 +433,10 @@ func (d *Driver) processPendingTxs(ctx context.Context) error {
"blockTimestamp", blockTimestamp) "blockTimestamp", blockTimestamp)
} }
d.metrics.SuccessfulDisbursements.Set(float64(successfulDisbursements)) d.metrics.SuccessfulDisbursements.Add(float64(successfulDisbursements))
d.metrics.FailedDisbursements.Set(float64(failedDisbursements)) d.metrics.FailedDisbursements.Add(float64(failedDisbursements))
d.metrics.FailedDatabaseMethods.With(DBMethodUpsertDisbursement). d.metrics.FailedDatabaseMethods.With(DBMethodUpsertDisbursement).
Set(float64(failedUpserts)) Inc()
// We have completed our post-processing once all of the disbursements are // We have completed our post-processing once all of the disbursements are
// written without failures. // written without failures.
...@@ -616,7 +623,7 @@ func (d *Driver) logDatabaseContractMismatch( ...@@ -616,7 +623,7 @@ func (d *Driver) logDatabaseContractMismatch(
log.Warn("Recorded disbursements behind contract", log.Warn("Recorded disbursements behind contract",
"last_disbursement_id", *lastDisbursementID, "last_disbursement_id", *lastDisbursementID,
"contract_next_id", contractNextID) "contract_next_id", contractNextID)
d.metrics.DepositIDMismatch.Set(1.0) d.metrics.DepositIDMismatch.Inc()
// The last recorded disbursement is ahead of what the contract believes. // The last recorded disbursement is ahead of what the contract believes.
// This should NEVER happen unless the sequencer blows up and loses // This should NEVER happen unless the sequencer blows up and loses
...@@ -639,7 +646,7 @@ func (d *Driver) logDatabaseContractMismatch( ...@@ -639,7 +646,7 @@ func (d *Driver) logDatabaseContractMismatch(
log.Warn("Recorded disbursements behind contract", log.Warn("Recorded disbursements behind contract",
"last_disbursement_id", nil, "last_disbursement_id", nil,
"contract_next_id", contractNextID) "contract_next_id", contractNextID)
d.metrics.DepositIDMismatch.Set(1.0) d.metrics.DepositIDMismatch.Inc()
// Database and contract indicate we have not done a disbursement. // Database and contract indicate we have not done a disbursement.
default: default:
...@@ -650,10 +657,9 @@ func (d *Driver) logDatabaseContractMismatch( ...@@ -650,10 +657,9 @@ func (d *Driver) logDatabaseContractMismatch(
func (d *Driver) upsertDeposits(deposits []db.Deposit, end uint64) error { func (d *Driver) upsertDeposits(deposits []db.Deposit, end uint64) error {
err := d.cfg.Database.UpsertDeposits(deposits, end) err := d.cfg.Database.UpsertDeposits(deposits, end)
if err != nil { if err != nil {
d.metrics.FailedDatabaseMethods.With(DBMethodUpsertDeposits).Set(1.0) d.metrics.FailedDatabaseMethods.With(DBMethodUpsertDeposits).Inc()
return err return err
} }
d.metrics.FailedDatabaseMethods.With(DBMethodUpsertDeposits).Set(0.0)
return nil return nil
} }
...@@ -662,59 +668,70 @@ func (d *Driver) confirmedDeposits(blockNumber uint64) ([]db.Deposit, error) { ...@@ -662,59 +668,70 @@ func (d *Driver) confirmedDeposits(blockNumber uint64) ([]db.Deposit, error) {
blockNumber, d.cfg.NumConfirmations, blockNumber, d.cfg.NumConfirmations,
) )
if err != nil { if err != nil {
d.metrics.FailedDatabaseMethods.With(DBMethodConfirmedDeposits).Set(1.0) d.metrics.FailedDatabaseMethods.With(DBMethodConfirmedDeposits).Inc()
return nil, err return nil, err
} }
d.metrics.FailedDatabaseMethods.With(DBMethodConfirmedDeposits).Set(0.0)
return confirmedDeposits, nil return confirmedDeposits, nil
} }
func (d *Driver) lastProcessedBlock() (*uint64, error) { func (d *Driver) lastProcessedBlock() (*uint64, error) {
lastProcessedBlock, err := d.cfg.Database.LastProcessedBlock() lastProcessedBlock, err := d.cfg.Database.LastProcessedBlock()
if err != nil { if err != nil {
d.metrics.FailedDatabaseMethods.With(DBMethodLastProcessedBlock).Set(1.0) d.metrics.FailedDatabaseMethods.With(DBMethodLastProcessedBlock).Inc()
return nil, err return nil, err
} }
d.metrics.FailedDatabaseMethods.With(DBMethodLastProcessedBlock).Set(0.0)
return lastProcessedBlock, nil return lastProcessedBlock, nil
} }
func (d *Driver) upsertPendingTx(pendingTx db.PendingTx) error { func (d *Driver) upsertPendingTx(pendingTx db.PendingTx) error {
err := d.cfg.Database.UpsertPendingTx(pendingTx) err := d.cfg.Database.UpsertPendingTx(pendingTx)
if err != nil { if err != nil {
d.metrics.FailedDatabaseMethods.With(DBMethodUpsertPendingTx).Set(1.0) d.metrics.FailedDatabaseMethods.With(DBMethodUpsertPendingTx).Inc()
return err return err
} }
d.metrics.FailedDatabaseMethods.With(DBMethodUpsertPendingTx).Set(0.0)
return nil return nil
} }
func (d *Driver) listPendingTxs() ([]db.PendingTx, error) { func (d *Driver) listPendingTxs() ([]db.PendingTx, error) {
pendingTxs, err := d.cfg.Database.ListPendingTxs() pendingTxs, err := d.cfg.Database.ListPendingTxs()
if err != nil { if err != nil {
d.metrics.FailedDatabaseMethods.With(DBMethodListPendingTxs).Set(1.0) d.metrics.FailedDatabaseMethods.With(DBMethodListPendingTxs).Inc()
return nil, err return nil, err
} }
d.metrics.FailedDatabaseMethods.With(DBMethodListPendingTxs).Set(0.0)
return pendingTxs, nil return pendingTxs, nil
} }
func (d *Driver) latestDisbursementID() (*uint64, error) { func (d *Driver) latestDisbursementID() (*uint64, error) {
lastDisbursementID, err := d.cfg.Database.LatestDisbursementID() lastDisbursementID, err := d.cfg.Database.LatestDisbursementID()
if err != nil { if err != nil {
d.metrics.FailedDatabaseMethods.With(DBMethodLatestDisbursementID).Set(1.0) d.metrics.FailedDatabaseMethods.With(DBMethodLatestDisbursementID).Inc()
return nil, err return nil, err
} }
d.metrics.FailedDatabaseMethods.With(DBMethodLatestDisbursementID).Set(0.0)
return lastDisbursementID, nil return lastDisbursementID, nil
} }
func (d *Driver) deletePendingTx(startID, endID uint64) error { func (d *Driver) deletePendingTx(startID, endID uint64) error {
err := d.cfg.Database.DeletePendingTx(startID, endID) err := d.cfg.Database.DeletePendingTx(startID, endID)
if err != nil { if err != nil {
d.metrics.FailedDatabaseMethods.With(DBMethodDeletePendingTx).Set(1.0) d.metrics.FailedDatabaseMethods.With(DBMethodDeletePendingTx).Inc()
return err return err
} }
d.metrics.FailedDatabaseMethods.With(DBMethodDeletePendingTx).Set(0.0)
return nil return nil
} }
func (d *Driver) updateBalanceMetrics(ctx context.Context) {
disburserBal, err := d.cfg.L2Client.BalanceAt(ctx, d.walletAddr, nil)
if err != nil {
log.Error("Error getting disburser wallet balance", "err", err)
disburserBal = big.NewInt(0)
}
depositBal, err := d.cfg.L1Client.BalanceAt(ctx, d.cfg.DepositAddr, nil)
if err != nil {
log.Error("Error getting deposit contract balance", "err", err)
depositBal = big.NewInt(0)
}
d.metrics.DisburserBalance.Set(float64(disburserBal.Uint64()))
d.metrics.DepositContractBalance.Set(float64(depositBal.Uint64()))
}
...@@ -41,7 +41,7 @@ type Metrics struct { ...@@ -41,7 +41,7 @@ type Metrics struct {
// FailedDatabaseMethods tracks the number of database failures for each // FailedDatabaseMethods tracks the number of database failures for each
// known database method. // known database method.
FailedDatabaseMethods *prometheus.GaugeVec FailedDatabaseMethods *prometheus.CounterVec
// DepositIDMismatch tracks whether or not our database is in sync with the // DepositIDMismatch tracks whether or not our database is in sync with the
// disrburser contract. 1 means in sync, 0 means out of sync. // disrburser contract. 1 means in sync, 0 means out of sync.
...@@ -53,11 +53,11 @@ type Metrics struct { ...@@ -53,11 +53,11 @@ type Metrics struct {
// SuccessfulDisbursements tracks the number of disbursements that emit a // SuccessfulDisbursements tracks the number of disbursements that emit a
// success event from a given tx. // success event from a given tx.
SuccessfulDisbursements prometheus.Gauge SuccessfulDisbursements prometheus.Counter
// FailedDisbursements tracks the number of disbursements that emit a failed // FailedDisbursements tracks the number of disbursements that emit a failed
// event from a given tx. // event from a given tx.
FailedDisbursements prometheus.Gauge FailedDisbursements prometheus.Counter
// PostgresLastDisbursedID tracks the latest disbursement id in postgres. // PostgresLastDisbursedID tracks the latest disbursement id in postgres.
PostgresLastDisbursedID prometheus.Gauge PostgresLastDisbursedID prometheus.Gauge
...@@ -65,6 +65,12 @@ type Metrics struct { ...@@ -65,6 +65,12 @@ type Metrics struct {
// ContractNextDisbursementID tracks the next disbursement id expected by // ContractNextDisbursementID tracks the next disbursement id expected by
// the disburser contract. // the disburser contract.
ContractNextDisbursementID prometheus.Gauge ContractNextDisbursementID prometheus.Gauge
// DisburserBalance tracks Teleportr's disburser account balance.
DisburserBalance prometheus.Gauge
// DepositContractBalance tracks Teleportr's deposit contract balance.
DepositContractBalance prometheus.Gauge
} }
// NewMetrics initializes a new, extended metrics object. // NewMetrics initializes a new, extended metrics object.
...@@ -72,7 +78,7 @@ func NewMetrics(subsystem string) *Metrics { ...@@ -72,7 +78,7 @@ func NewMetrics(subsystem string) *Metrics {
base := metrics.NewBase(subsystem, "") base := metrics.NewBase(subsystem, "")
return &Metrics{ return &Metrics{
Base: base, Base: base,
FailedDatabaseMethods: promauto.NewGaugeVec(prometheus.GaugeOpts{ FailedDatabaseMethods: promauto.NewCounterVec(prometheus.CounterOpts{
Name: "failed_database_operations", Name: "failed_database_operations",
Help: "Tracks the number of database failures", Help: "Tracks the number of database failures",
Subsystem: base.SubsystemName(), Subsystem: base.SubsystemName(),
...@@ -111,5 +117,15 @@ func NewMetrics(subsystem string) *Metrics { ...@@ -111,5 +117,15 @@ func NewMetrics(subsystem string) *Metrics {
Help: "Next disbursement id expected by the disburser contract", Help: "Next disbursement id expected by the disburser contract",
Subsystem: base.SubsystemName(), Subsystem: base.SubsystemName(),
}), }),
DisburserBalance: promauto.NewGauge(prometheus.GaugeOpts{
Name: "disburser_balance",
Help: "Balance in Wei of Teleportr's disburser wallet",
Subsystem: base.SubsystemName(),
}),
DepositContractBalance: promauto.NewGauge(prometheus.GaugeOpts{
Name: "deposit_contract_balance",
Help: "Balance in Wei of Teleportr's deposit contract",
Subsystem: base.SubsystemName(),
}),
} }
} }
...@@ -24,74 +24,18 @@ var ( ...@@ -24,74 +24,18 @@ var (
Required: true, Required: true,
EnvVar: prefixAPIEnvVar("PORT"), EnvVar: prefixAPIEnvVar("PORT"),
} }
APIL1EthRpcFlag = cli.StringFlag{
Name: "l1-eth-rpc",
Usage: "The endpoint for the L1 ETH provider",
Required: true,
EnvVar: prefixAPIEnvVar("L1_ETH_RPC"),
}
APIDepositAddressFlag = cli.StringFlag{
Name: "deposit-address",
Usage: "Address of the TeleportrDeposit contract",
Required: true,
EnvVar: prefixAPIEnvVar("DEPOSIT_ADDRESS"),
}
APINumConfirmationsFlag = cli.StringFlag{
Name: "num-confirmations",
Usage: "Number of confirmations required until deposits are " +
"considered confirmed",
Required: true,
EnvVar: prefixAPIEnvVar("NUM_CONFIRMATIONS"),
}
APIPostgresHostFlag = cli.StringFlag{
Name: "postgres-host",
Usage: "Host of the teleportr postgres instance",
Required: true,
EnvVar: prefixAPIEnvVar("POSTGRES_HOST"),
}
APIPostgresPortFlag = cli.Uint64Flag{
Name: "postgres-port",
Usage: "Port of the teleportr postgres instance",
Required: true,
EnvVar: prefixAPIEnvVar("POSTGRES_PORT"),
}
APIPostgresUserFlag = cli.StringFlag{
Name: "postgres-user",
Usage: "Username of the teleportr postgres instance",
Required: true,
EnvVar: prefixAPIEnvVar("POSTGRES_USER"),
}
APIPostgresPasswordFlag = cli.StringFlag{
Name: "postgres-password",
Usage: "Password of the teleportr postgres instance",
Required: true,
EnvVar: prefixAPIEnvVar("POSTGRES_PASSWORD"),
}
APIPostgresDBNameFlag = cli.StringFlag{
Name: "postgres-db-name",
Usage: "Database name of the teleportr postgres instance",
Required: true,
EnvVar: prefixAPIEnvVar("POSTGRES_DB_NAME"),
}
APIPostgresEnableSSLFlag = cli.BoolFlag{
Name: "postgres-enable-ssl",
Usage: "Whether or not to enable SSL on connections to " +
"teleportr postgres instance",
Required: true,
EnvVar: prefixAPIEnvVar("POSTGRES_ENABLE_SSL"),
}
) )
var APIFlags = []cli.Flag{ var APIFlags = []cli.Flag{
APIHostnameFlag, APIHostnameFlag,
APIPortFlag, APIPortFlag,
APIL1EthRpcFlag, L1EthRpcFlag,
APIDepositAddressFlag, DepositAddressFlag,
APINumConfirmationsFlag, NumDepositConfirmationsFlag,
APIPostgresHostFlag, PostgresHostFlag,
APIPostgresPortFlag, PostgresPortFlag,
APIPostgresUserFlag, PostgresUserFlag,
APIPostgresPasswordFlag, PostgresPasswordFlag,
APIPostgresDBNameFlag, PostgresDBNameFlag,
APIPostgresEnableSSLFlag, PostgresEnableSSLFlag,
} }
...@@ -126,16 +126,15 @@ var ( ...@@ -126,16 +126,15 @@ var (
Required: true, Required: true,
EnvVar: prefixEnvVar("POSTGRES_DB_NAME"), EnvVar: prefixEnvVar("POSTGRES_DB_NAME"),
} }
/* Optional Flags */
PostgresEnableSSLFlag = cli.BoolFlag{ PostgresEnableSSLFlag = cli.BoolFlag{
Name: "postgres-enable-ssl", Name: "postgres-enable-ssl",
Usage: "Whether or not to enable SSL on connections to " + Usage: "Whether or not to enable SSL on connections to " +
"teleportr postgres instance", "teleportr postgres instance",
Required: true, EnvVar: prefixEnvVar("POSTGRES_ENABLE_SSL"),
EnvVar: prefixEnvVar("POSTGRES_ENABLE_SSL"),
} }
/* Optional Flags */
LogLevelFlag = cli.StringFlag{ LogLevelFlag = cli.StringFlag{
Name: "log-level", Name: "log-level",
Usage: "The lowest log level that will be output", Usage: "The lowest log level that will be output",
...@@ -208,12 +207,12 @@ var requiredFlags = []cli.Flag{ ...@@ -208,12 +207,12 @@ var requiredFlags = []cli.Flag{
PostgresUserFlag, PostgresUserFlag,
PostgresPasswordFlag, PostgresPasswordFlag,
PostgresDBNameFlag, PostgresDBNameFlag,
PostgresEnableSSLFlag,
} }
var optionalFlags = []cli.Flag{ var optionalFlags = []cli.Flag{
LogLevelFlag, LogLevelFlag,
LogTerminalFlag, LogTerminalFlag,
PostgresEnableSSLFlag,
DisburserPrivateKeyFlag, DisburserPrivateKeyFlag,
MnemonicFlag, MnemonicFlag,
DisburserHDPathFlag, DisburserHDPathFlag,
......
...@@ -85,7 +85,7 @@ func Main(gitVersion string) func(ctx *cli.Context) error { ...@@ -85,7 +85,7 @@ func Main(gitVersion string) func(ctx *cli.Context) error {
go metrics.RunServer(cfg.MetricsHostname, cfg.MetricsPort) go metrics.RunServer(cfg.MetricsHostname, cfg.MetricsPort)
} }
chainID, err := l1Client.ChainID(ctx) chainID, err := l2Client.ChainID(ctx)
if err != nil { if err != nil {
return err return err
} }
...@@ -120,7 +120,7 @@ func Main(gitVersion string) func(ctx *cli.Context) error { ...@@ -120,7 +120,7 @@ func Main(gitVersion string) func(ctx *cli.Context) error {
Driver: teleportrDriver, Driver: teleportrDriver,
PollInterval: cfg.PollInterval, PollInterval: cfg.PollInterval,
ClearPendingTx: false, ClearPendingTx: false,
L1Client: l1Client, L1Client: l2Client,
TxManagerConfig: txManagerConfig, TxManagerConfig: txManagerConfig,
}) })
...@@ -152,3 +152,33 @@ func Main(gitVersion string) func(ctx *cli.Context) error { ...@@ -152,3 +152,33 @@ func Main(gitVersion string) func(ctx *cli.Context) error {
return nil return nil
} }
} }
func Migrate() func(ctx *cli.Context) error {
return func(cliCtx *cli.Context) error {
cfg, err := NewConfig(cliCtx)
if err != nil {
return err
}
log.Info("Initializing teleportr")
database, err := db.Open(db.Config{
Host: cfg.PostgresHost,
Port: uint16(cfg.PostgresPort),
User: cfg.PostgresUser,
Password: cfg.PostgresPassword,
DBName: cfg.PostgresDBName,
EnableSSL: cfg.PostgresEnableSSL,
})
if err != nil {
return err
}
log.Info("Migrating database")
if err := database.Migrate(); err != nil {
return err
}
log.Info("Done")
return nil
}
}
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namespace: kovan-replica-0-5-14
commonLabels:
network: kovan
provider: internal
bases:
- ../../envs/kovan-gen5-berlin
resources:
- ../../bases/data-transport-layer
- ../../bases/l2geth-replica
- ../../bases/configmaps
- ../../bases/servicemonitors
- ../../bases/replica-healthcheck
- ./volumes.yaml
images:
- name: ethereumoptimism/data-transport-layer
newName: ethereumoptimism/data-transport-layer
newTag: 0.5.21
- name: ethereumoptimism/l2geth
newName: ethereumoptimism/l2geth
newTag: 0.5.14
- name: ethereumoptimism/replica-healthcheck
newName: ethereumoptimism/replica-healthcheck
newTag: 0.3.3
patchesStrategicMerge:
- ./patches/dtl.yaml
- ./patches/l2geth.yaml
- ./patches/replica-healthcheck.yaml
patches:
- path: ./patches/l2geth-volume.yaml
target:
group: apps
version: v1
kind: StatefulSet
name: l2geth-replica
- path: ./patches/dtl-volume.yaml
target:
group: apps
version: v1
kind: StatefulSet
name: data-transport-layer
\ No newline at end of file
---
- op: replace
path: /spec/template/spec/volumes/0
value:
name: data-transport-layer
persistentVolumeClaim:
claimName: data-transport-layer-data
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: data-transport-layer
spec:
template:
spec:
initContainers:
- name: wait-for-l1
env:
- name: L1_NODE_WEB3_URL
value: http://failover-proxyd.default:8080
containers:
- name: data-transport-layer
resources:
limits:
cpu: "2"
memory: 4Gi
requests:
cpu: "1"
memory: 1Gi
env:
- name: DATA_TRANSPORT_LAYER__L1_RPC_ENDPOINT
value: http://failover-proxyd.default:8080
- name: DATA_TRANSPORT_LAYER__L2_RPC_ENDPOINT
value: http://sequencer.default:8545
- name: L1_NODE_WEB3_URL
value: http://failover-proxyd.default:8080
\ No newline at end of file
- op: replace
path: /spec/template/spec/volumes/0
value:
name: l2geth-replica-data
persistentVolumeClaim:
claimName: l2geth-replica-data
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: l2geth-replica
spec:
template:
spec:
containers:
- name: l2geth-replica
env:
- name: IPC_DISABLE
value: "false"
resources:
limits:
cpu: "4"
memory: 12Gi
requests:
cpu: "2"
memory: 8Gi
apiVersion: apps/v1
kind: Deployment
metadata:
name: replica-healthcheck
spec:
template:
spec:
containers:
- name: replica-healthcheck
env:
- name: REPLICA_HEALTHCHECK__ETH_NETWORK_RPC_PROVIDER
value: http://sequencer.default:8545
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: l2geth-replica-data
spec:
storageClassName: premium-rwo
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 200Gi
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: data-transport-layer-data
spec:
storageClassName: premium-rwo
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 10Gi
\ No newline at end of file
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namespace: mainnet-replica-0-5-14
commonLabels:
network: mainnet
provider: internal
bases:
- ../../../envs/mainnet-gen5-berlin
- ../../../scripts
resources:
- ../../bases/data-transport-layer
- ../../bases/l2geth-replica
- ../../bases/servicemonitors
- ../../bases/replica-healthcheck
- ./volumes.yaml
images:
- name: ethereumoptimism/data-transport-layer
newName: ethereumoptimism/data-transport-layer
newTag: 0.5.21
- name: ethereumoptimism/l2geth
newName: ethereumoptimism/l2geth
newTag: 0.5.14
- name: ethereumoptimism/replica-healthcheck
newName: ethereumoptimism/replica-healthcheck
newTag: 0.3.6
patchesStrategicMerge:
- ./patches/dtl.yaml
- ./patches/l2geth.yaml
- ./patches/replica-healthcheck.yaml
patches:
- path: ./patches/l2geth-volume.yaml
target:
group: apps
version: v1
kind: StatefulSet
name: l2geth-replica
- path: ./patches/dtl-volume.yaml
target:
group: apps
version: v1
kind: StatefulSet
name: data-transport-layer
\ No newline at end of file
---
- op: replace
path: /spec/template/spec/volumes/0
value:
name: data-transport-layer
persistentVolumeClaim:
claimName: data-transport-layer-data
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: data-transport-layer
spec:
template:
spec:
initContainers:
- name: wait-for-l1
env:
- name: L1_NODE_WEB3_URL
value: http://failover-proxyd.default:8080
containers:
- name: data-transport-layer
resources:
limits:
cpu: "2"
memory: 4Gi
requests:
cpu: "1"
memory: 1Gi
env:
- name: DATA_TRANSPORT_LAYER__L1_RPC_ENDPOINT
value: http://failover-proxyd.default:8080
- name: DATA_TRANSPORT_LAYER__L2_RPC_ENDPOINT
value: http://sequencer.default:8545
- name: L1_NODE_WEB3_URL
value: http://failover-proxyd.default:8080
\ No newline at end of file
---
- op: replace
path: /spec/template/spec/volumes/0
value:
name: l2geth-replica-data
persistentVolumeClaim:
claimName: l2geth-replica-data
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: l2geth-replica
spec:
template:
spec:
containers:
- name: l2geth-replica
env:
- name: IPC_DISABLE
value: "false"
resources:
limits:
cpu: "4"
memory: 12Gi
requests:
cpu: "2"
memory: 8Gi
apiVersion: apps/v1
kind: Deployment
metadata:
name: replica-healthcheck
spec:
template:
spec:
containers:
- name: replica-healthcheck
env:
- name: REPLICA_HEALTHCHECK__ETH_NETWORK_RPC_PROVIDER
value: http://sequencer.default:8545
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: l2geth-replica-data
spec:
storageClassName: premium-rwo
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 500Gi
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: data-transport-layer-data
spec:
storageClassName: premium-rwo
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 10Gi
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namespace: mainnet-replica-l1-0-5-14
commonLabels:
network: mainnet
provider: internal
sync_source: l1
bases:
- ../../../envs/mainnet-gen5-l1-berlin/
- ../../../scripts
resources:
- ../../bases/data-transport-layer
- ../../bases/l2geth-replica
- ../../bases/servicemonitors
- ../../bases/replica-healthcheck
- ./volumes.yaml
images:
- name: ethereumoptimism/data-transport-layer
newName: ethereumoptimism/data-transport-layer
newTag: 0.5.21
- name: ethereumoptimism/l2geth
newName: ethereumoptimism/l2geth
newTag: 0.5.14
- name: ethereumoptimism/replica-healthcheck
newName: ethereumoptimism/replica-healthcheck
newTag: 0.3.6
patchesStrategicMerge:
- ./patches/dtl.yaml
- ./patches/l2geth.yaml
- ./patches/replica-healthcheck.yaml
patches:
- path: ./patches/l2geth-volume.yaml
target:
group: apps
version: v1
kind: StatefulSet
name: l2geth-replica
- path: ./patches/dtl-volume.yaml
target:
group: apps
version: v1
kind: StatefulSet
name: data-transport-layer
\ No newline at end of file
---
- op: replace
path: /spec/template/spec/volumes/0
value:
name: data-transport-layer
persistentVolumeClaim:
claimName: data-transport-layer-data
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: data-transport-layer
spec:
template:
spec:
initContainers:
- name: wait-for-l1
env:
- name: L1_NODE_WEB3_URL
value: http://failover-proxyd.default:8080
containers:
- name: data-transport-layer
resources:
limits:
cpu: "2"
memory: 4Gi
requests:
cpu: "1"
memory: 1Gi
env:
- name: DATA_TRANSPORT_LAYER__L1_RPC_ENDPOINT
value: http://failover-proxyd.default:8080
- name: DATA_TRANSPORT_LAYER__L2_RPC_ENDPOINT
value: http://sequencer.default:8545
- name: L1_NODE_WEB3_URL
value: http://failover-proxyd.default:8080
\ No newline at end of file
---
- op: replace
path: /spec/template/spec/volumes/0
value:
name: l2geth-replica-data
persistentVolumeClaim:
claimName: l2geth-replica-data
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: l2geth-replica
spec:
template:
spec:
containers:
- name: l2geth-replica
env:
- name: IPC_DISABLE
value: "false"
resources:
limits:
cpu: "4"
memory: 12Gi
requests:
cpu: "2"
memory: 8Gi
apiVersion: apps/v1
kind: Deployment
metadata:
name: replica-healthcheck
spec:
replicas: 1
template:
spec:
containers:
- name: replica-healthcheck
env:
- name: REPLICA_HEALTHCHECK__ETH_NETWORK_RPC_PROVIDER
value: http://sequencer.default:8545
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: l2geth-replica-data
spec:
storageClassName: premium-rwo
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 500Gi
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: data-transport-layer-data
spec:
storageClassName: premium-rwo
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 10Gi
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: kovan-replica-0-5-14
annotations:
kubernetes.io/ingress.class: gce
kubernetes.io/ingress.global-static-ip-name: kovan-replica-0-5-14
networking.gke.io/managed-certificates: kovan-replica-0-5-14
spec:
rules:
- host: kovan-replica-0-5-14.optimism.io
http:
paths:
- backend:
service:
name: l2geth-replica
port:
name: rpc
path: /
pathType: ImplementationSpecific
---
apiVersion: networking.gke.io/v1
kind: ManagedCertificate
metadata:
name: kovan-replica-0-5-14
spec:
domains:
- kovan-replica-0-5-14.optimism.io
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namespace: kovan-replica-0-5-14
commonLabels:
network: kovan
provider: internal
bases:
- ../../../envs/kovan-gen5-berlin
- ../../../scripts
resources:
- ../../bases/data-transport-layer
- ../../bases/l2geth-replica
- ../../bases/servicemonitors
- ../../bases/replica-healthcheck
- ./ingress.yaml
- ./volumes.yaml
images:
- name: ethereumoptimism/data-transport-layer
newName: ethereumoptimism/data-transport-layer
newTag: 0.5.21
- name: ethereumoptimism/l2geth
newName: ethereumoptimism/l2geth
newTag: 0.5.14
- name: ethereumoptimism/replica-healthcheck
newName: ethereumoptimism/replica-healthcheck
newTag: 0.3.6
patchesStrategicMerge:
- ./patches/dtl.yaml
- ./patches/l2geth.yaml
- ./patches/replica-healthcheck.yaml
patches:
- path: ./patches/l2geth-volume.yaml
target:
group: apps
version: v1
kind: StatefulSet
name: l2geth-replica
- path: ./patches/dtl-volume.yaml
target:
group: apps
version: v1
kind: StatefulSet
name: data-transport-layer
\ No newline at end of file
---
- op: replace
path: /spec/template/spec/volumes/0
value:
name: data-transport-layer
persistentVolumeClaim:
claimName: data-transport-layer-data
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: data-transport-layer
spec:
template:
spec:
initContainers:
- name: wait-for-l1
env:
- name: L1_NODE_WEB3_URL
valueFrom:
secretKeyRef:
name: replica-secrets
key: l1-rpc-endpoint
containers:
- name: data-transport-layer
resources:
limits:
cpu: "2"
memory: 4Gi
requests:
cpu: "1"
memory: 1Gi
env:
- name: DATA_TRANSPORT_LAYER__L1_RPC_ENDPOINT
valueFrom:
secretKeyRef:
name: replica-secrets
key: l1-rpc-endpoint
- name: DATA_TRANSPORT_LAYER__L2_RPC_ENDPOINT
valueFrom:
secretKeyRef:
name: replica-secrets
key: l2-rpc-endpoint
- name: L1_NODE_WEB3_URL
valueFrom:
secretKeyRef:
name: replica-secrets
key: l1-rpc-endpoint
\ No newline at end of file
- op: replace
path: /spec/template/spec/volumes/0
value:
name: l2geth-replica-data
persistentVolumeClaim:
claimName: l2geth-replica-data
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: l2geth-replica
spec:
template:
spec:
containers:
- name: l2geth-replica
env:
- name: IPC_DISABLE
value: "false"
resources:
limits:
cpu: "4"
memory: 12Gi
requests:
cpu: "2"
memory: 8Gi
apiVersion: apps/v1
kind: Deployment
metadata:
name: replica-healthcheck
spec:
template:
spec:
containers:
- name: replica-healthcheck
env:
- name: REPLICA_HEALTHCHECK__ETH_NETWORK_RPC_PROVIDER
value: https://kovan.optimism.io
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: l2geth-replica-data
spec:
storageClassName: premium-rwo
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 200Gi
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: data-transport-layer-data
spec:
storageClassName: premium-rwo
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 10Gi
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: mainnet-replica-0-5-14
annotations:
kubernetes.io/ingress.class: gce
kubernetes.io/ingress.global-static-ip-name: mainnet-replica-0-5-14
networking.gke.io/managed-certificates: mainnet-replica-0-5-14
spec:
rules:
- host: mainnet-replica-0-5-14.optimism.io
http:
paths:
- backend:
service:
name: l2geth-replica
port:
name: rpc
path: /
pathType: ImplementationSpecific
---
apiVersion: networking.gke.io/v1
kind: ManagedCertificate
metadata:
name: mainnet-replica-0-5-14
spec:
domains:
- mainnet-replica-0-5-14.optimism.io
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namespace: mainnet-replica-0-5-14
commonLabels:
network: mainnet
provider: internal
bases:
- ../../../envs/mainnet-gen5-berlin/
- ../../../scripts
resources:
- ../../bases/data-transport-layer
- ../../bases/l2geth-replica
- ../../bases/servicemonitors
- ../../bases/replica-healthcheck
- ./volumes.yaml
- ./ingress.yaml
images:
- name: ethereumoptimism/data-transport-layer
newName: ethereumoptimism/data-transport-layer
newTag: 0.5.21
- name: ethereumoptimism/l2geth
newName: ethereumoptimism/l2geth
newTag: 0.5.14
- name: ethereumoptimism/replica-healthcheck
newName: ethereumoptimism/replica-healthcheck
newTag: 0.3.3
patchesStrategicMerge:
- ./patches/dtl.yaml
- ./patches/l2geth.yaml
- ./patches/replica-healthcheck.yaml
patches:
- path: ./patches/l2geth-volume.yaml
target:
group: apps
version: v1
kind: StatefulSet
name: l2geth-replica
\ No newline at end of file
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: data-transport-layer
spec:
template:
spec:
initContainers:
- name: wait-for-l1
env:
- name: L1_NODE_WEB3_URL
valueFrom:
secretKeyRef:
name: replica-secrets
key: l1-rpc-endpoint
containers:
- name: data-transport-layer
resources:
limits:
cpu: "2"
memory: 4Gi
requests:
cpu: "1"
memory: 1Gi
env:
- name: DATA_TRANSPORT_LAYER__L1_RPC_ENDPOINT
valueFrom:
secretKeyRef:
name: replica-secrets
key: l1-rpc-endpoint
- name: DATA_TRANSPORT_LAYER__L2_RPC_ENDPOINT
valueFrom:
secretKeyRef:
name: replica-secrets
key: l2-rpc-endpoint
- name: L1_NODE_WEB3_URL
valueFrom:
secretKeyRef:
name: replica-secrets
key: l1-rpc-endpoint
\ No newline at end of file
- op: replace
path: /spec/template/spec/volumes/0
value:
name: l2geth-replica-data
persistentVolumeClaim:
claimName: l2geth-replica-data
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: l2geth-replica
spec:
template:
spec:
containers:
- name: l2geth-replica
command:
- geth
- --config=/l2geth-config/l2geth.toml
- --datadir=$(DATADIR)
- --password=$(DATADIR)/password
- --allow-insecure-unlock
- --unlock=$(BLOCK_SIGNER_ADDRESS)
- --mine
- --miner.etherbase=$(BLOCK_SIGNER_ADDRESS)
- --metrics
- --metrics.influxdb
- --metrics.influxdb.endpoint=http://influxdb.monitoring:8086
- --metrics.influxdb.database=$(NAMESPACE)
resources:
limits:
cpu: "8"
memory: 24Gi
requests:
cpu: "4"
memory: 12Gi
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: data-transport-layer
spec:
template:
spec:
initContainers:
- name: wait-for-l1
env:
- name: L1_NODE_WEB3_URL
valueFrom:
secretKeyRef:
name: replica-secrets
key: l1-rpc-endpoint
containers:
- name: data-transport-layer
resources:
limits:
cpu: "2"
memory: 4Gi
requests:
cpu: "1"
memory: 1Gi
env:
- name: DATA_TRANSPORT_LAYER__L1_RPC_ENDPOINT
valueFrom:
secretKeyRef:
name: replica-secrets
key: l1-rpc-endpoint
- name: DATA_TRANSPORT_LAYER__L2_RPC_ENDPOINT
valueFrom:
secretKeyRef:
name: replica-secrets
key: l2-rpc-endpoint
- name: L1_NODE_WEB3_URL
valueFrom:
secretKeyRef:
name: replica-secrets
key: l1-rpc-endpoint
\ No newline at end of file
apiVersion: apps/v1
kind: Deployment
metadata:
name: replica-healthcheck
spec:
template:
spec:
containers:
- name: replica-healthcheck
env:
- name: REPLICA_HEALTHCHECK__ETH_NETWORK_RPC_PROVIDER
value: https://mainnet.optimism.io
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: l2geth-replica-data
spec:
storageClassName: premium-rwo
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 500Gi
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: data-transport-layer-data
spec:
storageClassName: premium-rwo
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 10Gi
\ No newline at end of file
...@@ -10,8 +10,9 @@ OVMCONTEXT_SPEC_NUM_TXS=1 ...@@ -10,8 +10,9 @@ OVMCONTEXT_SPEC_NUM_TXS=1
RUN_WITHDRAWAL_TESTS=false RUN_WITHDRAWAL_TESTS=false
RUN_DEBUG_TRACE_TESTS=false RUN_DEBUG_TRACE_TESTS=false
RUN_REPLICA_TESTS=false RUN_REPLICA_TESTS=false
RUN_HEALTHCHECK_TESTS=false
RUN_STRESS_TESTS=false RUN_STRESS_TESTS=false
# Can be configured up or down as necessary # Can be configured up or down as necessary
MOCHA_TIMEOUT=300000 MOCHA_TIMEOUT=300000
# Set to true to make Mocha stop after the first failed test. # Set to true to make Mocha stop after the first failed test.
MOCHA_BAIL=false MOCHA_BAIL=false
\ No newline at end of file
...@@ -67,6 +67,7 @@ ...@@ -67,6 +67,7 @@
"hardhat-gas-reporter": "^1.0.4", "hardhat-gas-reporter": "^1.0.4",
"lint-staged": "11.0.0", "lint-staged": "11.0.0",
"mocha": "^8.4.0", "mocha": "^8.4.0",
"node-fetch": "^2.6.7",
"prom-client": "^14.0.1", "prom-client": "^14.0.1",
"rimraf": "^3.0.2", "rimraf": "^3.0.2",
"typescript": "^4.3.5", "typescript": "^4.3.5",
......
import fetch from 'node-fetch'
import { expect } from './shared/setup'
import { envConfig } from './shared/utils'
describe('Healthcheck Tests', () => {
before(async function () {
if (!envConfig.RUN_HEALTHCHECK_TESTS) {
this.skip()
}
})
// Super simple test, is the metric server up?
it('should have metrics exposed', async () => {
const response = await fetch(envConfig.HEALTHCHECK_URL)
expect(response.status).to.equal(200)
})
})
...@@ -56,6 +56,8 @@ const procEnv = cleanEnv(process.env, { ...@@ -56,6 +56,8 @@ const procEnv = cleanEnv(process.env, {
VERIFIER_URL: str({ default: 'http://localhost:8547' }), VERIFIER_URL: str({ default: 'http://localhost:8547' }),
HEALTHCHECK_URL: str({ default: 'http://localhost:7300/metrics' }),
PRIVATE_KEY: str({ PRIVATE_KEY: str({
default: default:
'0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80', '0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80',
...@@ -78,6 +80,9 @@ const procEnv = cleanEnv(process.env, { ...@@ -78,6 +80,9 @@ const procEnv = cleanEnv(process.env, {
RUN_REPLICA_TESTS: bool({ RUN_REPLICA_TESTS: bool({
default: true, default: true,
}), }),
RUN_HEALTHCHECK_TESTS: bool({
default: true,
}),
RUN_DEBUG_TRACE_TESTS: bool({ RUN_DEBUG_TRACE_TESTS: bool({
default: true, default: true,
}), }),
......
...@@ -36,30 +36,7 @@ services: ...@@ -36,30 +36,7 @@ services:
# Env vars for the deployment script. # Env vars for the deployment script.
CONTRACTS_RPC_URL: http://l1_chain:8545 CONTRACTS_RPC_URL: http://l1_chain:8545
CONTRACTS_DEPLOYER_KEY: 'ac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80' CONTRACTS_DEPLOYER_KEY: 'ac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80'
CONTRACTS_TARGET_NETWORK: 'custom' CONTRACTS_TARGET_NETWORK: 'local'
OVM_ADDRESS_MANAGER_OWNER: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266'
OVM_PROPOSER_ADDRESS: '0x3c44cdddb6a900fa2b585dd299e03d12fa4293bc'
OVM_SEQUENCER_ADDRESS: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8'
SCC_FRAUD_PROOF_WINDOW: 0
NUM_DEPLOY_CONFIRMATIONS: 0
# skip compilation when run in docker-compose, since the contracts
# were already compiled in the builder step
NO_COMPILE: 1
# Env vars for the dump script.
# Default hardhat account 5
GAS_PRICE_ORACLE_OWNER: '0x9965507d1a55bcc2695c58ba16fb37d819b0a4dc'
# setting the whitelist owner to address(0) disables the whitelist
WHITELIST_OWNER: '0x0000000000000000000000000000000000000000'
L1_FEE_WALLET_ADDRESS: '0x391716d440c151c42cdf1c95c1d83a5427bca52c'
L2_CHAIN_ID: 987
L2_BLOCK_GAS_LIMIT: 15000000
BLOCK_SIGNER_ADDRESS: '0x00000398232E2064F896018496b4b44b3D62751F'
GAS_PRICE_ORACLE_OVERHEAD: 2750
GAS_PRICE_ORACLE_SCALAR: 1500000
GAS_PRICE_ORACLE_L1_BASE_FEE: 1
GAS_PRICE_ORACLE_GAS_PRICE: 1
GAS_PRICE_ORACLE_DECIMALS: 6
ports: ports:
# expose the service to the host for getting the contract addrs # expose the service to the host for getting the contract addrs
- ${DEPLOYER_PORT:-8080}:8081 - ${DEPLOYER_PORT:-8080}:8081
...@@ -197,6 +174,23 @@ services: ...@@ -197,6 +174,23 @@ services:
- ${REPLICA_HTTP_PORT:-8549}:8545 - ${REPLICA_HTTP_PORT:-8549}:8545
- ${REPLICA_WS_PORT:-8550}:8546 - ${REPLICA_WS_PORT:-8550}:8546
replica-healthcheck:
depends_on:
- l2geth
- replica
deploy:
replicas: 0
build:
context: ..
dockerfile: ./ops/docker/Dockerfile.packages
target: replica-healthcheck
image: ethereumoptimism/replica-healthcheck:${DOCKER_TAG_REPLICA_HEALTHCHECK:-latest}
environment:
HEALTHCHECK__REFERENCE_RPC_PROVIDER: http://l2geth:8545
HEALTHCHECK__TARGET_RPC_PROVIDER: http://replica:8545
ports:
- ${HEALTHCHECK_HTTP_PORT:-7300}:7300
integration_tests: integration_tests:
deploy: deploy:
replicas: 0 replicas: 0
...@@ -209,6 +203,7 @@ services: ...@@ -209,6 +203,7 @@ services:
environment: environment:
L1_URL: http://l1_chain:8545 L1_URL: http://l1_chain:8545
L2_URL: http://l2geth:8545 L2_URL: http://l2geth:8545
HEALTHCHECK_URL: http://replica-healthcheck:7300/metrics
REPLICA_URL: http://replica:8545 REPLICA_URL: http://replica:8545
VERIFIER_URL: http://verifier:8545 VERIFIER_URL: http://verifier:8545
URL: http://deployer:8081/addresses.json URL: http://deployer:8081/addresses.json
......
...@@ -61,5 +61,5 @@ CMD ["npm", "run", "start"] ...@@ -61,5 +61,5 @@ CMD ["npm", "run", "start"]
FROM base as replica-healthcheck FROM base as replica-healthcheck
WORKDIR /opts/optimism/packages/replica-healthcheck WORKDIR /opt/optimism/packages/replica-healthcheck
ENTRYPOINT ["npm", "run", "start"] ENTRYPOINT ["npm", "run", "start"]
FROM golang:1.17.3-alpine3.13 as builder
RUN apk add --no-cache make gcc musl-dev linux-headers git jq bash
COPY ./go/bss-core /go/bss-core
COPY ./go/teleportr/go.mod ./go/teleportr/go.sum /go/teleportr/
WORKDIR /go/teleportr
RUN go mod graph | grep -v bss-core | awk '{if ($1 !~ "@") print $2}' | xargs -n 1 go get
COPY ./go/teleportr/ ./
RUN make teleportr teleportr-api
FROM alpine:3.13
RUN apk add --no-cache ca-certificates jq curl
COPY --from=builder /go/teleportr/teleportr /usr/local/bin/
COPY --from=builder /go/teleportr/teleportr-api /usr/local/bin/
CMD ["teleportr"]
FROM golang:1.17.8-alpine3.15
RUN apk add --no-cache make gcc musl-dev linux-headers git jq curl bash gzip ca-certificates openssh && \
go install gotest.tools/gotestsum@latest && \
curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(go env GOPATH)/bin v1.44.2
CMD ["bash"]
FROM python:3.8.12-slim-buster
RUN apt-get update && \
apt-get install -y curl openssh-client git build-essential ca-certificates && \
curl -sL https://deb.nodesource.com/setup_16.x -o nodesource_setup.sh && \
bash nodesource_setup.sh && \
apt-get install -y nodejs && \
npm i -g yarn && \
npm i -g depcheck && \
pip install slither-analyzer
...@@ -24,39 +24,7 @@ curl \ ...@@ -24,39 +24,7 @@ curl \
echo "Connected to L1." echo "Connected to L1."
echo "Building deployment command." echo "Building deployment command."
DEPLOY_CMD="npx hardhat deploy" DEPLOY_CMD="npx hardhat deploy --network $CONTRACTS_TARGET_NETWORK"
# Helper method to concatenate things onto $DEPLOY_CMD.
# Usage: concat_cmd "str-to-concat"
function concat_cmd() {
DEPLOY_CMD="$DEPLOY_CMD $1"
}
# Helper method to conditionally concatenate CLI arguments
# when a given env var is defined.
# Usage: concat_arg "--arg-name" "env-var-name"
function concat_arg() {
ARG=$1
ENV_VAR=$2
if [ -n "${!ENV_VAR+x}" ]; then
echo "$ENV_VAR set to ${!ENV_VAR}, applying $ARG argument."
concat_cmd "$ARG \"${!ENV_VAR}\""
else
echo "$ENV_VAR is not not set, skipping $ARG argument."
fi
}
concat_arg "--network" "CONTRACTS_TARGET_NETWORK"
concat_arg "--ovm-address-manager-owner" "OVM_ADDRESS_MANAGER_OWNER"
concat_arg "--ovm-proposer-address" "OVM_PROPOSER_ADDRESS"
concat_arg "--ovm-sequencer-address" "OVM_SEQUENCER_ADDRESS"
concat_arg "--l1-block-time-seconds" "L1_BLOCK_TIME_SECONDS"
concat_arg "--ctc-max-transaction-gas-limit" "CTC_MAX_TRANSACTION_GAS_LIMIT"
concat_arg "--ctc-l2-gas-discount-divisor" "CTC_L2_GAS_DISCOUNT_DIVISOR"
concat_arg "--ctc-enqueue-gas-cost" "CTC_ENQUEUE_GAS_COST"
concat_arg "--scc-fraud-proof-window" "SCC_FRAUD_PROOF_WINDOW"
concat_arg "--num-deploy-confirmations" "NUM_DEPLOY_CONFIRMATIONS"
concat_arg "--forked" "FORKED"
echo "Deploying contracts. Deployment command:" echo "Deploying contracts. Deployment command:"
echo "$DEPLOY_CMD" echo "$DEPLOY_CMD"
...@@ -81,20 +49,13 @@ echo "}" >> addresses.json ...@@ -81,20 +49,13 @@ echo "}" >> addresses.json
echo "Built addresses.json. Content:" echo "Built addresses.json. Content:"
jq . addresses.json jq . addresses.json
echo "Env vars for the dump script:"
export L1_STANDARD_BRIDGE_ADDRESS=$(cat "./addresses.json" | jq -r .Proxy__OVM_L1StandardBridge)
export L1_CROSS_DOMAIN_MESSENGER_ADDRESS=$(cat "./addresses.json" | jq -r .Proxy__OVM_L1CrossDomainMessenger)
echo "ADDRESS_MANAGER_ADDRESS=$ADDRESS_MANAGER_ADDRESS"
echo "L1_STANDARD_BRIDGE_ADDRESS=$L1_STANDARD_BRIDGE_ADDRESS"
echo "L1_CROSS_DOMAIN_MESSENGER_ADDRESS=$L1_CROSS_DOMAIN_MESSENGER_ADDRESS"
echo "Building dump file." echo "Building dump file."
yarn run build:dump npx hardhat take-dump --network $CONTRACTS_TARGET_NETWORK
mv addresses.json ./dist/dumps mv addresses.json ./genesis
cp ./genesis/$CONTRACTS_TARGET_NETWORK.json ./genesis/state-dump.latest.json
# service the addresses and dumps # service the addresses and dumps
echo "Starting server." echo "Starting server."
python3 -m http.server \ python3 -m http.server \
--bind "0.0.0.0" 8081 \ --bind "0.0.0.0" 8081 \
--directory ./dist/dumps --directory ./genesis
...@@ -23,4 +23,4 @@ curl \ ...@@ -23,4 +23,4 @@ curl \
--output /dev/null \ --output /dev/null \
$L2_URL $L2_URL
npx hardhat test --network optimism --no-compile npx hardhat test --network optimism --no-compile "$@"
#!/bin/bash #!/bin/bash
CONTAINER=l2geth CONTAINER=l2geth
RETRIES=30 RETRIES=90
i=0 i=0
until docker-compose logs l2geth | grep -q "Starting Sequencer Loop"; until docker-compose logs l2geth | grep -q "Starting Sequencer Loop";
do do
sleep 3 sleep 1
if [ $i -eq $RETRIES ]; then if [ $i -eq $RETRIES ]; then
echo 'Timed out waiting for sequencer' echo 'Timed out waiting for sequencer'
break break
......
/* Imports: External */ import { Server } from 'net'
import Config from 'bcfg' import Config from 'bcfg'
import * as dotenv from 'dotenv' import * as dotenv from 'dotenv'
import { Command, Option } from 'commander' import { Command, Option } from 'commander'
import { ValidatorSpec, Spec, cleanEnv } from 'envalid' import { ValidatorSpec, Spec, cleanEnv } from 'envalid'
import { sleep } from '@eth-optimism/core-utils' import { sleep } from '@eth-optimism/core-utils'
import snakeCase from 'lodash/snakeCase' import snakeCase from 'lodash/snakeCase'
import express from 'express'
import prometheus, { Registry } from 'prom-client'
/* Imports: Internal */
import { Logger } from '../common/logger' import { Logger } from '../common/logger'
import { Metric } from './metrics' import { Metric } from './metrics'
...@@ -82,6 +84,26 @@ export abstract class BaseServiceV2< ...@@ -82,6 +84,26 @@ export abstract class BaseServiceV2<
*/ */
protected readonly metrics: TMetrics protected readonly metrics: TMetrics
/**
* Registry for prometheus metrics.
*/
protected readonly metricsRegistry: Registry
/**
* Metrics server.
*/
protected metricsServer: Server
/**
* Port for the metrics server.
*/
protected readonly metricsServerPort: number
/**
* Hostname for the metrics server.
*/
protected readonly metricsServerHostname: string
/** /**
* @param params Options for the construction of the service. * @param params Options for the construction of the service.
* @param params.name Name for the service. This name will determine the prefix used for logging, * @param params.name Name for the service. This name will determine the prefix used for logging,
...@@ -93,6 +115,8 @@ export abstract class BaseServiceV2< ...@@ -93,6 +115,8 @@ export abstract class BaseServiceV2<
* @param params.options Options to pass to the service. * @param params.options Options to pass to the service.
* @param params.loops Whether or not the service should loop. Defaults to true. * @param params.loops Whether or not the service should loop. Defaults to true.
* @param params.loopIntervalMs Loop interval in milliseconds. Defaults to zero. * @param params.loopIntervalMs Loop interval in milliseconds. Defaults to zero.
* @param params.metricsServerPort Port for the metrics server. Defaults to 7300.
* @param params.metricsServerHostname Hostname for the metrics server. Defaults to 0.0.0.0.
*/ */
constructor(params: { constructor(params: {
name: string name: string
...@@ -101,6 +125,8 @@ export abstract class BaseServiceV2< ...@@ -101,6 +125,8 @@ export abstract class BaseServiceV2<
options?: Partial<TOptions> options?: Partial<TOptions>
loop?: boolean loop?: boolean
loopIntervalMs?: number loopIntervalMs?: number
metricsServerPort?: number
metricsServerHostname?: string
}) { }) {
this.loop = params.loop !== undefined ? params.loop : true this.loop = params.loop !== undefined ? params.loop : true
this.loopIntervalMs = this.loopIntervalMs =
...@@ -203,6 +229,11 @@ export abstract class BaseServiceV2< ...@@ -203,6 +229,11 @@ export abstract class BaseServiceV2<
return acc return acc
}, {}) as TMetrics }, {}) as TMetrics
// Create the metrics server.
this.metricsRegistry = prometheus.register
this.metricsServerPort = params.metricsServerPort || 7300
this.metricsServerHostname = params.metricsServerHostname || '0.0.0.0'
this.logger = new Logger({ name: params.name }) this.logger = new Logger({ name: params.name })
// Gracefully handle stop signals. // Gracefully handle stop signals.
...@@ -222,6 +253,33 @@ export abstract class BaseServiceV2< ...@@ -222,6 +253,33 @@ export abstract class BaseServiceV2<
public async run(): Promise<void> { public async run(): Promise<void> {
this.done = false this.done = false
// Start the metrics server if not yet running.
if (!this.metricsServer) {
this.logger.info('starting metrics server')
await new Promise((resolve) => {
const app = express()
app.get('/metrics', async (_, res) => {
res.status(200).send(await this.metricsRegistry.metrics())
})
this.metricsServer = app.listen(
this.metricsServerPort,
this.metricsServerHostname,
() => {
resolve(null)
}
)
})
this.logger.info(`metrics started`, {
port: this.metricsServerPort,
hostname: this.metricsServerHostname,
route: '/metrics',
})
}
if (this.init) { if (this.init) {
this.logger.info('initializing service') this.logger.info('initializing service')
await this.init() await this.init()
...@@ -267,7 +325,18 @@ export abstract class BaseServiceV2< ...@@ -267,7 +325,18 @@ export abstract class BaseServiceV2<
while (!this.done) { while (!this.done) {
await sleep(1000) await sleep(1000)
} }
this.logger.info('main loop finished, goodbye!')
// Shut down the metrics server if it's running.
if (this.metricsServer) {
this.logger.info('stopping metrics server')
await new Promise((resolve) => {
this.metricsServer.close(() => {
resolve(null)
})
})
this.logger.info('metrics server stopped')
this.metricsServer = undefined
}
} }
/** /**
......
# Name for the network to deploy to ("mainnet", "kovan", etc.)
CONTRACTS_TARGET_NETWORK=
# Private key that will send deployment transactions
CONTRACTS_DEPLOYER_KEY=
# RPC URL connected to the L1 chain we're deploying to
CONTRACTS_RPC_URL=
# Your Etherscan API key for the L1 network
ETHERSCAN_API_KEY=
module.exports = { module.exports = {
extends: '../../.eslintrc.js', extends: '../../.eslintrc.js',
ignorePatterns: [
'src/contract-artifacts.ts',
'src/contract-deployed-artifacts.ts',
],
} }
...@@ -32,7 +32,9 @@ import { L1CrossDomainMessenger } from "@eth-optimism/contracts/L1/messaging/L1C ...@@ -32,7 +32,9 @@ import { L1CrossDomainMessenger } from "@eth-optimism/contracts/L1/messaging/L1C
``` ```
## Guide for Developers ## Guide for Developers
### Setup ### Setup
Install the following: Install the following:
- [`Node.js` (14+)](https://nodejs.org/en/) - [`Node.js` (14+)](https://nodejs.org/en/)
- [`npm`](https://www.npmjs.com/get-npm) - [`npm`](https://www.npmjs.com/get-npm)
...@@ -46,87 +48,75 @@ cd contracts ...@@ -46,87 +48,75 @@ cd contracts
``` ```
Install `npm` packages: Install `npm` packages:
```shell ```shell
yarn install yarn install
``` ```
### Running Tests ### Running Tests
Tests are executed via `yarn`: Tests are executed via `yarn`:
```shell ```shell
yarn test yarn test
``` ```
Run specific tests by giving a path to the file you want to run: Run specific tests by giving a path to the file you want to run:
```shell ```shell
yarn test ./test/path/to/my/test.spec.ts yarn test ./test/path/to/my/test.spec.ts
``` ```
### Measuring test coverage: ### Measuring test coverage:
```shell ```shell
yarn test:coverage yarn test:coverage
``` ```
The output is most easily viewable by opening the html file in your browser: The output is most easily viewable by opening the html file in your browser:
```shell ```shell
open ./coverage/index.html open ./coverage/index.html
``` ```
### Compiling and Building ### Compiling and Building
Easiest way is to run the primary build script:
```shell
yarn build
```
Running the full build command will perform the following actions: Compile and build the various required with the `build` command:
1. `build:contracts` - Compile all Solidity contracts with both the EVM and OVM compilers.
2. `build:typescript` - Builds the typescript files that are used to export utilities into js.
3. `build:copy` - Copies various other files into the dist folder.
4. `build:dump` - Generates a genesis state from the contracts that L2 geth will use.
5. `build:typechain` - Generates [TypeChain](https://github.com/ethereum-ts/TypeChain) artifacts.
You can also build specific components as follows:
```shell ```shell
yarn build:contracts yarn build
``` ```
### Deploying the Contracts ### Deploying the Contracts
#### Required environment variables #### Required environment variables
You must set the following environment variables to execute a deployment: You must set several required environment variables before you can execute a deployment.
Duplicate the file [`.env.example`](./.env.example) and rename your duplicate to `.env`.
```bash Fill out each of the environment variables before continuing.
# Name for the network to deploy to ("mainnet", "kovan", etc.)
export CONTRACTS_TARGET_NETWORK=...
# Private key that will send deployment transactions
export CONTRACTS_DEPLOYER_KEY=...
# RPC URL connected to the L1 chain we're deploying to #### Creating a deployment configuration
export CONTRACTS_RPC_URL=...
# Your Etherscan API key for the L1 network Before you can carry out a deployment, you must create a deployment configuration file inside of the [deploy-config](./deploy-config/) folder.
export ETHERSCAN_API_KEY=... Deployment configuration files are TypeScript files that export an object that conforms to the `DeployConfig` type.
``` See [mainnet.ts](./deploy-config/mainnet.ts) for an example deployment configuration.
We recommend duplicating an existing deployment config and modifying it to satisfy your requirements.
#### Creating a deployment script
Before you can carry out a deployment, you must create a deployment script. #### Executing a deployment
See [mainnet.sh](./scripts/deploy-scripts/mainnet.sh) for an example deployment script.
We recommend duplicating an existing deployment script and modifying it to satisfy your requirements.
Most variables within the deploy script are relatively self-explanatory. Once you've created your deploy config, you can execute a deployment with the following command:
If you intend to upgrade an existing system you **MUST** [include the following argument](https://github.com/ethereum-optimism/optimism/blob/6f633f915b34a46ac14430724bed9722af8bd05e/packages/contracts/scripts/deploy-scripts/mainnet.sh#L33) in the deploy script:
``` ```
--tags upgrade npx hardhat deploy --network <my network name>
``` ```
If you are deploying a system from scratch, you should **NOT** include `--tags upgrade` or you will fail to deploy several contracts. Note that this only applies to fresh deployments.
If you want to upgrade an existing system (instead of deploying a new system from scratch), you must use the following command instead:
#### Executing a deployment ```
npx hardhat deploy --network <my network name> --tags upgrade
```
Once you've created your deploy script, simply run the script to trigger a deployment.
During the deployment process, you will be asked to transfer ownership of several contracts to a special contract address. During the deployment process, you will be asked to transfer ownership of several contracts to a special contract address.
You will also be asked to verify various configuration values. You will also be asked to verify various configuration values.
This is a safety mechanism to make sure that actions within an upgrade are performed atomically. This is a safety mechanism to make sure that actions within an upgrade are performed atomically.
...@@ -134,19 +124,29 @@ Ownership of these addresses will be automatically returned to the original owne ...@@ -134,19 +124,29 @@ Ownership of these addresses will be automatically returned to the original owne
The original owner can always recover ownership from the upgrade contract in an emergency. The original owner can always recover ownership from the upgrade contract in an emergency.
Please read these instructions carefully, verify each of the presented configuration values, and carefully confirm that the contract you are giving ownership to has not been compromised (e.g., check the code on Etherscan). Please read these instructions carefully, verify each of the presented configuration values, and carefully confirm that the contract you are giving ownership to has not been compromised (e.g., check the code on Etherscan).
After your deployment is complete, your new contracts will be written to an artifacts directory in `./deployments/<name>`. After your deployment is complete, your new contracts will be written to an artifacts directory in `./deployments/<my network name>`.
Your contracts will also be automatically verified as part of the deployment script.
#### Verifying contract source code
Contracts will be automatically verified via both [Etherscan](https://etherscan.io) and [Sourcify](https://sourcify.dev/) during the deployment process.
If there was an issue with verification during the deployment, you can manually verify your contracts with the command:
```
npx hardhat etherscan-verify --network <my network name>
```
#### Creating a genesis file #### Creating a genesis file
Optimism expects that certain contracts (called "predeploys") be deployed to the L2 network at pre-determined addresses. Optimism expects that certain contracts (called "predeploys") be deployed to the L2 network at pre-determined addresses.
Doing this requires that you generate a special genesis file to be used by your corresponding L2Geth nodes. We guarantee this by creating a genesis file in which certain contracts are already within the L2 state at the genesis block.
You must first create a genesis generation script. To create the genesis file for your network, you must first deploy the L1 contracts using the appropriate commands from above.
Like in the deploy script, we recommend starting from an [existing script](./scripts/deploy-scripts/mainnet-genesis.sh). Once you've deployed your contracts, run the following command:
Modify each of the values within this script to match the values of your own deployment, taking any L1 contract addresses from the `./deployments/<name>` folder that was just generated or modified.
```
npx hardhat take-dump --network <my network name>
```
Execute this script to generate the genesis file. A genesis file will be created for you at `/genesis/<my network name>.json`.
You will find this genesis file at `./dist/dumps/state-dump.latest.json`.
You can then ingest this file via `geth init`. You can then ingest this file via `geth init`.
### Hardhat tasks ### Hardhat tasks
......
/* External Imports */
import * as fs from 'fs'
import * as path from 'path'
import * as mkdirp from 'mkdirp'
const ensure = (value, key) => {
if (typeof value === 'undefined' || value === null || Number.isNaN(value)) {
throw new Error(`${key} is undefined, null or NaN`)
}
}
/* Internal Imports */
import { makeL2GenesisFile } from '../src/make-genesis'
;(async () => {
const outdir = path.resolve(__dirname, '../dist/dumps')
const outfile = path.join(outdir, 'state-dump.latest.json')
mkdirp.sync(outdir)
const env = process.env
// An account that represents the owner of the whitelist
const whitelistOwner = env.WHITELIST_OWNER
// The gas price oracle owner, can update values is GasPriceOracle L2 predeploy
const gasPriceOracleOwner = env.GAS_PRICE_ORACLE_OWNER
// The initial overhead value for the GasPriceOracle
const gasPriceOracleOverhead = parseInt(
env.GAS_PRICE_ORACLE_OVERHEAD || '2750',
10
)
// The initial scalar value for the GasPriceOracle. The actual
// scalar is scaled downwards by the number of decimals
const gasPriceOracleScalar = parseInt(
env.GAS_PRICE_ORACLE_SCALAR || '1500000',
10
)
// The initial decimals that scale down the scalar in the GasPriceOracle
const gasPriceOracleDecimals = parseInt(
env.GAS_PRICE_ORACLE_DECIMALS || '6',
10
)
// The initial L1 base fee in the GasPriceOracle. This determines how
// expensive the L1 portion of the transaction fee is.
const gasPriceOracleL1BaseFee = parseInt(
env.GAS_PRICE_ORACLE_L1_BASE_FEE || '1',
10
)
// The initial L2 gas price set in the GasPriceOracle
const gasPriceOracleGasPrice = parseInt(
env.GAS_PRICE_ORACLE_GAS_PRICE || '1',
10
)
// The L2 block gas limit, used in the L2 block headers as well to limit
// the amount of execution for a single block.
const l2BlockGasLimit = parseInt(env.L2_BLOCK_GAS_LIMIT, 10)
// The L2 chain id, added to the chain config
const l2ChainId = parseInt(env.L2_CHAIN_ID, 10)
// The block signer address, added to the block extradata for clique consensus
const blockSignerAddress = env.BLOCK_SIGNER_ADDRESS
// The L1 standard bridge address for cross domain messaging
const l1StandardBridgeAddress = env.L1_STANDARD_BRIDGE_ADDRESS
// The L1 fee wallet address, used to restrict the account that fees on L2 can
// be withdrawn to on L1
const l1FeeWalletAddress = env.L1_FEE_WALLET_ADDRESS
// The L1 cross domain messenger address, used for cross domain messaging
const l1CrossDomainMessengerAddress = env.L1_CROSS_DOMAIN_MESSENGER_ADDRESS
// The block height at which the berlin hardfork activates
const berlinBlock = parseInt(env.BERLIN_BLOCK, 10) || 0
ensure(whitelistOwner, 'WHITELIST_OWNER')
ensure(gasPriceOracleOwner, 'GAS_PRICE_ORACLE_OWNER')
ensure(l2BlockGasLimit, 'L2_BLOCK_GAS_LIMIT')
ensure(l2ChainId, 'L2_CHAIN_ID')
ensure(blockSignerAddress, 'BLOCK_SIGNER_ADDRESS')
ensure(l1StandardBridgeAddress, 'L1_STANDARD_BRIDGE_ADDRESS')
ensure(l1FeeWalletAddress, 'L1_FEE_WALLET_ADDRESS')
ensure(l1CrossDomainMessengerAddress, 'L1_CROSS_DOMAIN_MESSENGER_ADDRESS')
ensure(berlinBlock, 'BERLIN_BLOCK')
// Basic warning so users know that the whitelist will be disabled if the owner is the zero address.
if (env.WHITELIST_OWNER === '0x' + '00'.repeat(20)) {
console.log(
'WARNING: whitelist owner is address(0), whitelist will be disabled'
)
}
const genesis = await makeL2GenesisFile({
whitelistOwner,
gasPriceOracleOwner,
gasPriceOracleOverhead,
gasPriceOracleScalar,
gasPriceOracleL1BaseFee,
gasPriceOracleGasPrice,
gasPriceOracleDecimals,
l2BlockGasLimit,
l2ChainId,
blockSignerAddress,
l1StandardBridgeAddress,
l1FeeWalletAddress,
l1CrossDomainMessengerAddress,
berlinBlock,
})
fs.writeFileSync(outfile, JSON.stringify(genesis, null, 4))
})()
import { DeployConfig } from '../src/deploy-config'
const config: DeployConfig = {
network: 'goerli',
l1BlockTimeSeconds: 15,
l2BlockGasLimit: 15_000_000,
l2ChainId: 420,
ctcL2GasDiscountDivisor: 32,
ctcEnqueueGasCost: 60_000,
sccFaultProofWindowSeconds: 604800,
sccSequencerPublishWindowSeconds: 12592000,
ovmSequencerAddress: '0xB79f76EF2c5F0286176833E7B2eEe103b1CC3244',
ovmProposerAddress: '0x9A2F243c605e6908D96b18e21Fb82Bf288B19EF3',
ovmBlockSignerAddress: '0x27770a9694e4B4b1E130Ab91Bc327C36855f612E',
ovmFeeWalletAddress: '0xB79f76EF2c5F0286176833E7B2eEe103b1CC3244',
ovmAddressManagerOwner: '0x32b70c156302d28A9119445d2bbb9ab1cBD01671',
ovmGasPriceOracleOwner: '0x84f70449f90300997840eCb0918873745Ede7aE6',
}
export default config
import { DeployConfig } from '../src/deploy-config'
const config: DeployConfig = {
network: 'kovan',
numDeployConfirmations: 1,
gasPrice: 5_000_000_000,
l1BlockTimeSeconds: 15,
l2BlockGasLimit: 15_000_000,
l2ChainId: 69,
ctcL2GasDiscountDivisor: 32,
ctcEnqueueGasCost: 60_000,
sccFaultProofWindowSeconds: 10,
sccSequencerPublishWindowSeconds: 12592000,
ovmSequencerAddress: '0xB79f76EF2c5F0286176833E7B2eEe103b1CC3244',
ovmProposerAddress: '0x9A2F243c605e6908D96b18e21Fb82Bf288B19EF3',
ovmBlockSignerAddress: '0x00000398232E2064F896018496b4b44b3D62751F',
ovmFeeWalletAddress: '0xB79f76EF2c5F0286176833E7B2eEe103b1CC3244',
ovmAddressManagerOwner: '0x18394B52d3Cb931dfA76F63251919D051953413d',
ovmGasPriceOracleOwner: '0x84f70449f90300997840eCb0918873745Ede7aE6',
}
export default config
import { DeployConfig } from '../src/deploy-config'
const config: DeployConfig = {
network: 'local',
l1BlockTimeSeconds: 15,
l2BlockGasLimit: 15_000_000,
l2ChainId: 987,
ctcL2GasDiscountDivisor: 32,
ctcEnqueueGasCost: 60_000,
sccFaultProofWindowSeconds: 0,
sccSequencerPublishWindowSeconds: 12592000,
ovmSequencerAddress: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
ovmProposerAddress: '0x3c44cdddb6a900fa2b585dd299e03d12fa4293bc',
ovmBlockSignerAddress: '0x00000398232E2064F896018496b4b44b3D62751F',
ovmFeeWalletAddress: '0x391716d440c151c42cdf1c95c1d83a5427bca52c',
ovmAddressManagerOwner: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
ovmGasPriceOracleOwner: '0x9965507d1a55bcc2695c58ba16fb37d819b0a4dc',
}
export default config
import { DeployConfig } from '../src/deploy-config'
const config: DeployConfig = {
network: 'mainnet',
numDeployConfirmations: 4,
gasPrice: 150_000_000_000,
l1BlockTimeSeconds: 15,
l2BlockGasLimit: 15_000_000,
l2ChainId: 10,
ctcL2GasDiscountDivisor: 32,
ctcEnqueueGasCost: 60_000,
sccFaultProofWindowSeconds: 604800,
sccSequencerPublishWindowSeconds: 12592000,
ovmSequencerAddress: '0x6887246668a3b87F54DeB3b94Ba47a6f63F32985',
ovmProposerAddress: '0x473300df21D047806A082244b417f96b32f13A33',
ovmBlockSignerAddress: '0x00000398232E2064F896018496b4b44b3D62751F',
ovmFeeWalletAddress: '0x391716d440c151c42cdf1c95c1d83a5427bca52c',
ovmAddressManagerOwner: '0x9BA6e03D8B90dE867373Db8cF1A58d2F7F006b3A',
ovmGasPriceOracleOwner: '0x7107142636C85c549690b1Aca12Bdb8052d26Ae6',
ovmWhitelistOwner: '0x648E3e8101BFaB7bf5997Bd007Fb473786019159',
}
export default config
...@@ -9,10 +9,12 @@ import { ...@@ -9,10 +9,12 @@ import {
sendImpersonatedTx, sendImpersonatedTx,
BIG_BALANCE, BIG_BALANCE,
} from '../src/deploy-utils' } from '../src/deploy-utils'
import { getDeployConfig } from '../src/deploy-config'
import { names } from '../src/address-names' import { names } from '../src/address-names'
const deployFn: DeployFunction = async (hre) => { const deployFn: DeployFunction = async (hre) => {
if ((hre as any).deployConfig.forked !== 'true') { const deployConfig = getDeployConfig(hre.network.name)
if (!deployConfig.isForkedNetwork) {
return return
} }
......
...@@ -2,18 +2,20 @@ ...@@ -2,18 +2,20 @@
import { DeployFunction } from 'hardhat-deploy/dist/types' import { DeployFunction } from 'hardhat-deploy/dist/types'
import { names } from '../src/address-names' import { names } from '../src/address-names'
import { getDeployConfig } from '../src/deploy-config'
/* Imports: External */ /* Imports: External */
const deployFn: DeployFunction = async (hre) => { const deployFn: DeployFunction = async (hre) => {
const { deploy } = hre.deployments const { deploy } = hre.deployments
const { deployer } = await hre.getNamedAccounts() const { deployer } = await hre.getNamedAccounts()
const deployConfig = getDeployConfig(hre.network.name)
await deploy(names.unmanaged.Lib_AddressManager, { await deploy(names.unmanaged.Lib_AddressManager, {
from: deployer, from: deployer,
args: [], args: [],
log: true, log: true,
waitConfirmations: (hre as any).deployConfig.numDeployConfirmations, waitConfirmations: deployConfig.numDeployConfirmations,
}) })
} }
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment