Commit 2e0320a8 authored by Andreas Bigger's avatar Andreas Bigger

fix nits

parents 1630ad33 51fb98aa
---
'@eth-optimism/common-ts': patch
---
Fixes a minor bug where the provider name was incorrectly logged when using waitForProvider
---
'@eth-optimism/contracts-bedrock': patch
---
Added a test for large deposit gaps
...@@ -422,6 +422,10 @@ jobs: ...@@ -422,6 +422,10 @@ jobs:
name: Check integration-tests name: Check integration-tests
command: npx depcheck command: npx depcheck
working_directory: integration-tests working_directory: integration-tests
- run:
name: Check two-step-monitor
command: npx depcheck
working_directory: packages/two-step-monitor
go-lint: go-lint:
parameters: parameters:
......
...@@ -35,6 +35,7 @@ ...@@ -35,6 +35,7 @@
/.github @ethereum-optimism/infra-reviewers /.github @ethereum-optimism/infra-reviewers
/ops @ethereum-optimism/infra-reviewers /ops @ethereum-optimism/infra-reviewers
/ops-bedrock @ethereum-optimism/infra-reviewers /ops-bedrock @ethereum-optimism/infra-reviewers
/op-signer @ethereum-optimism/infra-reviewers
# Misc # Misc
/proxyd @ethereum-optimism/infra-reviewers /proxyd @ethereum-optimism/infra-reviewers
......
...@@ -17,6 +17,7 @@ use ( ...@@ -17,6 +17,7 @@ use (
./op-node ./op-node
./op-proposer ./op-proposer
./op-service ./op-service
./op-signer
./op-wheel ./op-wheel
./packages/contracts-bedrock/test-case-generator ./packages/contracts-bedrock/test-case-generator
./proxyd ./proxyd
......
...@@ -166,6 +166,7 @@ github.com/ethereum-optimism/op-geth v0.0.0-20221104125741-d6c1bb9a110d h1:rDRvY ...@@ -166,6 +166,7 @@ github.com/ethereum-optimism/op-geth v0.0.0-20221104125741-d6c1bb9a110d h1:rDRvY
github.com/ethereum-optimism/op-geth v0.0.0-20221104125741-d6c1bb9a110d/go.mod h1:/6CsT5Ceen2WPLI/oCA3xMcZ5sWMF/D46SjM/ayY0Oo= github.com/ethereum-optimism/op-geth v0.0.0-20221104125741-d6c1bb9a110d/go.mod h1:/6CsT5Ceen2WPLI/oCA3xMcZ5sWMF/D46SjM/ayY0Oo=
github.com/ethereum-optimism/op-geth v0.0.0-20221215174217-c69b1f12761e h1:kdpBVWv7Rs/LbM8o8QyJlEBNiA2sw1GEhGyn4pkpesw= github.com/ethereum-optimism/op-geth v0.0.0-20221215174217-c69b1f12761e h1:kdpBVWv7Rs/LbM8o8QyJlEBNiA2sw1GEhGyn4pkpesw=
github.com/ethereum-optimism/op-geth v0.0.0-20221215174217-c69b1f12761e/go.mod h1:p0Yox74PhYlq1HvijrCBCD9A3cI7rXco7hT6KrQr+rY= github.com/ethereum-optimism/op-geth v0.0.0-20221215174217-c69b1f12761e/go.mod h1:p0Yox74PhYlq1HvijrCBCD9A3cI7rXco7hT6KrQr+rY=
github.com/ethereum-optimism/optimism/op-signer v0.1.0/go.mod h1:u8sN6X/c20pP9F1Ey7jH3fi19D08Y+T9ep3PGJfdyi8=
github.com/evanphx/json-patch v4.9.0+incompatible h1:kLcOMZeuLAJvL2BPWLMIj5oaZQobrkAqrL+WFZwQses= github.com/evanphx/json-patch v4.9.0+incompatible h1:kLcOMZeuLAJvL2BPWLMIj5oaZQobrkAqrL+WFZwQses=
github.com/fasthttp-contrib/websocket v0.0.0-20160511215533-1f3b11f56072 h1:DddqAaWDpywytcG8w/qoQ5sAN8X12d3Z3koB0C3Rxsc= github.com/fasthttp-contrib/websocket v0.0.0-20160511215533-1f3b11f56072 h1:DddqAaWDpywytcG8w/qoQ5sAN8X12d3Z3koB0C3Rxsc=
github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo= github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo=
...@@ -579,6 +580,7 @@ golang.org/x/net v0.0.0-20220630215102-69896b714898/go.mod h1:XRhObCWvk6IyKnWLug ...@@ -579,6 +580,7 @@ golang.org/x/net v0.0.0-20220630215102-69896b714898/go.mod h1:XRhObCWvk6IyKnWLug
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.0.0-20220812174116-3211cb980234/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= golang.org/x/net v0.0.0-20220812174116-3211cb980234/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
golang.org/x/net v0.0.0-20220923203811-8be639271d50/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= golang.org/x/net v0.0.0-20220923203811-8be639271d50/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
golang.org/x/net v0.0.0-20221014081412-f15817d10f9b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco=
golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=
golang.org/x/net v0.3.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE= golang.org/x/net v0.3.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE=
......
...@@ -30,10 +30,10 @@ ...@@ -30,10 +30,10 @@
"devDependencies": { "devDependencies": {
"@babel/eslint-parser": "^7.5.4", "@babel/eslint-parser": "^7.5.4",
"@eth-optimism/contracts": "^0.5.40", "@eth-optimism/contracts": "^0.5.40",
"@eth-optimism/contracts-bedrock": "0.11.2", "@eth-optimism/contracts-bedrock": "0.11.3",
"@eth-optimism/contracts-periphery": "^1.0.6", "@eth-optimism/contracts-periphery": "^1.0.7",
"@eth-optimism/core-utils": "0.12.0", "@eth-optimism/core-utils": "0.12.0",
"@eth-optimism/sdk": "1.10.0", "@eth-optimism/sdk": "1.10.1",
"@ethersproject/abstract-provider": "^5.7.0", "@ethersproject/abstract-provider": "^5.7.0",
"@ethersproject/providers": "^5.7.0", "@ethersproject/providers": "^5.7.0",
"@ethersproject/transactions": "^5.7.0", "@ethersproject/transactions": "^5.7.0",
......
# Changelog # Changelog
## 0.5.32
### Patch Changes
- ea817097b: Use default cas gap of 25 million
## 0.5.31 ## 0.5.31
### Patch Changes ### Patch Changes
......
...@@ -516,6 +516,7 @@ var ( ...@@ -516,6 +516,7 @@ var (
} }
RPCGlobalGasCap = cli.Uint64Flag{ RPCGlobalGasCap = cli.Uint64Flag{
Name: "rpc.gascap", Name: "rpc.gascap",
Value: eth.DefaultConfig.RPCGasCap.Uint64(),
Usage: "Sets a cap on gas that can be used in eth_call/estimateGas", Usage: "Sets a cap on gas that can be used in eth_call/estimateGas",
} }
RPCGlobalEVMTimeoutFlag = &cli.DurationFlag{ RPCGlobalEVMTimeoutFlag = &cli.DurationFlag{
......
...@@ -58,6 +58,7 @@ var DefaultConfig = Config{ ...@@ -58,6 +58,7 @@ var DefaultConfig = Config{
Recommit: 3 * time.Second, Recommit: 3 * time.Second,
}, },
TxPool: core.DefaultTxPoolConfig, TxPool: core.DefaultTxPoolConfig,
RPCGasCap: new(big.Int).SetUint64(25_000_000),
RPCEVMTimeout: 5 * time.Second, RPCEVMTimeout: 5 * time.Second,
GPO: gasprice.Config{ GPO: gasprice.Config{
Blocks: 20, Blocks: 20,
......
{ {
"name": "@eth-optimism/l2geth", "name": "@eth-optimism/l2geth",
"version": "0.5.31", "version": "0.5.32",
"private": true, "private": true,
"devDependencies": {} "devDependencies": {}
} }
...@@ -9,6 +9,7 @@ COPY ./op-node /app/op-node ...@@ -9,6 +9,7 @@ COPY ./op-node /app/op-node
COPY ./op-proposer /app/op-proposer COPY ./op-proposer /app/op-proposer
COPY ./op-service /app/op-service COPY ./op-service /app/op-service
COPY ./op-batcher /app/op-batcher COPY ./op-batcher /app/op-batcher
COPY ./op-signer /app/op-signer
COPY ./.git /app/.git COPY ./.git /app/.git
WORKDIR /app/op-batcher WORKDIR /app/op-batcher
......
...@@ -3,6 +3,7 @@ package batcher ...@@ -3,6 +3,7 @@ package batcher
import ( import (
"context" "context"
"fmt" "fmt"
"math/big"
_ "net/http/pprof" _ "net/http/pprof"
"os" "os"
"os/signal" "os/signal"
...@@ -13,6 +14,9 @@ import ( ...@@ -13,6 +14,9 @@ import (
opmetrics "github.com/ethereum-optimism/optimism/op-service/metrics" opmetrics "github.com/ethereum-optimism/optimism/op-service/metrics"
oppprof "github.com/ethereum-optimism/optimism/op-service/pprof" oppprof "github.com/ethereum-optimism/optimism/op-service/pprof"
oprpc "github.com/ethereum-optimism/optimism/op-service/rpc" oprpc "github.com/ethereum-optimism/optimism/op-service/rpc"
opsigner "github.com/ethereum-optimism/optimism/op-signer/client"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/urfave/cli" "github.com/urfave/cli"
) )
...@@ -36,10 +40,32 @@ func Main(version string) func(cliCtx *cli.Context) error { ...@@ -36,10 +40,32 @@ func Main(version string) func(cliCtx *cli.Context) error {
l := oplog.NewLogger(cfg.LogConfig) l := oplog.NewLogger(cfg.LogConfig)
l.Info("Initializing Batch Submitter") l.Info("Initializing Batch Submitter")
batchSubmitter, err := NewBatchSubmitter(cfg, l) var batchSubmitter *BatchSubmitter
if err != nil { if !cfg.SignerConfig.Enabled() {
l.Error("Unable to create Batch Submitter", "error", err) bs, err := NewBatchSubmitter(cfg, l)
return err if err != nil {
l.Error("Unable to create Batch Submitter", "error", err)
return err
}
batchSubmitter = bs
} else {
signerClient, err := opsigner.NewSignerClientFromConfig(l, cfg.SignerConfig)
if err != nil {
l.Error("Unable to create Signer Client", "error", err)
return err
}
signer := func(chainID *big.Int) SignerFn {
return func(ctx context.Context, rawTx types.TxData) (*types.Transaction, error) {
tx := types.NewTx(rawTx)
return signerClient.SignTransaction(ctx, chainID, tx)
}
}
bs, err := NewBatchSubmitterWithSigner(cfg, common.HexToAddress(cfg.SignerConfig.Address), signer, l)
if err != nil {
l.Error("Unable to create Batch Submitter with signer", "error", err)
return err
}
batchSubmitter = bs
} }
l.Info("Starting Batch Submitter") l.Info("Starting Batch Submitter")
......
...@@ -10,6 +10,7 @@ import ( ...@@ -10,6 +10,7 @@ import (
opmetrics "github.com/ethereum-optimism/optimism/op-service/metrics" opmetrics "github.com/ethereum-optimism/optimism/op-service/metrics"
oppprof "github.com/ethereum-optimism/optimism/op-service/pprof" oppprof "github.com/ethereum-optimism/optimism/op-service/pprof"
oprpc "github.com/ethereum-optimism/optimism/op-service/rpc" oprpc "github.com/ethereum-optimism/optimism/op-service/rpc"
opsigner "github.com/ethereum-optimism/optimism/op-signer/client"
) )
type Config struct { type Config struct {
...@@ -76,6 +77,9 @@ type Config struct { ...@@ -76,6 +77,9 @@ type Config struct {
MetricsConfig opmetrics.CLIConfig MetricsConfig opmetrics.CLIConfig
PprofConfig oppprof.CLIConfig PprofConfig oppprof.CLIConfig
// SignerConfig contains the client config for op-signer service
SignerConfig opsigner.CLIConfig
} }
func (c Config) Check() error { func (c Config) Check() error {
...@@ -91,6 +95,9 @@ func (c Config) Check() error { ...@@ -91,6 +95,9 @@ func (c Config) Check() error {
if err := c.PprofConfig.Check(); err != nil { if err := c.PprofConfig.Check(); err != nil {
return err return err
} }
if err := c.SignerConfig.Check(); err != nil {
return err
}
return nil return nil
} }
...@@ -116,5 +123,6 @@ func NewConfig(ctx *cli.Context) Config { ...@@ -116,5 +123,6 @@ func NewConfig(ctx *cli.Context) Config {
LogConfig: oplog.ReadCLIConfig(ctx), LogConfig: oplog.ReadCLIConfig(ctx),
MetricsConfig: opmetrics.ReadCLIConfig(ctx), MetricsConfig: opmetrics.ReadCLIConfig(ctx),
PprofConfig: oppprof.ReadCLIConfig(ctx), PprofConfig: oppprof.ReadCLIConfig(ctx),
SignerConfig: opsigner.ReadCLIConfig(ctx),
} }
} }
...@@ -163,7 +163,7 @@ func NewBatchSubmitterWithSigner(cfg Config, addr common.Address, signer SignerF ...@@ -163,7 +163,7 @@ func NewBatchSubmitterWithSigner(cfg Config, addr common.Address, signer SignerF
done: make(chan struct{}), done: make(chan struct{}),
log: l, log: l,
state: NewChannelManager(l, cfg.ChannelTimeout), state: NewChannelManager(l, cfg.ChannelTimeout),
// TODO: this context only exists because the even loop doesn't reach done // TODO: this context only exists because the event loop doesn't reach done
// if the tx manager is blocking forever due to e.g. insufficient balance. // if the tx manager is blocking forever due to e.g. insufficient balance.
ctx: ctx, ctx: ctx,
cancel: cancel, cancel: cancel,
......
...@@ -6,4 +6,5 @@ use ( ...@@ -6,4 +6,5 @@ use (
./op-node ./op-node
./op-proposer ./op-proposer
./op-service ./op-service
./op-signer
) )
...@@ -8,6 +8,7 @@ import ( ...@@ -8,6 +8,7 @@ import (
opmetrics "github.com/ethereum-optimism/optimism/op-service/metrics" opmetrics "github.com/ethereum-optimism/optimism/op-service/metrics"
oppprof "github.com/ethereum-optimism/optimism/op-service/pprof" oppprof "github.com/ethereum-optimism/optimism/op-service/pprof"
oprpc "github.com/ethereum-optimism/optimism/op-service/rpc" oprpc "github.com/ethereum-optimism/optimism/op-service/rpc"
opsigner "github.com/ethereum-optimism/optimism/op-signer/client"
) )
const envVarPrefix = "OP_BATCHER" const envVarPrefix = "OP_BATCHER"
...@@ -131,6 +132,7 @@ func init() { ...@@ -131,6 +132,7 @@ func init() {
optionalFlags = append(optionalFlags, oplog.CLIFlags(envVarPrefix)...) optionalFlags = append(optionalFlags, oplog.CLIFlags(envVarPrefix)...)
optionalFlags = append(optionalFlags, opmetrics.CLIFlags(envVarPrefix)...) optionalFlags = append(optionalFlags, opmetrics.CLIFlags(envVarPrefix)...)
optionalFlags = append(optionalFlags, oppprof.CLIFlags(envVarPrefix)...) optionalFlags = append(optionalFlags, oppprof.CLIFlags(envVarPrefix)...)
optionalFlags = append(optionalFlags, opsigner.CLIFlags(envVarPrefix)...)
Flags = append(requiredFlags, optionalFlags...) Flags = append(requiredFlags, optionalFlags...)
} }
......
...@@ -7,6 +7,7 @@ require ( ...@@ -7,6 +7,7 @@ require (
github.com/ethereum-optimism/optimism/op-node v0.10.10 github.com/ethereum-optimism/optimism/op-node v0.10.10
github.com/ethereum-optimism/optimism/op-proposer v0.10.10 github.com/ethereum-optimism/optimism/op-proposer v0.10.10
github.com/ethereum-optimism/optimism/op-service v0.10.10 github.com/ethereum-optimism/optimism/op-service v0.10.10
github.com/ethereum-optimism/optimism/op-signer v0.1.0
github.com/ethereum/go-ethereum v1.10.26 github.com/ethereum/go-ethereum v1.10.26
github.com/urfave/cli v1.22.9 github.com/urfave/cli v1.22.9
) )
...@@ -23,8 +24,10 @@ require ( ...@@ -23,8 +24,10 @@ require (
github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect
github.com/deckarep/golang-set v1.8.0 // indirect github.com/deckarep/golang-set v1.8.0 // indirect
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0 // indirect github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0 // indirect
github.com/dyson/certman v0.3.0 // indirect
github.com/ethereum-optimism/optimism/op-bindings v0.10.10 // indirect github.com/ethereum-optimism/optimism/op-bindings v0.10.10 // indirect
github.com/fjl/memsize v0.0.1 // indirect github.com/fjl/memsize v0.0.1 // indirect
github.com/fsnotify/fsnotify v1.6.0 // indirect
github.com/go-ole/go-ole v1.2.6 // indirect github.com/go-ole/go-ole v1.2.6 // indirect
github.com/go-stack/stack v1.8.1 // indirect github.com/go-stack/stack v1.8.1 // indirect
github.com/gogo/protobuf v1.3.2 // indirect github.com/gogo/protobuf v1.3.2 // indirect
...@@ -87,7 +90,7 @@ require ( ...@@ -87,7 +90,7 @@ require (
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect
github.com/yusufpapurcu/wmi v1.2.2 // indirect github.com/yusufpapurcu/wmi v1.2.2 // indirect
golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa // indirect golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa // indirect
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4 // indirect golang.org/x/sync v0.1.0 // indirect
golang.org/x/sys v0.0.0-20221013171732-95e765b1cc43 // indirect golang.org/x/sys v0.0.0-20221013171732-95e765b1cc43 // indirect
golang.org/x/term v0.0.0-20220722155259-a9ba230a4035 // indirect golang.org/x/term v0.0.0-20220722155259-a9ba230a4035 // indirect
google.golang.org/protobuf v1.28.1 // indirect google.golang.org/protobuf v1.28.1 // indirect
......
...@@ -98,6 +98,8 @@ github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0 h1:HbphB4TFFXpv7MNrT52FGrrgVXF1 ...@@ -98,6 +98,8 @@ github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0 h1:HbphB4TFFXpv7MNrT52FGrrgVXF1
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0/go.mod h1:DZGJHZMqrU4JJqFAWUS2UO1+lbSKsdiOoYi9Zzey7Fc= github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0/go.mod h1:DZGJHZMqrU4JJqFAWUS2UO1+lbSKsdiOoYi9Zzey7Fc=
github.com/decred/dcrd/lru v1.0.0/go.mod h1:mxKOwFd7lFjN2GZYsiz/ecgqR6kkYAl+0pz0tEMk218= github.com/decred/dcrd/lru v1.0.0/go.mod h1:mxKOwFd7lFjN2GZYsiz/ecgqR6kkYAl+0pz0tEMk218=
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
github.com/dyson/certman v0.3.0 h1:S7WCUim5faT/OiBhiY3u5cMaiC9MNKiA+8PJDXLaIYQ=
github.com/dyson/certman v0.3.0/go.mod h1:RMWlyA9op6D9SxOBRRX3sxnParehv9gf52WWUJPd1JA=
github.com/edsrzf/mmap-go v1.1.0 h1:6EUwBLQ/Mcr1EYLE4Tn1VdW1A4ckqCQWZBw8Hr0kjpQ= github.com/edsrzf/mmap-go v1.1.0 h1:6EUwBLQ/Mcr1EYLE4Tn1VdW1A4ckqCQWZBw8Hr0kjpQ=
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.0/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/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
...@@ -115,12 +117,15 @@ github.com/ethereum-optimism/optimism/op-proposer v0.10.10 h1:VOpHt1T/CnaYhjbhj/ ...@@ -115,12 +117,15 @@ github.com/ethereum-optimism/optimism/op-proposer v0.10.10 h1:VOpHt1T/CnaYhjbhj/
github.com/ethereum-optimism/optimism/op-proposer v0.10.10/go.mod h1:oRPWIlr9DsVT4iNHmXs1AVhUYlU6I9GZ50YqnKcADWc= github.com/ethereum-optimism/optimism/op-proposer v0.10.10/go.mod h1:oRPWIlr9DsVT4iNHmXs1AVhUYlU6I9GZ50YqnKcADWc=
github.com/ethereum-optimism/optimism/op-service v0.10.10 h1:B5mGpATX6zPkDABoh6smCjh6Z5mA2KWh71MD1i6T5ww= github.com/ethereum-optimism/optimism/op-service v0.10.10 h1:B5mGpATX6zPkDABoh6smCjh6Z5mA2KWh71MD1i6T5ww=
github.com/ethereum-optimism/optimism/op-service v0.10.10/go.mod h1:wbtHqi1fv00B3agj7a2zdP3OFanEfGZ23zPgGgFCF/c= github.com/ethereum-optimism/optimism/op-service v0.10.10/go.mod h1:wbtHqi1fv00B3agj7a2zdP3OFanEfGZ23zPgGgFCF/c=
github.com/ethereum-optimism/optimism/op-signer v0.1.0 h1:wH44Deai43YQWO0pEd44pDm3BahdAtSmrOHKiPvTB8Y=
github.com/ethereum-optimism/optimism/op-signer v0.1.0/go.mod h1:u8sN6X/c20pP9F1Ey7jH3fi19D08Y+T9ep3PGJfdyi8=
github.com/fjl/memsize v0.0.1 h1:+zhkb+dhUgx0/e+M8sF0QqiouvMQUiKR+QYvdxIOKcQ= github.com/fjl/memsize v0.0.1 h1:+zhkb+dhUgx0/e+M8sF0QqiouvMQUiKR+QYvdxIOKcQ=
github.com/fjl/memsize v0.0.1/go.mod h1:VvhXpOYNQvB+uIk2RvXzuaQtkQJzzIx6lSBe1xv7hi0= github.com/fjl/memsize v0.0.1/go.mod h1:VvhXpOYNQvB+uIk2RvXzuaQtkQJzzIx6lSBe1xv7hi0=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
github.com/fsnotify/fsnotify v1.5.4 h1:jRbGcIw6P2Meqdwuo0H1p6JVLbL5DHKAKlYndzMwVZI=
github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU= github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU=
github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY=
github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw=
github.com/gballet/go-libpcsclite v0.0.0-20191108122812-4678299bea08 h1:f6D9Hr8xV8uYKlyuj8XIruxlh9WjVjdh1gIicAS7ays= github.com/gballet/go-libpcsclite v0.0.0-20191108122812-4678299bea08 h1:f6D9Hr8xV8uYKlyuj8XIruxlh9WjVjdh1gIicAS7ays=
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
...@@ -521,8 +526,8 @@ golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJ ...@@ -521,8 +526,8 @@ golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4 h1:uVc8UZUe6tr40fFVnUP5Oj+veunVezqYl9z7DYw9xzw= golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
...@@ -580,6 +585,7 @@ golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBc ...@@ -580,6 +585,7 @@ golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20221013171732-95e765b1cc43 h1:OK7RB6t2WQX54srQQYSXMW8dF5C6/8+oA/s5QBmmto4= golang.org/x/sys v0.0.0-20221013171732-95e765b1cc43 h1:OK7RB6t2WQX54srQQYSXMW8dF5C6/8+oA/s5QBmmto4=
golang.org/x/sys v0.0.0-20221013171732-95e765b1cc43/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20221013171732-95e765b1cc43/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
......
This diff is collapsed.
This diff is collapsed.
...@@ -76,6 +76,7 @@ func (h *Hardhat) init() error { ...@@ -76,6 +76,7 @@ func (h *Hardhat) init() error {
// initDeployments reads all of the deployment json files from disk and then // initDeployments reads all of the deployment json files from disk and then
// caches the deserialized `Deployment` structs. // caches the deserialized `Deployment` structs.
func (h *Hardhat) initDeployments() error { func (h *Hardhat) initDeployments() error {
knownDeployments := make(map[string]string)
for _, deploymentPath := range h.DeploymentPaths { for _, deploymentPath := range h.DeploymentPaths {
fileSystem := os.DirFS(filepath.Join(deploymentPath, h.network)) fileSystem := os.DirFS(filepath.Join(deploymentPath, h.network))
err := fs.WalkDir(fileSystem, ".", func(path string, d fs.DirEntry, err error) error { err := fs.WalkDir(fileSystem, ".", func(path string, d fs.DirEntry, err error) error {
...@@ -103,7 +104,16 @@ func (h *Hardhat) initDeployments() error { ...@@ -103,7 +104,16 @@ func (h *Hardhat) initDeployments() error {
} }
deployment.Name = filepath.Base(name[:len(name)-5]) deployment.Name = filepath.Base(name[:len(name)-5])
if knownDeployments[deployment.Name] != "" {
return fmt.Errorf(
"discovered duplicate deployment %s. old: %s, new: %s",
deployment.Name,
knownDeployments[deployment.Name],
name,
)
}
h.deployments = append(h.deployments, &deployment) h.deployments = append(h.deployments, &deployment)
knownDeployments[deployment.Name] = name
return nil return nil
}) })
if err != nil { if err != nil {
......
...@@ -146,6 +146,20 @@ func TestHardhatGetDeployments(t *testing.T) { ...@@ -146,6 +146,20 @@ func TestHardhatGetDeployments(t *testing.T) {
require.NotNil(t, deployment) require.NotNil(t, deployment)
} }
func TestHardhatGetDeploymentsDuplicates(t *testing.T) {
t.Parallel()
// Set the network to an empty string to simulate
// an invalid network name.
_, err := hardhat.New(
"",
[]string{"testdata/artifacts"},
[]string{"testdata/deployments"},
)
require.Error(t, err)
require.Contains(t, err.Error(), "duplicate deployment")
}
func TestHardhatGetStorageLayout(t *testing.T) { func TestHardhatGetStorageLayout(t *testing.T) {
t.Parallel() t.Parallel()
......
...@@ -170,3 +170,17 @@ func (w *LegacyWithdrawal) Value() (*big.Int, error) { ...@@ -170,3 +170,17 @@ func (w *LegacyWithdrawal) Value() (*big.Int, error) {
return value, nil return value, nil
} }
// CrossDomainMessage turns the LegacyWithdrawal into
// a CrossDomainMessage. LegacyWithdrawals do not have
// the concept of value or gaslimit, so set them to 0.
func (w *LegacyWithdrawal) CrossDomainMessage() *CrossDomainMessage {
return &CrossDomainMessage{
Nonce: w.Nonce,
Sender: w.Sender,
Target: w.Target,
Value: new(big.Int),
GasLimit: new(big.Int),
Data: []byte(w.Data),
}
}
...@@ -9,7 +9,6 @@ import ( ...@@ -9,7 +9,6 @@ import (
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
) )
...@@ -29,7 +28,7 @@ var ( ...@@ -29,7 +28,7 @@ var (
} }
) )
func MigrateLegacyETH(ldb ethdb.Database, db *state.StateDB, addresses []common.Address, chainID int, noCheck bool) error { func MigrateLegacyETH(db *state.StateDB, addresses []common.Address, chainID int, noCheck bool) error {
// Chain params to use for integrity checking. // Chain params to use for integrity checking.
params := migration.ParamsByChainID[chainID] params := migration.ParamsByChainID[chainID]
if params == nil { if params == nil {
......
...@@ -8,7 +8,6 @@ import ( ...@@ -8,7 +8,6 @@ import (
"github.com/ethereum-optimism/optimism/op-chain-ops/genesis/migration" "github.com/ethereum-optimism/optimism/op-chain-ops/genesis/migration"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
...@@ -31,6 +30,8 @@ func PreCheckBalances(ldb ethdb.Database, db *state.StateDB, addresses []common. ...@@ -31,6 +30,8 @@ func PreCheckBalances(ldb ethdb.Database, db *state.StateDB, addresses []common.
slotsInp := make(map[common.Hash]int) slotsInp := make(map[common.Hash]int)
// For each known address, compute its balance key and add it to the list of addresses. // For each known address, compute its balance key and add it to the list of addresses.
// Mint events are instrumented as regular ETH events in the witness data, so we no longer
// need to iterate over mint events during the migration.
for _, addr := range addresses { for _, addr := range addresses {
addrs = append(addrs, addr) addrs = append(addrs, addr)
slotsInp[CalcOVMETHStorageKey(addr)] = 1 slotsInp[CalcOVMETHStorageKey(addr)] = 1
...@@ -48,28 +49,11 @@ func PreCheckBalances(ldb ethdb.Database, db *state.StateDB, addresses []common. ...@@ -48,28 +49,11 @@ func PreCheckBalances(ldb ethdb.Database, db *state.StateDB, addresses []common.
addrs = append(addrs, sequencerEntrypointAddr) addrs = append(addrs, sequencerEntrypointAddr)
slotsInp[CalcOVMETHStorageKey(sequencerEntrypointAddr)] = 1 slotsInp[CalcOVMETHStorageKey(sequencerEntrypointAddr)] = 1
// Also extract addresses/slots from Mint events. Our instrumentation currently only looks at
// direct balance changes inside of Geth, but Mint events mutate the ERC20 storage directly and
// therefore aren't picked up by our instrumentation. Instead of updating the instrumentation,
// we can simply iterate over every Mint event and add the address to the list of addresses.
log.Info("Reading mint events from DB")
headBlock := rawdb.ReadHeadBlock(ldb)
logProgress := ProgressLogger(100, "read mint events")
err := IterateMintEvents(ldb, headBlock.NumberU64(), func(address common.Address, headNum uint64) error {
addrs = append(addrs, address)
slotsInp[CalcOVMETHStorageKey(address)] = 1
logProgress("headnum", headNum)
return nil
})
if err != nil {
return nil, wrapErr(err, "error reading mint events")
}
// Build a mapping of every storage slot in the LegacyERC20ETH contract, except the list of // Build a mapping of every storage slot in the LegacyERC20ETH contract, except the list of
// slots that we know we can ignore (totalSupply, name, symbol). // slots that we know we can ignore (totalSupply, name, symbol).
var count int var count int
slotsAct := make(map[common.Hash]common.Hash) slotsAct := make(map[common.Hash]common.Hash)
err = db.ForEachStorage(predeploys.LegacyERC20ETHAddr, func(key, value common.Hash) bool { err := db.ForEachStorage(predeploys.LegacyERC20ETHAddr, func(key, value common.Hash) bool {
// We can safely ignore specific slots (totalSupply, name, symbol). // We can safely ignore specific slots (totalSupply, name, symbol).
if ignoredSlots[key] { if ignoredSlots[key] {
return true return true
......
package ether package ether
import ( import (
"fmt"
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
) )
func wrapErr(err error, msg string, ctx ...any) error {
return fmt.Errorf("%s: %w", fmt.Sprintf(msg, ctx...), err)
}
func ProgressLogger(n int, msg string) func(...any) { func ProgressLogger(n int, msg string) func(...any) {
var i int var i int
......
...@@ -119,6 +119,11 @@ func PostCheckMigratedDB( ...@@ -119,6 +119,11 @@ func PostCheckMigratedDB(
Preimages: true, Preimages: true,
}) })
prevDB, err := state.New(prevHeader.Root, underlyingDB, nil)
if err != nil {
return fmt.Errorf("cannot open historical StateDB: %w", err)
}
db, err := state.New(header.Root, underlyingDB, nil) db, err := state.New(header.Root, underlyingDB, nil)
if err != nil { if err != nil {
return fmt.Errorf("cannot open StateDB: %w", err) return fmt.Errorf("cannot open StateDB: %w", err)
...@@ -134,7 +139,7 @@ func PostCheckMigratedDB( ...@@ -134,7 +139,7 @@ func PostCheckMigratedDB(
} }
log.Info("checked untouchables") log.Info("checked untouchables")
if err := PostCheckPredeploys(db); err != nil { if err := PostCheckPredeploys(prevDB, db); err != nil {
return err return err
} }
log.Info("checked predeploys") log.Info("checked predeploys")
...@@ -209,13 +214,13 @@ func PostCheckUntouchables(udb state.Database, currDB *state.StateDB, prevRoot c ...@@ -209,13 +214,13 @@ func PostCheckUntouchables(udb state.Database, currDB *state.StateDB, prevRoot c
// PostCheckPredeploys will check that there is code at each predeploy // PostCheckPredeploys will check that there is code at each predeploy
// address // address
func PostCheckPredeploys(db *state.StateDB) error { func PostCheckPredeploys(prevDB, currDB *state.StateDB) error {
for i := uint64(0); i <= 2048; i++ { for i := uint64(0); i <= 2048; i++ {
// Compute the predeploy address // Compute the predeploy address
bigAddr := new(big.Int).Or(bigL2PredeployNamespace, new(big.Int).SetUint64(i)) bigAddr := new(big.Int).Or(bigL2PredeployNamespace, new(big.Int).SetUint64(i))
addr := common.BigToAddress(bigAddr) addr := common.BigToAddress(bigAddr)
// Get the code for the predeploy // Get the code for the predeploy
code := db.GetCode(addr) code := currDB.GetCode(addr)
// There must be code for the predeploy // There must be code for the predeploy
if len(code) == 0 { if len(code) == 0 {
return fmt.Errorf("no code found at predeploy %s", addr) return fmt.Errorf("no code found at predeploy %s", addr)
...@@ -227,11 +232,23 @@ func PostCheckPredeploys(db *state.StateDB) error { ...@@ -227,11 +232,23 @@ func PostCheckPredeploys(db *state.StateDB) error {
} }
// There must be an admin // There must be an admin
admin := db.GetState(addr, AdminSlot) admin := currDB.GetState(addr, AdminSlot)
adminAddr := common.BytesToAddress(admin.Bytes()) adminAddr := common.BytesToAddress(admin.Bytes())
if addr != predeploys.ProxyAdminAddr && addr != predeploys.GovernanceTokenAddr && adminAddr != predeploys.ProxyAdminAddr { if addr != predeploys.ProxyAdminAddr && addr != predeploys.GovernanceTokenAddr && adminAddr != predeploys.ProxyAdminAddr {
return fmt.Errorf("expected admin for %s to be %s but got %s", addr, predeploys.ProxyAdminAddr, adminAddr) return fmt.Errorf("expected admin for %s to be %s but got %s", addr, predeploys.ProxyAdminAddr, adminAddr)
} }
// Balances and nonces should match legacy
oldNonce := prevDB.GetNonce(addr)
oldBalance := prevDB.GetBalance(addr)
newNonce := currDB.GetNonce(addr)
newBalance := currDB.GetBalance(addr)
if oldNonce != newNonce {
return fmt.Errorf("expected nonce for %s to be %d but got %d", addr, oldNonce, newNonce)
}
if oldBalance.Cmp(newBalance) != 0 {
return fmt.Errorf("expected balance for %s to be %d but got %d", addr, oldBalance, newBalance)
}
} }
// For each predeploy, check that we've set the implementation correctly when // For each predeploy, check that we've set the implementation correctly when
...@@ -248,7 +265,7 @@ func PostCheckPredeploys(db *state.StateDB) error { ...@@ -248,7 +265,7 @@ func PostCheckPredeploys(db *state.StateDB) error {
} }
if *proxyAddr == predeploys.ProxyAdminAddr { if *proxyAddr == predeploys.ProxyAdminAddr {
implCode := db.GetCode(*proxyAddr) implCode := currDB.GetCode(*proxyAddr)
if len(implCode) == 0 { if len(implCode) == 0 {
return errors.New("no code found at proxy admin") return errors.New("no code found at proxy admin")
} }
...@@ -260,12 +277,12 @@ func PostCheckPredeploys(db *state.StateDB) error { ...@@ -260,12 +277,12 @@ func PostCheckPredeploys(db *state.StateDB) error {
return fmt.Errorf("error converting to code namespace: %w", err) return fmt.Errorf("error converting to code namespace: %w", err)
} }
implCode := db.GetCode(expImplAddr) implCode := currDB.GetCode(expImplAddr)
if len(implCode) == 0 { if len(implCode) == 0 {
return fmt.Errorf("no code found at predeploy impl %s", *proxyAddr) return fmt.Errorf("no code found at predeploy impl %s", *proxyAddr)
} }
impl := db.GetState(*proxyAddr, ImplementationSlot) impl := currDB.GetState(*proxyAddr, ImplementationSlot)
actImplAddr := common.BytesToAddress(impl.Bytes()) actImplAddr := common.BytesToAddress(impl.Bytes())
if expImplAddr != actImplAddr { if expImplAddr != actImplAddr {
return fmt.Errorf("expected implementation for %s to be at %s, but got %s", *proxyAddr, expImplAddr, actImplAddr) return fmt.Errorf("expected implementation for %s to be at %s, but got %s", *proxyAddr, expImplAddr, actImplAddr)
......
...@@ -193,7 +193,7 @@ func MigrateDB(ldb ethdb.Database, config *DeployConfig, l1Block *types.Block, m ...@@ -193,7 +193,7 @@ func MigrateDB(ldb ethdb.Database, config *DeployConfig, l1Block *types.Block, m
// Finally we migrate the balances held inside the LegacyERC20ETH contract into the state trie. // Finally we migrate the balances held inside the LegacyERC20ETH contract into the state trie.
// Note that we do NOT delete the balances from the LegacyERC20ETH contract. // Note that we do NOT delete the balances from the LegacyERC20ETH contract.
log.Info("Starting to migrate ERC20 ETH") log.Info("Starting to migrate ERC20 ETH")
err = ether.MigrateLegacyETH(ldb, db, addrs, int(config.L1ChainID), noCheck) err = ether.MigrateLegacyETH(db, addrs, int(config.L1ChainID), noCheck)
if err != nil { if err != nil {
return nil, fmt.Errorf("cannot migrate legacy eth: %w", err) return nil, fmt.Errorf("cannot migrate legacy eth: %w", err)
} }
......
...@@ -92,7 +92,17 @@ func WipePredeployStorage(db vm.StateDB) error { ...@@ -92,7 +92,17 @@ func WipePredeployStorage(db vm.StateDB) error {
} }
log.Info("wiping storage", "name", name, "address", *addr) log.Info("wiping storage", "name", name, "address", *addr)
// We need to make sure that we preserve nonces.
oldNonce := db.GetNonce(*addr)
oldBalance := db.GetBalance(*addr)
db.CreateAccount(*addr) db.CreateAccount(*addr)
if oldNonce > 0 {
db.SetNonce(*addr, oldNonce)
}
if oldBalance.Cmp(common.Big0) != 0 {
db.AddBalance(*addr, oldBalance)
}
} }
return nil return nil
......
...@@ -4,6 +4,7 @@ import ( ...@@ -4,6 +4,7 @@ import (
"context" "context"
"crypto/ecdsa" "crypto/ecdsa"
"math/big" "math/big"
"time"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
...@@ -14,6 +15,7 @@ import ( ...@@ -14,6 +15,7 @@ import (
"github.com/ethereum-optimism/optimism/op-node/sources" "github.com/ethereum-optimism/optimism/op-node/sources"
"github.com/ethereum-optimism/optimism/op-proposer/proposer" "github.com/ethereum-optimism/optimism/op-proposer/proposer"
"github.com/ethereum-optimism/optimism/op-proposer/txmgr"
opcrypto "github.com/ethereum-optimism/optimism/op-service/crypto" opcrypto "github.com/ethereum-optimism/optimism/op-service/crypto"
) )
...@@ -26,28 +28,41 @@ type ProposerCfg struct { ...@@ -26,28 +28,41 @@ type ProposerCfg struct {
type L2Proposer struct { type L2Proposer struct {
log log.Logger log log.Logger
l1 *ethclient.Client l1 *ethclient.Client
driver *proposer.Driver driver *proposer.L2OutputSubmitter
address common.Address address common.Address
lastTx common.Hash lastTx common.Hash
} }
func NewL2Proposer(t Testing, log log.Logger, cfg *ProposerCfg, l1 *ethclient.Client, rollupCl *sources.RollupClient) *L2Proposer { func NewL2Proposer(t Testing, log log.Logger, cfg *ProposerCfg, l1 *ethclient.Client, rollupCl *sources.RollupClient) *L2Proposer {
chainID, err := l1.ChainID(t.Ctx()) signer := func(chainID *big.Int) proposer.SignerFn {
require.NoError(t, err) s := opcrypto.PrivateKeySignerFn(cfg.ProposerKey, chainID)
signer := opcrypto.PrivateKeySignerFn(cfg.ProposerKey, chainID) return func(_ context.Context, addr common.Address, tx *types.Transaction) (*types.Transaction, error) {
dr, err := proposer.NewDriver(proposer.DriverConfig{ return s(addr, tx)
Log: log, }
Name: "proposer", }
from := crypto.PubkeyToAddress(cfg.ProposerKey.PublicKey)
proposerCfg := proposer.Config{
L2OutputOracleAddr: cfg.OutputOracleAddr,
PollInterval: time.Second,
TxManagerConfig: txmgr.Config{
Log: log,
Name: "action-proposer",
ResubmissionTimeout: 5 * time.Second,
ReceiptQueryInterval: time.Second,
NumConfirmations: 1,
SafeAbortNonceTooLowCount: 4,
},
L1Client: l1, L1Client: l1,
RollupClient: rollupCl, RollupClient: rollupCl,
AllowNonFinalized: cfg.AllowNonFinalized, AllowNonFinalized: cfg.AllowNonFinalized,
L2OOAddr: cfg.OutputOracleAddr, From: from,
From: crypto.PubkeyToAddress(cfg.ProposerKey.PublicKey), SignerFnFactory: signer,
SignerFn: func(_ context.Context, addr common.Address, tx *types.Transaction) (*types.Transaction, error) { }
return signer(addr, tx)
}, dr, err := proposer.NewL2OutputSubmitterWithSigner(proposerCfg, log)
})
require.NoError(t, err) require.NoError(t, err)
return &L2Proposer{ return &L2Proposer{
log: log, log: log,
l1: l1, l1: l1,
...@@ -57,25 +72,24 @@ func NewL2Proposer(t Testing, log log.Logger, cfg *ProposerCfg, l1 *ethclient.Cl ...@@ -57,25 +72,24 @@ func NewL2Proposer(t Testing, log log.Logger, cfg *ProposerCfg, l1 *ethclient.Cl
} }
func (p *L2Proposer) CanPropose(t Testing) bool { func (p *L2Proposer) CanPropose(t Testing) bool {
start, end, err := p.driver.GetBlockRange(t.Ctx()) _, shouldPropose, err := p.driver.FetchNextOutputInfo(t.Ctx())
require.NoError(t, err) require.NoError(t, err)
return start.Cmp(end) < 0 return shouldPropose
} }
func (p *L2Proposer) ActMakeProposalTx(t Testing) { func (p *L2Proposer) ActMakeProposalTx(t Testing) {
start, end, err := p.driver.GetBlockRange(t.Ctx()) output, shouldPropose, err := p.driver.FetchNextOutputInfo(t.Ctx())
require.NoError(t, err) if !shouldPropose {
if start.Cmp(end) == 0 { return
t.InvalidAction("nothing to propose, block range starts and ends at %s", start.String())
} }
nonce, err := p.l1.PendingNonceAt(t.Ctx(), p.address)
require.NoError(t, err) require.NoError(t, err)
tx, err := p.driver.CraftTx(t.Ctx(), start, end, new(big.Int).SetUint64(nonce)) tx, err := p.driver.CreateProposalTx(t.Ctx(), output)
require.NoError(t, err) require.NoError(t, err)
err = p.driver.SendTransaction(t.Ctx(), tx) err = p.driver.SendTransaction(t.Ctx(), tx)
require.NoError(t, err) require.NoError(t, err)
p.lastTx = tx.Hash() p.lastTx = tx.Hash()
} }
......
...@@ -113,6 +113,14 @@ func (s *l2VerifierBackend) ResetDerivationPipeline(ctx context.Context) error { ...@@ -113,6 +113,14 @@ func (s *l2VerifierBackend) ResetDerivationPipeline(ctx context.Context) error {
return nil return nil
} }
func (s *l2VerifierBackend) StartSequencer(ctx context.Context, blockHash common.Hash) error {
return nil
}
func (s *l2VerifierBackend) StopSequencer(ctx context.Context) (common.Hash, error) {
return common.Hash{}, errors.New("stopping the L2Verifier sequencer is not supported")
}
func (s *L2Verifier) L2Finalized() eth.L2BlockRef { func (s *L2Verifier) L2Finalized() eth.L2BlockRef {
return s.derivation.Finalized() return s.derivation.Finalized()
} }
......
...@@ -342,7 +342,7 @@ func TestMigration(t *testing.T) { ...@@ -342,7 +342,7 @@ func TestMigration(t *testing.T) {
batcher.Stop() batcher.Stop()
}) })
proposer, err := l2os.NewL2OutputSubmitter(l2os.Config{ proposer, err := l2os.NewL2OutputSubmitter(l2os.CLIConfig{
L1EthRpc: forkedL1URL, L1EthRpc: forkedL1URL,
RollupRpc: rollupNode.HTTPEndpoint(), RollupRpc: rollupNode.HTTPEndpoint(),
L2OOAddress: l2OS.Address.String(), L2OOAddress: l2OS.Address.String(),
...@@ -356,7 +356,7 @@ func TestMigration(t *testing.T) { ...@@ -356,7 +356,7 @@ func TestMigration(t *testing.T) {
Format: "text", Format: "text",
}, },
PrivateKey: hexPriv(secrets.Proposer), PrivateKey: hexPriv(secrets.Proposer),
}, "", lgr.New("module", "proposer")) }, lgr.New("module", "proposer"))
require.NoError(t, err) require.NoError(t, err)
t.Cleanup(func() { t.Cleanup(func() {
proposer.Stop() proposer.Stop()
......
...@@ -498,7 +498,7 @@ func (cfg SystemConfig) Start() (*System, error) { ...@@ -498,7 +498,7 @@ func (cfg SystemConfig) Start() (*System, error) {
} }
// L2Output Submitter // L2Output Submitter
sys.L2OutputSubmitter, err = l2os.NewL2OutputSubmitter(l2os.Config{ sys.L2OutputSubmitter, err = l2os.NewL2OutputSubmitter(l2os.CLIConfig{
L1EthRpc: sys.Nodes["l1"].WSEndpoint(), L1EthRpc: sys.Nodes["l1"].WSEndpoint(),
RollupRpc: sys.RollupNodes["sequencer"].HTTPEndpoint(), RollupRpc: sys.RollupNodes["sequencer"].HTTPEndpoint(),
L2OOAddress: predeploys.DevL2OutputOracleAddr.String(), L2OOAddress: predeploys.DevL2OutputOracleAddr.String(),
...@@ -512,7 +512,7 @@ func (cfg SystemConfig) Start() (*System, error) { ...@@ -512,7 +512,7 @@ func (cfg SystemConfig) Start() (*System, error) {
Format: "text", Format: "text",
}, },
PrivateKey: hexPriv(cfg.Secrets.Proposer), PrivateKey: hexPriv(cfg.Secrets.Proposer),
}, "", sys.cfg.Loggers["proposer"]) }, sys.cfg.Loggers["proposer"])
if err != nil { if err != nil {
return nil, fmt.Errorf("unable to setup l2 output submitter: %w", err) return nil, fmt.Errorf("unable to setup l2 output submitter: %w", err)
} }
......
...@@ -1129,6 +1129,58 @@ func TestFees(t *testing.T) { ...@@ -1129,6 +1129,58 @@ func TestFees(t *testing.T) {
require.Equal(t, balanceDiff, totalFee, "balances should add up") require.Equal(t, balanceDiff, totalFee, "balances should add up")
} }
func TestStopStartSequencer(t *testing.T) {
parallel(t)
if !verboseGethNodes {
log.Root().SetHandler(log.DiscardHandler())
}
cfg := DefaultSystemConfig(t)
sys, err := cfg.Start()
require.Nil(t, err, "Error starting up system")
defer sys.Close()
l2Seq := sys.Clients["sequencer"]
rollupNode := sys.RollupNodes["sequencer"]
nodeRPC, err := rpc.DialContext(context.Background(), rollupNode.HTTPEndpoint())
require.Nil(t, err, "Error dialing node")
blockBefore := latestBlock(t, l2Seq)
time.Sleep(time.Duration(cfg.DeployConfig.L2BlockTime+1) * time.Second)
blockAfter := latestBlock(t, l2Seq)
require.Greaterf(t, blockAfter, blockBefore, "Chain did not advance")
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
blockHash := common.Hash{}
err = nodeRPC.CallContext(ctx, &blockHash, "admin_stopSequencer")
require.Nil(t, err, "Error stopping sequencer")
blockBefore = latestBlock(t, l2Seq)
time.Sleep(time.Duration(cfg.DeployConfig.L2BlockTime+1) * time.Second)
blockAfter = latestBlock(t, l2Seq)
require.Equal(t, blockAfter, blockBefore, "Chain advanced after stopping sequencer")
ctx, cancel = context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
err = nodeRPC.CallContext(ctx, nil, "admin_startSequencer", blockHash)
require.Nil(t, err, "Error starting sequencer")
blockBefore = latestBlock(t, l2Seq)
time.Sleep(time.Duration(cfg.DeployConfig.L2BlockTime+1) * time.Second)
blockAfter = latestBlock(t, l2Seq)
require.Greater(t, blockAfter, blockBefore, "Chain did not advance after starting sequencer")
}
func safeAddBig(a *big.Int, b *big.Int) *big.Int { func safeAddBig(a *big.Int, b *big.Int) *big.Int {
return new(big.Int).Add(a, b) return new(big.Int).Add(a, b)
} }
func latestBlock(t *testing.T, client *ethclient.Client) uint64 {
ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second)
defer cancel()
blockAfter, err := client.BlockNumber(ctx)
require.Nil(t, err, "Error getting latest block")
return blockAfter
}
...@@ -3,16 +3,17 @@ package main ...@@ -3,16 +3,17 @@ package main
import ( import (
"context" "context"
"net" "net"
"net/http"
"os" "os"
"os/signal" "os/signal"
"strconv"
"syscall" "syscall"
"time"
"github.com/ethereum-optimism/optimism/op-node/cmd/doc" "github.com/ethereum-optimism/optimism/op-node/cmd/doc"
"github.com/urfave/cli" "github.com/urfave/cli"
"github.com/ethereum/go-ethereum/log"
opnode "github.com/ethereum-optimism/optimism/op-node" opnode "github.com/ethereum-optimism/optimism/op-node"
"github.com/ethereum-optimism/optimism/op-node/cmd/genesis" "github.com/ethereum-optimism/optimism/op-node/cmd/genesis"
"github.com/ethereum-optimism/optimism/op-node/cmd/p2p" "github.com/ethereum-optimism/optimism/op-node/cmd/p2p"
...@@ -21,7 +22,7 @@ import ( ...@@ -21,7 +22,7 @@ import (
"github.com/ethereum-optimism/optimism/op-node/metrics" "github.com/ethereum-optimism/optimism/op-node/metrics"
"github.com/ethereum-optimism/optimism/op-node/node" "github.com/ethereum-optimism/optimism/op-node/node"
"github.com/ethereum-optimism/optimism/op-node/version" "github.com/ethereum-optimism/optimism/op-node/version"
"github.com/ethereum/go-ethereum/log" oppprof "github.com/ethereum-optimism/optimism/op-service/pprof"
) )
var ( var (
...@@ -145,24 +146,14 @@ func RollupNodeMain(ctx *cli.Context) error { ...@@ -145,24 +146,14 @@ func RollupNodeMain(ctx *cli.Context) error {
} }
if cfg.Pprof.Enabled { if cfg.Pprof.Enabled {
var srv http.Server pprofCtx, pprofCancel := context.WithCancel(context.Background())
srv.Addr = net.JoinHostPort(cfg.Pprof.ListenAddr, cfg.Pprof.ListenPort)
// Start pprof server + register it's shutdown
go func() { go func() {
log.Info("pprof server started", "addr", srv.Addr) log.Info("pprof server started", "addr", net.JoinHostPort(cfg.Pprof.ListenAddr, strconv.Itoa(cfg.Pprof.ListenPort)))
if err := srv.ListenAndServe(); err != http.ErrServerClosed { if err := oppprof.ListenAndServe(pprofCtx, cfg.Pprof.ListenAddr, cfg.Pprof.ListenPort); err != nil {
log.Error("error in pprof server", "err", err) log.Error("error starting pprof", "err", err)
} else {
log.Info("pprof server shutting down")
} }
}()
defer func() {
shutCtx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
err := srv.Shutdown(shutCtx)
log.Info("pprof server shut down", "err", err)
}() }()
defer pprofCancel()
} }
interruptChannel := make(chan os.Signal, 1) interruptChannel := make(chan os.Signal, 1)
......
...@@ -94,6 +94,11 @@ var ( ...@@ -94,6 +94,11 @@ var (
Usage: "Enable sequencing of new L2 blocks. A separate batch submitter has to be deployed to publish the data for verifiers.", Usage: "Enable sequencing of new L2 blocks. A separate batch submitter has to be deployed to publish the data for verifiers.",
EnvVar: prefixEnvVar("SEQUENCER_ENABLED"), EnvVar: prefixEnvVar("SEQUENCER_ENABLED"),
} }
SequencerStoppedFlag = cli.BoolFlag{
Name: "sequencer.stopped",
Usage: "Initialize the sequencer in a stopped state. The sequencer can be started using the admin_startSequencer RPC",
EnvVar: prefixEnvVar("SEQUENCER_STOPPED"),
}
SequencerL1Confs = cli.Uint64Flag{ SequencerL1Confs = cli.Uint64Flag{
Name: "sequencer.l1-confs", Name: "sequencer.l1-confs",
Usage: "Number of L1 blocks to keep distance from the L1 head as a sequencer for picking an L1 origin.", Usage: "Number of L1 blocks to keep distance from the L1 head as a sequencer for picking an L1 origin.",
...@@ -197,6 +202,7 @@ var optionalFlags = append([]cli.Flag{ ...@@ -197,6 +202,7 @@ var optionalFlags = append([]cli.Flag{
L2EngineJWTSecret, L2EngineJWTSecret,
VerifierL1Confs, VerifierL1Confs,
SequencerEnabledFlag, SequencerEnabledFlag,
SequencerStoppedFlag,
SequencerL1Confs, SequencerL1Confs,
L1EpochPollIntervalFlag, L1EpochPollIntervalFlag,
LogLevelFlag, LogLevelFlag,
......
// Package heartbeat provides a service for sending heartbeats to a server.
package heartbeat package heartbeat
import ( import (
......
...@@ -124,6 +124,7 @@ type Metrics struct { ...@@ -124,6 +124,7 @@ type Metrics struct {
var _ Metricer = (*Metrics)(nil) var _ Metricer = (*Metrics)(nil)
// NewMetrics creates a new [Metrics] instance with the given process name.
func NewMetrics(procName string) *Metrics { func NewMetrics(procName string) *Metrics {
if procName == "" { if procName == "" {
procName = "default" procName = "default"
......
...@@ -26,6 +26,8 @@ type driverClient interface { ...@@ -26,6 +26,8 @@ type driverClient interface {
SyncStatus(ctx context.Context) (*eth.SyncStatus, error) SyncStatus(ctx context.Context) (*eth.SyncStatus, error)
BlockRefWithStatus(ctx context.Context, num uint64) (eth.L2BlockRef, *eth.SyncStatus, error) BlockRefWithStatus(ctx context.Context, num uint64) (eth.L2BlockRef, *eth.SyncStatus, error)
ResetDerivationPipeline(context.Context) error ResetDerivationPipeline(context.Context) error
StartSequencer(ctx context.Context, blockHash common.Hash) error
StopSequencer(context.Context) (common.Hash, error)
} }
type rpcMetrics interface { type rpcMetrics interface {
...@@ -51,6 +53,18 @@ func (n *adminAPI) ResetDerivationPipeline(ctx context.Context) error { ...@@ -51,6 +53,18 @@ func (n *adminAPI) ResetDerivationPipeline(ctx context.Context) error {
return n.dr.ResetDerivationPipeline(ctx) return n.dr.ResetDerivationPipeline(ctx)
} }
func (n *adminAPI) StartSequencer(ctx context.Context, blockHash common.Hash) error {
recordDur := n.m.RecordRPCServerRequest("admin_startSequencer")
defer recordDur()
return n.dr.StartSequencer(ctx, blockHash)
}
func (n *adminAPI) StopSequencer(ctx context.Context) (common.Hash, error) {
recordDur := n.m.RecordRPCServerRequest("admin_stopSequencer")
defer recordDur()
return n.dr.StopSequencer(ctx)
}
type nodeAPI struct { type nodeAPI struct {
config *rollup.Config config *rollup.Config
client l2EthClient client l2EthClient
......
...@@ -9,6 +9,7 @@ import ( ...@@ -9,6 +9,7 @@ import (
"github.com/ethereum-optimism/optimism/op-node/p2p" "github.com/ethereum-optimism/optimism/op-node/p2p"
"github.com/ethereum-optimism/optimism/op-node/rollup" "github.com/ethereum-optimism/optimism/op-node/rollup"
"github.com/ethereum-optimism/optimism/op-node/rollup/driver" "github.com/ethereum-optimism/optimism/op-node/rollup/driver"
oppprof "github.com/ethereum-optimism/optimism/op-service/pprof"
) )
type Config struct { type Config struct {
...@@ -29,7 +30,7 @@ type Config struct { ...@@ -29,7 +30,7 @@ type Config struct {
Metrics MetricsConfig Metrics MetricsConfig
Pprof PprofConfig Pprof oppprof.CLIConfig
// Used to poll the L1 for new finalized or safe blocks // Used to poll the L1 for new finalized or safe blocks
L1EpochPollInterval time.Duration L1EpochPollInterval time.Duration
...@@ -67,16 +68,6 @@ func (m MetricsConfig) Check() error { ...@@ -67,16 +68,6 @@ func (m MetricsConfig) Check() error {
return nil return nil
} }
type PprofConfig struct {
Enabled bool
ListenAddr string
ListenPort string
}
func (p PprofConfig) Check() error {
return nil
}
type HeartbeatConfig struct { type HeartbeatConfig struct {
Enabled bool Enabled bool
Moniker string Moniker string
......
...@@ -218,3 +218,11 @@ func (c *mockDriverClient) SyncStatus(ctx context.Context) (*eth.SyncStatus, err ...@@ -218,3 +218,11 @@ func (c *mockDriverClient) SyncStatus(ctx context.Context) (*eth.SyncStatus, err
func (c *mockDriverClient) ResetDerivationPipeline(ctx context.Context) error { func (c *mockDriverClient) ResetDerivationPipeline(ctx context.Context) error {
return c.Mock.MethodCalled("ResetDerivationPipeline").Get(0).(error) return c.Mock.MethodCalled("ResetDerivationPipeline").Get(0).(error)
} }
func (c *mockDriverClient) StartSequencer(ctx context.Context, blockHash common.Hash) error {
return c.Mock.MethodCalled("StartSequencer").Get(0).(error)
}
func (c *mockDriverClient) StopSequencer(ctx context.Context) (common.Hash, error) {
return c.Mock.MethodCalled("StopSequencer").Get(0).(common.Hash), nil
}
...@@ -74,10 +74,11 @@ func validatePort(p uint) (uint16, error) { ...@@ -74,10 +74,11 @@ func validatePort(p uint) (uint16, error) {
return uint16(p), nil return uint16(p), nil
} }
func loadScoringOpts(conf *p2p.Config, ctx *cli.Context) error { // TODO: Load peer scoring options
conf.ScoringParams = p2p.DefaultScoringParams // func loadScoringOpts(conf *p2p.Config, ctx *cli.Context) error {
return nil // conf.ScoringParams = p2p.DefaultScoringParams
} // return nil
// }
func loadListenOpts(conf *p2p.Config, ctx *cli.Context) error { func loadListenOpts(conf *p2p.Config, ctx *cli.Context) error {
listenIP := ctx.GlobalString(flags.ListenIP.Name) listenIP := ctx.GlobalString(flags.ListenIP.Name)
......
...@@ -145,19 +145,19 @@ func BuildGlobalGossipParams(cfg *rollup.Config) pubsub.GossipSubParams { ...@@ -145,19 +145,19 @@ func BuildGlobalGossipParams(cfg *rollup.Config) pubsub.GossipSubParams {
// NewGossipSub configures a new pubsub instance with the specified parameters. // NewGossipSub configures a new pubsub instance with the specified parameters.
// PubSub uses a GossipSubRouter as it's router under the hood. // PubSub uses a GossipSubRouter as it's router under the hood.
func NewGossipSub(p2pCtx context.Context, h host.Host, g ConnectionGater, cfg *rollup.Config, gossipConf GossipSetupConfigurables, m GossipMetricer) (*pubsub.PubSub, error) { func NewGossipSub(p2pCtx context.Context, h host.Host, g ConnectionGater, cfg *rollup.Config, gossipConf GossipSetupConfigurables, m GossipMetricer, log log.Logger) (*pubsub.PubSub, error) {
denyList, err := pubsub.NewTimeCachedBlacklist(30 * time.Second) denyList, err := pubsub.NewTimeCachedBlacklist(30 * time.Second)
if err != nil { if err != nil {
return nil, err return nil, err
} }
params := BuildGlobalGossipParams(cfg) params := BuildGlobalGossipParams(cfg)
// TODO: make this configurable behind a cli flag - disabled or default // TODO: make this configurable behind a cli flag - disabled or default
peerScoreParams, err := GetPeerScoreParams("default") peerScoreParams, err := GetPeerScoreParams("default", cfg)
if err != nil { if err != nil {
return nil, err return nil, err
} }
peerScoreThresholds := NewPeerScoreThresholds() peerScoreThresholds := NewPeerScoreThresholds()
scorer := NewScorer(g, h.Peerstore(), m) scorer := NewScorer(g, h.Peerstore(), m, log)
gossipOpts := []pubsub.Option{ gossipOpts := []pubsub.Option{
pubsub.WithMaxMessageSize(maxGossipSize), pubsub.WithMaxMessageSize(maxGossipSize),
pubsub.WithMessageIdFn(BuildMsgIdFn(cfg)), pubsub.WithMessageIdFn(BuildMsgIdFn(cfg)),
...@@ -442,7 +442,7 @@ func JoinGossip(p2pCtx context.Context, self peer.ID, ps *pubsub.PubSub, log log ...@@ -442,7 +442,7 @@ func JoinGossip(p2pCtx context.Context, self peer.ID, ps *pubsub.PubSub, log log
// See prysm: https://github.com/prysmaticlabs/prysm/blob/develop/beacon-chain/p2p/gossip_scoring_params.go // See prysm: https://github.com/prysmaticlabs/prysm/blob/develop/beacon-chain/p2p/gossip_scoring_params.go
// And research from lighthouse: https://gist.github.com/blacktemplar/5c1862cb3f0e32a1a7fb0b25e79e6e2c // And research from lighthouse: https://gist.github.com/blacktemplar/5c1862cb3f0e32a1a7fb0b25e79e6e2c
// And docs: https://github.com/libp2p/specs/blob/master/pubsub/gossipsub/gossipsub-v1.1.md#topic-parameter-calculation-and-decay // And docs: https://github.com/libp2p/specs/blob/master/pubsub/gossipsub/gossipsub-v1.1.md#topic-parameter-calculation-and-decay
defaultTopicScoreParams, err := GetTopicScoreParams("default") defaultTopicScoreParams, err := GetTopicScoreParams("default", cfg)
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to create default topic score params: %w", err) return nil, fmt.Errorf("failed to create default topic score params: %w", err)
} }
......
...@@ -23,6 +23,7 @@ import ( ...@@ -23,6 +23,7 @@ import (
"github.com/ethereum-optimism/optimism/op-node/rollup" "github.com/ethereum-optimism/optimism/op-node/rollup"
) )
// NodeP2P is a p2p node, which can be used to gossip messages.
type NodeP2P struct { type NodeP2P struct {
host host.Host // p2p host (optional, may be nil) host host.Host // p2p host (optional, may be nil)
gater ConnectionGater // p2p gater, to ban/unban peers with, may be nil even with p2p enabled gater ConnectionGater // p2p gater, to ban/unban peers with, may be nil even with p2p enabled
...@@ -77,7 +78,7 @@ func (n *NodeP2P) init(resourcesCtx context.Context, rollupCfg *rollup.Config, l ...@@ -77,7 +78,7 @@ func (n *NodeP2P) init(resourcesCtx context.Context, rollupCfg *rollup.Config, l
n.host.Network().Notify(NewNetworkNotifier(log, metrics)) n.host.Network().Notify(NewNetworkNotifier(log, metrics))
// unregister identify-push handler. Only identifying on dial is fine, and more robust against spam // unregister identify-push handler. Only identifying on dial is fine, and more robust against spam
n.host.RemoveStreamHandler(identify.IDDelta) n.host.RemoveStreamHandler(identify.IDDelta)
n.gs, err = NewGossipSub(resourcesCtx, n.host, n.gater, rollupCfg, setup, metrics) n.gs, err = NewGossipSub(resourcesCtx, n.host, n.gater, rollupCfg, setup, metrics, log)
if err != nil { if err != nil {
return fmt.Errorf("failed to start gossipsub router: %w", err) return fmt.Errorf("failed to start gossipsub router: %w", err)
} }
......
...@@ -5,74 +5,86 @@ import ( ...@@ -5,74 +5,86 @@ import (
"math" "math"
"time" "time"
"github.com/ethereum-optimism/optimism/op-node/rollup"
pubsub "github.com/libp2p/go-libp2p-pubsub" pubsub "github.com/libp2p/go-libp2p-pubsub"
"github.com/libp2p/go-libp2p/core/peer" "github.com/libp2p/go-libp2p/core/peer"
) )
// TODO: Update these parameters. // DecayToZero is the decay factor for a peer's score to zero.
const ( const DecayToZero = 0.01
slot = 2 * time.Second
epoch = 12 * time.Second
tenEpochs = 10 * epoch
oneHundredEpochs = 100 * epoch
decayToZero = 0.01
)
// ScoreDecay returns the decay factor for a given duration. // ScoreDecay returns the decay factor for a given duration.
func ScoreDecay(duration time.Duration) float64 { func ScoreDecay(duration time.Duration, slot time.Duration) float64 {
numOfTimes := duration / slot numOfTimes := duration / slot
return math.Pow(decayToZero, 1/float64(numOfTimes)) return math.Pow(DecayToZero, 1/float64(numOfTimes))
} }
// DefaultPeerScoreParams is a default instantiation of [pubsub.PeerScoreParams]. // DefaultPeerScoreParams is a default instantiation of [pubsub.PeerScoreParams].
// See [PeerScoreParams] for detailed documentation. // See [PeerScoreParams] for detailed documentation.
// Default parameters are loosely based on prysm's peer scoring parameters.
// See [PrysmPeerScoringParams] for more details.
// //
// [PeerScoreParams]: https://pkg.go.dev/github.com/libp2p/go-libp2p-pubsub@v0.8.1#PeerScoreParams // [PeerScoreParams]: https://pkg.go.dev/github.com/libp2p/go-libp2p-pubsub@v0.8.1#PeerScoreParams
// [PrysmPeerScoringParams]: https://github.com/prysmaticlabs/prysm/blob/develop/beacon-chain/p2p/gossip_scoring_params.go#L72 var DefaultPeerScoreParams = func(cfg *rollup.Config) pubsub.PeerScoreParams {
var DefaultPeerScoreParams = pubsub.PeerScoreParams{ slot := time.Duration(cfg.BlockTime) * time.Second
Topics: make(map[string]*pubsub.TopicScoreParams), if slot == 0 {
TopicScoreCap: 32.72, slot = 2 * time.Second
AppSpecificScore: func(p peer.ID) float64 { }
return 0 // TODO: tune these params
}, // TODO: we initialize an "epoch" as 6 blocks suggesting 6 blocks, each taking ~ 2 seconds, is 12 seconds
AppSpecificWeight: 1, epoch := 6 * slot
IPColocationFactorWeight: -35.11, tenEpochs := 10 * epoch
IPColocationFactorThreshold: 10, oneHundredEpochs := 100 * epoch
IPColocationFactorWhitelist: nil, return pubsub.PeerScoreParams{
BehaviourPenaltyWeight: -15.92, Topics: make(map[string]*pubsub.TopicScoreParams),
BehaviourPenaltyThreshold: 6, TopicScoreCap: 34,
BehaviourPenaltyDecay: ScoreDecay(tenEpochs), AppSpecificScore: func(p peer.ID) float64 {
DecayInterval: slot, return 0
DecayToZero: decayToZero, },
RetainScore: oneHundredEpochs, AppSpecificWeight: 1,
IPColocationFactorWeight: -35,
IPColocationFactorThreshold: 10,
IPColocationFactorWhitelist: nil,
BehaviourPenaltyWeight: -16,
BehaviourPenaltyThreshold: 6,
BehaviourPenaltyDecay: ScoreDecay(tenEpochs, slot),
DecayInterval: slot,
DecayToZero: DecayToZero,
RetainScore: oneHundredEpochs,
}
} }
// DisabledPeerScoreParams is an instantiation of [pubsub.PeerScoreParams] where all scoring is disabled. // DisabledPeerScoreParams is an instantiation of [pubsub.PeerScoreParams] where all scoring is disabled.
// See [PeerScoreParams] for detailed documentation. // See [PeerScoreParams] for detailed documentation.
// //
// [PeerScoreParams]: https://pkg.go.dev/github.com/libp2p/go-libp2p-pubsub@v0.8.1#PeerScoreParams // [PeerScoreParams]: https://pkg.go.dev/github.com/libp2p/go-libp2p-pubsub@v0.8.1#PeerScoreParams
var DisabledPeerScoreParams = pubsub.PeerScoreParams{ var DisabledPeerScoreParams = func(cfg *rollup.Config) pubsub.PeerScoreParams {
Topics: make(map[string]*pubsub.TopicScoreParams), slot := time.Duration(cfg.BlockTime) * time.Second
TopicScoreCap: 0, // 0 represent no cap // TODO: tune these params
AppSpecificScore: func(p peer.ID) float64 { // TODO: we initialize an "epoch" as 6 blocks suggesting 6 blocks, each taking ~ 2 seconds, is 12 seconds
return 0 epoch := 6 * slot
}, tenEpochs := 10 * epoch
AppSpecificWeight: 1, oneHundredEpochs := 100 * epoch
// ignore colocation scoring return pubsub.PeerScoreParams{
IPColocationFactorWeight: 0, Topics: make(map[string]*pubsub.TopicScoreParams),
IPColocationFactorWhitelist: nil, // 0 represent no cap
// 0 disables the behaviour penalty TopicScoreCap: 0,
BehaviourPenaltyWeight: 0, AppSpecificScore: func(p peer.ID) float64 {
BehaviourPenaltyDecay: ScoreDecay(tenEpochs), return 0
DecayInterval: slot, },
DecayToZero: decayToZero, AppSpecificWeight: 1,
RetainScore: oneHundredEpochs, // ignore colocation scoring
IPColocationFactorWeight: 0,
IPColocationFactorWhitelist: nil,
// 0 disables the behaviour penalty
BehaviourPenaltyWeight: 0,
BehaviourPenaltyDecay: ScoreDecay(tenEpochs, slot),
DecayInterval: slot,
DecayToZero: DecayToZero,
RetainScore: oneHundredEpochs,
}
} }
// PeerScoreParamsByName is a map of name to [pubsub.PeerScoreParams]. // PeerScoreParamsByName is a map of name to function that returns a [pubsub.PeerScoreParams] based on the provided [rollup.Config].
var PeerScoreParamsByName = map[string]pubsub.PeerScoreParams{ var PeerScoreParamsByName = map[string](func(cfg *rollup.Config) pubsub.PeerScoreParams){
"default": DefaultPeerScoreParams, "default": DefaultPeerScoreParams,
"disabled": DisabledPeerScoreParams, "disabled": DisabledPeerScoreParams,
} }
...@@ -89,13 +101,13 @@ func AvailablePeerScoreParams() []string { ...@@ -89,13 +101,13 @@ func AvailablePeerScoreParams() []string {
} }
// GetPeerScoreParams returns the [pubsub.PeerScoreParams] for the given name. // GetPeerScoreParams returns the [pubsub.PeerScoreParams] for the given name.
func GetPeerScoreParams(name string) (pubsub.PeerScoreParams, error) { func GetPeerScoreParams(name string, cfg *rollup.Config) (pubsub.PeerScoreParams, error) {
params, ok := PeerScoreParamsByName[name] params, ok := PeerScoreParamsByName[name]
if !ok { if !ok {
return pubsub.PeerScoreParams{}, fmt.Errorf("invalid params %s", name) return pubsub.PeerScoreParams{}, fmt.Errorf("invalid params %s", name)
} }
return params, nil return params(cfg), nil
} }
// NewPeerScoreThresholds returns a default [pubsub.PeerScoreThresholds]. // NewPeerScoreThresholds returns a default [pubsub.PeerScoreThresholds].
......
package p2p package p2p
import ( import (
"github.com/ethereum/go-ethereum/log"
pubsub "github.com/libp2p/go-libp2p-pubsub" pubsub "github.com/libp2p/go-libp2p-pubsub"
"github.com/libp2p/go-libp2p/core/peer" "github.com/libp2p/go-libp2p/core/peer"
"github.com/libp2p/go-libp2p/core/peerstore" "github.com/libp2p/go-libp2p/core/peerstore"
"golang.org/x/exp/slices"
) )
const ConnectionFactor = -10 const ConnectionFactor = -10
...@@ -14,6 +16,7 @@ type scorer struct { ...@@ -14,6 +16,7 @@ type scorer struct {
connGater ConnectionGater connGater ConnectionGater
peerStore peerstore.Peerstore peerStore peerstore.Peerstore
metricer GossipMetricer metricer GossipMetricer
log log.Logger
} }
// Scorer is a peer scorer that scores peers based on application-specific metrics. // Scorer is a peer scorer that scores peers based on application-specific metrics.
...@@ -24,11 +27,12 @@ type Scorer interface { ...@@ -24,11 +27,12 @@ type Scorer interface {
} }
// NewScorer returns a new peer scorer. // NewScorer returns a new peer scorer.
func NewScorer(connGater ConnectionGater, peerStore peerstore.Peerstore, metricer GossipMetricer) Scorer { func NewScorer(connGater ConnectionGater, peerStore peerstore.Peerstore, metricer GossipMetricer, log log.Logger) Scorer {
return &scorer{ return &scorer{
connGater: connGater, connGater: connGater,
peerStore: peerStore, peerStore: peerStore,
metricer: metricer, metricer: metricer,
log: log,
} }
} }
...@@ -59,27 +63,19 @@ func (s *scorer) SnapshotHook() pubsub.ExtendedPeerScoreInspectFn { ...@@ -59,27 +63,19 @@ func (s *scorer) SnapshotHook() pubsub.ExtendedPeerScoreInspectFn {
// Check if the peer score is below the threshold // Check if the peer score is below the threshold
// If so, we need to block the peer // If so, we need to block the peer
if snap.Score < PeerScoreThreshold { if snap.Score < PeerScoreThreshold {
_ = s.connGater.BlockPeer(id) err := s.connGater.BlockPeer(id)
s.log.Warn("connection gater failed to block peer", id.String(), "err", err)
} }
// Unblock peers whose score has recovered to an acceptable level // Unblock peers whose score has recovered to an acceptable level
if (snap.Score > PeerScoreThreshold) && contains(s.connGater.ListBlockedPeers(), id) { if (snap.Score > PeerScoreThreshold) && slices.Contains(s.connGater.ListBlockedPeers(), id) {
_ = s.connGater.UnblockPeer(id) err := s.connGater.UnblockPeer(id)
s.log.Warn("connection gater failed to unblock peer", id.String(), "err", err)
} }
} }
} }
} }
func contains(peers []peer.ID, id peer.ID) bool { // TODO: call the two methods below from the notifier
for _, v := range peers {
if v == id {
return true
}
}
return false
}
// call the two methods below from the notifier
// OnConnect is called when a peer connects. // OnConnect is called when a peer connects.
// See [p2p.NotificationsMetricer] for invocation. // See [p2p.NotificationsMetricer] for invocation.
......
...@@ -2,91 +2,93 @@ package p2p ...@@ -2,91 +2,93 @@ package p2p
import ( import (
"fmt" "fmt"
"math"
"time" "time"
"github.com/ethereum-optimism/optimism/op-node/rollup"
pubsub "github.com/libp2p/go-libp2p-pubsub" pubsub "github.com/libp2p/go-libp2p-pubsub"
) )
// TODO: Update these parameters. // MeshWeight is the weight of the mesh delivery topic.
const ( const MeshWeight = -0.7
beaconBlockWeight = 0.8
meshWeight = -0.717 // MaxInMeshScore is the maximum score for being in the mesh.
invalidDecayPeriod = 50 * epoch const MaxInMeshScore = 10
maxInMeshScore = 10
decayEpoch = time.Duration(5) // DecayEpoch is the number of epochs to decay the score over.
) const DecayEpoch = time.Duration(5)
// DefaultTopicScoreParams is a default instantiation of [pubsub.TopicScoreParams]. // DefaultTopicScoreParams is a default instantiation of [pubsub.TopicScoreParams].
// See [TopicScoreParams] for detailed documentation. // See [TopicScoreParams] for detailed documentation.
// Default parameters are loosely based on prysm's default block topic scoring parameters.
// See [PrysmTopicScoringParams] for more details.
// //
// [TopicScoreParams]: https://pkg.go.dev/github.com/libp2p/go-libp2p-pubsub@v0.8.1#TopicScoreParams // [TopicScoreParams]: https://pkg.go.dev/github.com/libp2p/go-libp2p-pubsub@v0.8.1#TopicScoreParams
// [PrysmTopicScoringParams]: https://github.com/prysmaticlabs/prysm/blob/develop/beacon-chain/p2p/gossip_scoring_params.go#L169 var DefaultTopicScoreParams = func(cfg *rollup.Config) pubsub.TopicScoreParams {
var DefaultTopicScoreParams = pubsub.TopicScoreParams{ slot := time.Duration(cfg.BlockTime) * time.Second
TopicWeight: beaconBlockWeight, if slot == 0 {
TimeInMeshWeight: maxInMeshScore / inMeshCap(), slot = 2 * time.Second
TimeInMeshQuantum: inMeshTime(), }
TimeInMeshCap: inMeshCap(), // TODO: tune these params
FirstMessageDeliveriesWeight: 1, // TODO: we initialize an "epoch" as 6 blocks suggesting 6 blocks, each taking ~ 2 seconds, is 12 seconds
FirstMessageDeliveriesDecay: scoreDecay(20 * epoch), epoch := 6 * slot
FirstMessageDeliveriesCap: 23, invalidDecayPeriod := 50 * epoch
MeshMessageDeliveriesWeight: meshWeight, return pubsub.TopicScoreParams{
MeshMessageDeliveriesDecay: scoreDecay(decayEpoch * epoch), TopicWeight: 0.8,
MeshMessageDeliveriesCap: float64(uint64(epoch/slot) * uint64(decayEpoch)), TimeInMeshWeight: MaxInMeshScore / inMeshCap(slot),
MeshMessageDeliveriesThreshold: float64(uint64(epoch/slot) * uint64(decayEpoch) / 10), TimeInMeshQuantum: slot,
MeshMessageDeliveriesWindow: 2 * time.Second, TimeInMeshCap: inMeshCap(slot),
MeshMessageDeliveriesActivation: 4 * epoch, FirstMessageDeliveriesWeight: 1,
MeshFailurePenaltyWeight: meshWeight, FirstMessageDeliveriesDecay: ScoreDecay(20*epoch, slot),
MeshFailurePenaltyDecay: scoreDecay(decayEpoch * epoch), FirstMessageDeliveriesCap: 23,
InvalidMessageDeliveriesWeight: -140.4475, MeshMessageDeliveriesWeight: MeshWeight,
InvalidMessageDeliveriesDecay: scoreDecay(invalidDecayPeriod), MeshMessageDeliveriesDecay: ScoreDecay(DecayEpoch*epoch, slot),
} MeshMessageDeliveriesCap: float64(uint64(epoch/slot) * uint64(DecayEpoch)),
MeshMessageDeliveriesThreshold: float64(uint64(epoch/slot) * uint64(DecayEpoch) / 10),
// determines the decay rate from the provided time period till MeshMessageDeliveriesWindow: 2 * time.Second,
// the decayToZero value. Ex: ( 1 -> 0.01) MeshMessageDeliveriesActivation: 4 * epoch,
func scoreDecay(duration time.Duration) float64 { MeshFailurePenaltyWeight: MeshWeight,
numOfTimes := duration / slot MeshFailurePenaltyDecay: ScoreDecay(DecayEpoch*epoch, slot),
return math.Pow(decayToZero, 1/float64(numOfTimes)) InvalidMessageDeliveriesWeight: -140.4475,
} InvalidMessageDeliveriesDecay: ScoreDecay(invalidDecayPeriod, slot),
}
// denotes the unit time in mesh for scoring tallying.
func inMeshTime() time.Duration {
return 1 * slot
} }
// the cap for `inMesh` time scoring. // the cap for `inMesh` time scoring.
func inMeshCap() float64 { func inMeshCap(slot time.Duration) float64 {
return float64((3600 * time.Second) / inMeshTime()) return float64((3600 * time.Second) / slot)
} }
// DisabledTopicScoreParams is an instantiation of [pubsub.TopicScoreParams] where all scoring is disabled. // DisabledTopicScoreParams is an instantiation of [pubsub.TopicScoreParams] where all scoring is disabled.
// See [TopicScoreParams] for detailed documentation. // See [TopicScoreParams] for detailed documentation.
// //
// [TopicScoreParams]: https://pkg.go.dev/github.com/libp2p/go-libp2p-pubsub@v0.8.1#TopicScoreParams // [TopicScoreParams]: https://pkg.go.dev/github.com/libp2p/go-libp2p-pubsub@v0.8.1#TopicScoreParams
var DisabledTopicScoreParams = pubsub.TopicScoreParams{ var DisabledTopicScoreParams = func(cfg *rollup.Config) pubsub.TopicScoreParams {
TopicWeight: 0, // disabled slot := time.Duration(cfg.BlockTime) * time.Second
TimeInMeshWeight: 0, // disabled // TODO: tune these params
TimeInMeshQuantum: inMeshTime(), // TODO: we initialize an "epoch" as 6 blocks suggesting 6 blocks, each taking ~ 2 seconds, is 12 seconds
TimeInMeshCap: inMeshCap(), epoch := 6 * slot
FirstMessageDeliveriesWeight: 0, // disabled invalidDecayPeriod := 50 * epoch
FirstMessageDeliveriesDecay: scoreDecay(20 * epoch), return pubsub.TopicScoreParams{
FirstMessageDeliveriesCap: 23, TopicWeight: 0, // disabled
MeshMessageDeliveriesWeight: 0, // disabled TimeInMeshWeight: 0, // disabled
MeshMessageDeliveriesDecay: scoreDecay(decayEpoch * epoch), TimeInMeshQuantum: slot,
MeshMessageDeliveriesCap: float64(uint64(epoch/slot) * uint64(decayEpoch)), TimeInMeshCap: inMeshCap(slot),
MeshMessageDeliveriesThreshold: float64(uint64(epoch/slot) * uint64(decayEpoch) / 10), FirstMessageDeliveriesWeight: 0, // disabled
MeshMessageDeliveriesWindow: 2 * time.Second, FirstMessageDeliveriesDecay: ScoreDecay(20*epoch, slot),
MeshMessageDeliveriesActivation: 4 * epoch, FirstMessageDeliveriesCap: 23,
MeshFailurePenaltyWeight: 0, // disabled MeshMessageDeliveriesWeight: 0, // disabled
MeshFailurePenaltyDecay: scoreDecay(decayEpoch * epoch), MeshMessageDeliveriesDecay: ScoreDecay(DecayEpoch*epoch, slot),
InvalidMessageDeliveriesWeight: 0, // disabled MeshMessageDeliveriesCap: float64(uint64(epoch/slot) * uint64(DecayEpoch)),
InvalidMessageDeliveriesDecay: scoreDecay(invalidDecayPeriod), MeshMessageDeliveriesThreshold: float64(uint64(epoch/slot) * uint64(DecayEpoch) / 10),
MeshMessageDeliveriesWindow: 2 * time.Second,
MeshMessageDeliveriesActivation: 4 * epoch,
MeshFailurePenaltyWeight: 0, // disabled
MeshFailurePenaltyDecay: ScoreDecay(DecayEpoch*epoch, slot),
InvalidMessageDeliveriesWeight: 0, // disabled
InvalidMessageDeliveriesDecay: ScoreDecay(invalidDecayPeriod, slot),
}
} }
// TopicScoreParamsByName is a map of name to [pubsub.TopicScoreParams]. // TopicScoreParamsByName is a map of name to [pubsub.TopicScoreParams].
var TopicScoreParamsByName = map[string]pubsub.TopicScoreParams{ var TopicScoreParamsByName = map[string](func(*rollup.Config) pubsub.TopicScoreParams){
"default": DefaultTopicScoreParams, "default": DefaultTopicScoreParams,
"disabled": DisabledTopicScoreParams, "disabled": DisabledTopicScoreParams,
} }
...@@ -103,11 +105,11 @@ func AvailableTopicScoreParams() []string { ...@@ -103,11 +105,11 @@ func AvailableTopicScoreParams() []string {
} }
// GetTopicScoreParams returns the [pubsub.TopicScoreParams] for the given name. // GetTopicScoreParams returns the [pubsub.TopicScoreParams] for the given name.
func GetTopicScoreParams(name string) (pubsub.TopicScoreParams, error) { func GetTopicScoreParams(name string, cfg *rollup.Config) (pubsub.TopicScoreParams, error) {
params, ok := TopicScoreParamsByName[name] params, ok := TopicScoreParamsByName[name]
if !ok { if !ok {
return pubsub.TopicScoreParams{}, fmt.Errorf("invalid topic params %s", name) return pubsub.TopicScoreParams{}, fmt.Errorf("invalid topic params %s", name)
} }
return params, nil return params(cfg), nil
} }
...@@ -13,4 +13,7 @@ type Config struct { ...@@ -13,4 +13,7 @@ type Config struct {
// SequencerEnabled is true when the driver should sequence new blocks. // SequencerEnabled is true when the driver should sequence new blocks.
SequencerEnabled bool `json:"sequencer_enabled"` SequencerEnabled bool `json:"sequencer_enabled"`
// SequencerStopped is false when the driver should sequence new blocks.
SequencerStopped bool `json:"sequencer_stopped"`
} }
...@@ -97,6 +97,8 @@ func NewDriver(driverCfg *Config, cfg *rollup.Config, l2 L2Chain, l1 L1Chain, ne ...@@ -97,6 +97,8 @@ func NewDriver(driverCfg *Config, cfg *rollup.Config, l2 L2Chain, l1 L1Chain, ne
idleDerivation: false, idleDerivation: false,
stateReq: make(chan chan struct{}), stateReq: make(chan chan struct{}),
forceReset: make(chan chan struct{}, 10), forceReset: make(chan chan struct{}, 10),
startSequencer: make(chan hashAndErrorChannel, 10),
stopSequencer: make(chan chan hashAndError, 10),
config: cfg, config: cfg,
driverConfig: driverCfg, driverConfig: driverCfg,
done: make(chan struct{}), done: make(chan struct{}),
......
package driver package driver
import ( import (
"bytes"
"context" "context"
"encoding/json" "encoding/json"
"errors" "errors"
...@@ -9,6 +10,7 @@ import ( ...@@ -9,6 +10,7 @@ import (
gosync "sync" gosync "sync"
"time" "time"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
"github.com/ethereum-optimism/optimism/op-node/eth" "github.com/ethereum-optimism/optimism/op-node/eth"
...@@ -42,6 +44,14 @@ type Driver struct { ...@@ -42,6 +44,14 @@ type Driver struct {
// It tells the caller that the reset occurred by closing the passed in channel. // It tells the caller that the reset occurred by closing the passed in channel.
forceReset chan chan struct{} forceReset chan chan struct{}
// Upon receiving a hash in this channel, the sequencer is started at the given hash.
// It tells the caller that the sequencer started by closing the passed in channel (or returning an error).
startSequencer chan hashAndErrorChannel
// Upon receiving a channel in this channel, the sequencer is stopped.
// It tells the caller that the sequencer stopped by returning the latest sequenced L2 block hash.
stopSequencer chan chan hashAndError
// Rollup config: rollup chain configuration // Rollup config: rollup chain configuration
config *rollup.Config config *rollup.Config
...@@ -274,7 +284,7 @@ func (s *Driver) eventLoop() { ...@@ -274,7 +284,7 @@ func (s *Driver) eventLoop() {
for { for {
// If we are sequencing, update the trigger for the next sequencer action. // If we are sequencing, update the trigger for the next sequencer action.
// This may adjust at any time based on fork-choice changes or previous errors. // This may adjust at any time based on fork-choice changes or previous errors.
if s.driverConfig.SequencerEnabled { if s.driverConfig.SequencerEnabled && !s.driverConfig.SequencerStopped {
// update sequencer time if the head changed // update sequencer time if the head changed
if sequencingPlannedOnto != s.derivation.UnsafeL2Head().ID() { if sequencingPlannedOnto != s.derivation.UnsafeL2Head().ID() {
planSequencerAction() planSequencerAction()
...@@ -367,6 +377,26 @@ func (s *Driver) eventLoop() { ...@@ -367,6 +377,26 @@ func (s *Driver) eventLoop() {
s.derivation.Reset() s.derivation.Reset()
s.metrics.RecordPipelineReset() s.metrics.RecordPipelineReset()
close(respCh) close(respCh)
case resp := <-s.startSequencer:
unsafeHead := s.derivation.UnsafeL2Head().Hash
if !s.driverConfig.SequencerStopped {
resp.err <- errors.New("sequencer already running")
} else if !bytes.Equal(unsafeHead[:], resp.hash[:]) {
resp.err <- fmt.Errorf("block hash does not match: head %s, received %s", unsafeHead.String(), resp.hash.String())
} else {
s.log.Info("Sequencer has been started")
s.driverConfig.SequencerStopped = false
sequencingPlannedOnto = eth.BlockID{}
close(resp.err)
}
case respCh := <-s.stopSequencer:
if s.driverConfig.SequencerStopped {
respCh <- hashAndError{err: errors.New("sequencer not running")}
} else {
s.log.Warn("Sequencer has been stopped")
s.driverConfig.SequencerStopped = true
respCh <- hashAndError{hash: s.derivation.UnsafeL2Head().Hash}
}
case <-s.done: case <-s.done:
return return
} }
...@@ -391,6 +421,45 @@ func (s *Driver) ResetDerivationPipeline(ctx context.Context) error { ...@@ -391,6 +421,45 @@ func (s *Driver) ResetDerivationPipeline(ctx context.Context) error {
} }
} }
func (s *Driver) StartSequencer(ctx context.Context, blockHash common.Hash) error {
if !s.driverConfig.SequencerEnabled {
return errors.New("sequencer is not enabled")
}
h := hashAndErrorChannel{
hash: blockHash,
err: make(chan error, 1),
}
select {
case <-ctx.Done():
return ctx.Err()
case s.startSequencer <- h:
select {
case <-ctx.Done():
return ctx.Err()
case e := <-h.err:
return e
}
}
}
func (s *Driver) StopSequencer(ctx context.Context) (common.Hash, error) {
if !s.driverConfig.SequencerEnabled {
return common.Hash{}, errors.New("sequencer is not enabled")
}
respCh := make(chan hashAndError, 1)
select {
case <-ctx.Done():
return common.Hash{}, ctx.Err()
case s.stopSequencer <- respCh:
select {
case <-ctx.Done():
return common.Hash{}, ctx.Err()
case he := <-respCh:
return he.hash, he.err
}
}
}
// syncStatus returns the current sync status, and should only be called synchronously with // syncStatus returns the current sync status, and should only be called synchronously with
// the driver event loop to avoid retrieval of an inconsistent status. // the driver event loop to avoid retrieval of an inconsistent status.
func (s *Driver) syncStatus() *eth.SyncStatus { func (s *Driver) syncStatus() *eth.SyncStatus {
...@@ -455,3 +524,13 @@ func (s *Driver) snapshot(event string) { ...@@ -455,3 +524,13 @@ func (s *Driver) snapshot(event string) {
"l2Safe", deferJSONString{s.derivation.SafeL2Head()}, "l2Safe", deferJSONString{s.derivation.SafeL2Head()},
"l2FinalizedHead", deferJSONString{s.derivation.Finalized()}) "l2FinalizedHead", deferJSONString{s.derivation.Finalized()})
} }
type hashAndError struct {
hash common.Hash
err error
}
type hashAndErrorChannel struct {
hash common.Hash
err chan error
}
...@@ -10,6 +10,7 @@ import ( ...@@ -10,6 +10,7 @@ import (
"github.com/ethereum-optimism/optimism/op-node/chaincfg" "github.com/ethereum-optimism/optimism/op-node/chaincfg"
"github.com/ethereum-optimism/optimism/op-node/sources" "github.com/ethereum-optimism/optimism/op-node/sources"
oppprof "github.com/ethereum-optimism/optimism/op-service/pprof"
"github.com/urfave/cli" "github.com/urfave/cli"
...@@ -75,10 +76,10 @@ func NewConfig(ctx *cli.Context, log log.Logger) (*node.Config, error) { ...@@ -75,10 +76,10 @@ func NewConfig(ctx *cli.Context, log log.Logger) (*node.Config, error) {
ListenAddr: ctx.GlobalString(flags.MetricsAddrFlag.Name), ListenAddr: ctx.GlobalString(flags.MetricsAddrFlag.Name),
ListenPort: ctx.GlobalInt(flags.MetricsPortFlag.Name), ListenPort: ctx.GlobalInt(flags.MetricsPortFlag.Name),
}, },
Pprof: node.PprofConfig{ Pprof: oppprof.CLIConfig{
Enabled: ctx.GlobalBool(flags.PprofEnabledFlag.Name), Enabled: ctx.GlobalBool(flags.PprofEnabledFlag.Name),
ListenAddr: ctx.GlobalString(flags.PprofAddrFlag.Name), ListenAddr: ctx.GlobalString(flags.PprofAddrFlag.Name),
ListenPort: ctx.GlobalString(flags.PprofPortFlag.Name), ListenPort: ctx.GlobalInt(flags.PprofPortFlag.Name),
}, },
P2P: p2pConfig, P2P: p2pConfig,
P2PSigner: p2pSignerSetup, P2PSigner: p2pSignerSetup,
...@@ -138,6 +139,7 @@ func NewDriverConfig(ctx *cli.Context) (*driver.Config, error) { ...@@ -138,6 +139,7 @@ func NewDriverConfig(ctx *cli.Context) (*driver.Config, error) {
VerifierConfDepth: ctx.GlobalUint64(flags.VerifierL1Confs.Name), VerifierConfDepth: ctx.GlobalUint64(flags.VerifierL1Confs.Name),
SequencerConfDepth: ctx.GlobalUint64(flags.SequencerL1Confs.Name), SequencerConfDepth: ctx.GlobalUint64(flags.SequencerL1Confs.Name),
SequencerEnabled: ctx.GlobalBool(flags.SequencerEnabledFlag.Name), SequencerEnabled: ctx.GlobalBool(flags.SequencerEnabledFlag.Name),
SequencerStopped: ctx.GlobalBool(flags.SequencerStoppedFlag.Name),
}, nil }, nil
} }
......
...@@ -68,7 +68,7 @@ func NewL1Client(client client.RPC, log log.Logger, metrics caching.Metrics, con ...@@ -68,7 +68,7 @@ func NewL1Client(client client.RPC, log log.Logger, metrics caching.Metrics, con
}, nil }, nil
} }
// L1BlockRefByLabel returns the L1BlockRef for the given block label. // L1BlockRefByLabel returns the [eth.L1BlockRef] for the given block label.
// Notice, we cannot cache a block reference by label because labels are not guaranteed to be unique. // Notice, we cannot cache a block reference by label because labels are not guaranteed to be unique.
func (s *L1Client) L1BlockRefByLabel(ctx context.Context, label eth.BlockLabel) (eth.L1BlockRef, error) { func (s *L1Client) L1BlockRefByLabel(ctx context.Context, label eth.BlockLabel) (eth.L1BlockRef, error) {
info, err := s.InfoByLabel(ctx, label) info, err := s.InfoByLabel(ctx, label)
...@@ -85,7 +85,7 @@ func (s *L1Client) L1BlockRefByLabel(ctx context.Context, label eth.BlockLabel) ...@@ -85,7 +85,7 @@ func (s *L1Client) L1BlockRefByLabel(ctx context.Context, label eth.BlockLabel)
return ref, nil return ref, nil
} }
// L1BlockRefByNumber returns the L1BlockRef for the given block number. // L1BlockRefByNumber returns an [eth.L1BlockRef] for the given block number.
// Notice, we cannot cache a block reference by number because L1 re-orgs can invalidate the cached block reference. // Notice, we cannot cache a block reference by number because L1 re-orgs can invalidate the cached block reference.
func (s *L1Client) L1BlockRefByNumber(ctx context.Context, num uint64) (eth.L1BlockRef, error) { func (s *L1Client) L1BlockRefByNumber(ctx context.Context, num uint64) (eth.L1BlockRef, error) {
info, err := s.InfoByNumber(ctx, num) info, err := s.InfoByNumber(ctx, num)
...@@ -97,7 +97,7 @@ func (s *L1Client) L1BlockRefByNumber(ctx context.Context, num uint64) (eth.L1Bl ...@@ -97,7 +97,7 @@ func (s *L1Client) L1BlockRefByNumber(ctx context.Context, num uint64) (eth.L1Bl
return ref, nil return ref, nil
} }
// L1BlockRefByHash returns the L1BlockRef for the given block hash. // L1BlockRefByHash returns the [eth.L1BlockRef] for the given block hash.
// We cache the block reference by hash as it is safe to assume collision will not occur. // We cache the block reference by hash as it is safe to assume collision will not occur.
func (s *L1Client) L1BlockRefByHash(ctx context.Context, hash common.Hash) (eth.L1BlockRef, error) { func (s *L1Client) L1BlockRefByHash(ctx context.Context, hash common.Hash) (eth.L1BlockRef, error) {
if v, ok := s.l1BlockRefsCache.Get(hash); ok { if v, ok := s.l1BlockRefsCache.Get(hash); ok {
......
...@@ -87,7 +87,7 @@ func NewL2Client(client client.RPC, log log.Logger, metrics caching.Metrics, con ...@@ -87,7 +87,7 @@ func NewL2Client(client client.RPC, log log.Logger, metrics caching.Metrics, con
}, nil }, nil
} }
// L2BlockRefByLabel returns the L2 block reference for the given label. // L2BlockRefByLabel returns the [eth.L2BlockRef] for the given block label.
func (s *L2Client) L2BlockRefByLabel(ctx context.Context, label eth.BlockLabel) (eth.L2BlockRef, error) { func (s *L2Client) L2BlockRefByLabel(ctx context.Context, label eth.BlockLabel) (eth.L2BlockRef, error) {
payload, err := s.PayloadByLabel(ctx, label) payload, err := s.PayloadByLabel(ctx, label)
if err != nil { if err != nil {
...@@ -107,7 +107,7 @@ func (s *L2Client) L2BlockRefByLabel(ctx context.Context, label eth.BlockLabel) ...@@ -107,7 +107,7 @@ func (s *L2Client) L2BlockRefByLabel(ctx context.Context, label eth.BlockLabel)
return ref, nil return ref, nil
} }
// L2BlockRefByNumber returns the L2 block reference for the given block number. // L2BlockRefByNumber returns the [eth.L2BlockRef] for the given block number.
func (s *L2Client) L2BlockRefByNumber(ctx context.Context, num uint64) (eth.L2BlockRef, error) { func (s *L2Client) L2BlockRefByNumber(ctx context.Context, num uint64) (eth.L2BlockRef, error) {
payload, err := s.PayloadByNumber(ctx, num) payload, err := s.PayloadByNumber(ctx, num)
if err != nil { if err != nil {
...@@ -122,7 +122,7 @@ func (s *L2Client) L2BlockRefByNumber(ctx context.Context, num uint64) (eth.L2Bl ...@@ -122,7 +122,7 @@ func (s *L2Client) L2BlockRefByNumber(ctx context.Context, num uint64) (eth.L2Bl
return ref, nil return ref, nil
} }
// L2BlockRefByHash returns the L2 block reference for the given block hash. // L2BlockRefByHash returns the [eth.L2BlockRef] for the given block hash.
// The returned BlockRef may not be in the canonical chain. // The returned BlockRef may not be in the canonical chain.
func (s *L2Client) L2BlockRefByHash(ctx context.Context, hash common.Hash) (eth.L2BlockRef, error) { func (s *L2Client) L2BlockRefByHash(ctx context.Context, hash common.Hash) (eth.L2BlockRef, error) {
if ref, ok := s.l2BlockRefsCache.Get(hash); ok { if ref, ok := s.l2BlockRefsCache.Get(hash); ok {
...@@ -142,8 +142,8 @@ func (s *L2Client) L2BlockRefByHash(ctx context.Context, hash common.Hash) (eth. ...@@ -142,8 +142,8 @@ func (s *L2Client) L2BlockRefByHash(ctx context.Context, hash common.Hash) (eth.
return ref, nil return ref, nil
} }
// SystemConfigByL2Hash returns the system config (matching the config updates up to and including the L1 origin) for the given L2 block hash. // SystemConfigByL2Hash returns the [eth.SystemConfig] (matching the config updates up to and including the L1 origin) for the given L2 block hash.
// The returned SystemConfig may not be in the canonical chain when the hash is not canonical. // The returned [eth.SystemConfig] may not be in the canonical chain when the hash is not canonical.
func (s *L2Client) SystemConfigByL2Hash(ctx context.Context, hash common.Hash) (eth.SystemConfig, error) { func (s *L2Client) SystemConfigByL2Hash(ctx context.Context, hash common.Hash) (eth.SystemConfig, error) {
if ref, ok := s.systemConfigsCache.Get(hash); ok { if ref, ok := s.systemConfigsCache.Get(hash); ok {
return ref.(eth.SystemConfig), nil return ref.(eth.SystemConfig), nil
......
...@@ -8,6 +8,7 @@ COPY ./op-bindings /app/op-bindings ...@@ -8,6 +8,7 @@ COPY ./op-bindings /app/op-bindings
COPY ./op-node /app/op-node COPY ./op-node /app/op-node
COPY ./op-proposer /app/op-proposer COPY ./op-proposer /app/op-proposer
COPY ./op-service /app/op-service COPY ./op-service /app/op-service
COPY ./op-signer /app/op-signer
COPY ./.git /app/.git COPY ./.git /app/.git
WORKDIR /app/op-proposer WORKDIR /app/op-proposer
......
...@@ -5,4 +5,5 @@ use ( ...@@ -5,4 +5,5 @@ use (
./op-node ./op-node
./op-proposer ./op-proposer
./op-service ./op-service
./op-signer
) )
...@@ -8,6 +8,7 @@ import ( ...@@ -8,6 +8,7 @@ import (
opmetrics "github.com/ethereum-optimism/optimism/op-service/metrics" opmetrics "github.com/ethereum-optimism/optimism/op-service/metrics"
oppprof "github.com/ethereum-optimism/optimism/op-service/pprof" oppprof "github.com/ethereum-optimism/optimism/op-service/pprof"
oprpc "github.com/ethereum-optimism/optimism/op-service/rpc" oprpc "github.com/ethereum-optimism/optimism/op-service/rpc"
opsigner "github.com/ethereum-optimism/optimism/op-signer/client"
) )
const envVarPrefix = "OP_PROPOSER" const envVarPrefix = "OP_PROPOSER"
...@@ -112,6 +113,7 @@ func init() { ...@@ -112,6 +113,7 @@ func init() {
optionalFlags = append(optionalFlags, oplog.CLIFlags(envVarPrefix)...) optionalFlags = append(optionalFlags, oplog.CLIFlags(envVarPrefix)...)
optionalFlags = append(optionalFlags, opmetrics.CLIFlags(envVarPrefix)...) optionalFlags = append(optionalFlags, opmetrics.CLIFlags(envVarPrefix)...)
optionalFlags = append(optionalFlags, oppprof.CLIFlags(envVarPrefix)...) optionalFlags = append(optionalFlags, oppprof.CLIFlags(envVarPrefix)...)
optionalFlags = append(optionalFlags, opsigner.CLIFlags(envVarPrefix)...)
Flags = append(requiredFlags, optionalFlags...) Flags = append(requiredFlags, optionalFlags...)
} }
......
...@@ -7,6 +7,7 @@ require ( ...@@ -7,6 +7,7 @@ require (
github.com/ethereum-optimism/optimism/op-bindings v0.10.10 github.com/ethereum-optimism/optimism/op-bindings v0.10.10
github.com/ethereum-optimism/optimism/op-node v0.10.10 github.com/ethereum-optimism/optimism/op-node v0.10.10
github.com/ethereum-optimism/optimism/op-service v0.10.10 github.com/ethereum-optimism/optimism/op-service v0.10.10
github.com/ethereum-optimism/optimism/op-signer v0.1.0
github.com/ethereum/go-ethereum v1.10.26 github.com/ethereum/go-ethereum v1.10.26
github.com/stretchr/testify v1.8.1 github.com/stretchr/testify v1.8.1
github.com/urfave/cli v1.22.9 github.com/urfave/cli v1.22.9
...@@ -25,7 +26,9 @@ require ( ...@@ -25,7 +26,9 @@ require (
github.com/davecgh/go-spew v1.1.1 // indirect github.com/davecgh/go-spew v1.1.1 // indirect
github.com/deckarep/golang-set v1.8.0 // indirect github.com/deckarep/golang-set v1.8.0 // indirect
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0 // indirect github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0 // indirect
github.com/dyson/certman v0.3.0 // indirect
github.com/fjl/memsize v0.0.1 // indirect github.com/fjl/memsize v0.0.1 // indirect
github.com/fsnotify/fsnotify v1.6.0 // indirect
github.com/go-ole/go-ole v1.2.6 // indirect github.com/go-ole/go-ole v1.2.6 // indirect
github.com/go-stack/stack v1.8.1 // indirect github.com/go-stack/stack v1.8.1 // indirect
github.com/gogo/protobuf v1.3.2 // indirect github.com/gogo/protobuf v1.3.2 // indirect
...@@ -89,7 +92,7 @@ require ( ...@@ -89,7 +92,7 @@ require (
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect
github.com/yusufpapurcu/wmi v1.2.2 // indirect github.com/yusufpapurcu/wmi v1.2.2 // indirect
golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa // indirect golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa // indirect
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4 // indirect golang.org/x/sync v0.1.0 // indirect
golang.org/x/sys v0.0.0-20221013171732-95e765b1cc43 // indirect golang.org/x/sys v0.0.0-20221013171732-95e765b1cc43 // indirect
golang.org/x/term v0.0.0-20220722155259-a9ba230a4035 // indirect golang.org/x/term v0.0.0-20220722155259-a9ba230a4035 // indirect
golang.org/x/time v0.0.0-20220722155302-e5dcc9cfc0b9 // indirect golang.org/x/time v0.0.0-20220722155302-e5dcc9cfc0b9 // indirect
......
...@@ -98,6 +98,8 @@ github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0 h1:HbphB4TFFXpv7MNrT52FGrrgVXF1 ...@@ -98,6 +98,8 @@ github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0 h1:HbphB4TFFXpv7MNrT52FGrrgVXF1
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0/go.mod h1:DZGJHZMqrU4JJqFAWUS2UO1+lbSKsdiOoYi9Zzey7Fc= github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0/go.mod h1:DZGJHZMqrU4JJqFAWUS2UO1+lbSKsdiOoYi9Zzey7Fc=
github.com/decred/dcrd/lru v1.0.0/go.mod h1:mxKOwFd7lFjN2GZYsiz/ecgqR6kkYAl+0pz0tEMk218= github.com/decred/dcrd/lru v1.0.0/go.mod h1:mxKOwFd7lFjN2GZYsiz/ecgqR6kkYAl+0pz0tEMk218=
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
github.com/dyson/certman v0.3.0 h1:S7WCUim5faT/OiBhiY3u5cMaiC9MNKiA+8PJDXLaIYQ=
github.com/dyson/certman v0.3.0/go.mod h1:RMWlyA9op6D9SxOBRRX3sxnParehv9gf52WWUJPd1JA=
github.com/edsrzf/mmap-go v1.1.0 h1:6EUwBLQ/Mcr1EYLE4Tn1VdW1A4ckqCQWZBw8Hr0kjpQ= github.com/edsrzf/mmap-go v1.1.0 h1:6EUwBLQ/Mcr1EYLE4Tn1VdW1A4ckqCQWZBw8Hr0kjpQ=
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.0/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/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
...@@ -113,12 +115,15 @@ github.com/ethereum-optimism/optimism/op-node v0.10.10 h1:edmxboiYSIk9n4A3paEF7I ...@@ -113,12 +115,15 @@ github.com/ethereum-optimism/optimism/op-node v0.10.10 h1:edmxboiYSIk9n4A3paEF7I
github.com/ethereum-optimism/optimism/op-node v0.10.10/go.mod h1:EEcHgMdKiWasJGO5uzspRN2xM1/OB+ehgVgMj4RgPas= github.com/ethereum-optimism/optimism/op-node v0.10.10/go.mod h1:EEcHgMdKiWasJGO5uzspRN2xM1/OB+ehgVgMj4RgPas=
github.com/ethereum-optimism/optimism/op-service v0.10.10 h1:B5mGpATX6zPkDABoh6smCjh6Z5mA2KWh71MD1i6T5ww= github.com/ethereum-optimism/optimism/op-service v0.10.10 h1:B5mGpATX6zPkDABoh6smCjh6Z5mA2KWh71MD1i6T5ww=
github.com/ethereum-optimism/optimism/op-service v0.10.10/go.mod h1:wbtHqi1fv00B3agj7a2zdP3OFanEfGZ23zPgGgFCF/c= github.com/ethereum-optimism/optimism/op-service v0.10.10/go.mod h1:wbtHqi1fv00B3agj7a2zdP3OFanEfGZ23zPgGgFCF/c=
github.com/ethereum-optimism/optimism/op-signer v0.1.0 h1:wH44Deai43YQWO0pEd44pDm3BahdAtSmrOHKiPvTB8Y=
github.com/ethereum-optimism/optimism/op-signer v0.1.0/go.mod h1:u8sN6X/c20pP9F1Ey7jH3fi19D08Y+T9ep3PGJfdyi8=
github.com/fjl/memsize v0.0.1 h1:+zhkb+dhUgx0/e+M8sF0QqiouvMQUiKR+QYvdxIOKcQ= github.com/fjl/memsize v0.0.1 h1:+zhkb+dhUgx0/e+M8sF0QqiouvMQUiKR+QYvdxIOKcQ=
github.com/fjl/memsize v0.0.1/go.mod h1:VvhXpOYNQvB+uIk2RvXzuaQtkQJzzIx6lSBe1xv7hi0= github.com/fjl/memsize v0.0.1/go.mod h1:VvhXpOYNQvB+uIk2RvXzuaQtkQJzzIx6lSBe1xv7hi0=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
github.com/fsnotify/fsnotify v1.5.4 h1:jRbGcIw6P2Meqdwuo0H1p6JVLbL5DHKAKlYndzMwVZI=
github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU= github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU=
github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY=
github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw=
github.com/gballet/go-libpcsclite v0.0.0-20191108122812-4678299bea08 h1:f6D9Hr8xV8uYKlyuj8XIruxlh9WjVjdh1gIicAS7ays= github.com/gballet/go-libpcsclite v0.0.0-20191108122812-4678299bea08 h1:f6D9Hr8xV8uYKlyuj8XIruxlh9WjVjdh1gIicAS7ays=
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
...@@ -527,8 +532,8 @@ golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJ ...@@ -527,8 +532,8 @@ golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4 h1:uVc8UZUe6tr40fFVnUP5Oj+veunVezqYl9z7DYw9xzw= golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
...@@ -586,6 +591,7 @@ golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBc ...@@ -586,6 +591,7 @@ golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20221013171732-95e765b1cc43 h1:OK7RB6t2WQX54srQQYSXMW8dF5C6/8+oA/s5QBmmto4= golang.org/x/sys v0.0.0-20221013171732-95e765b1cc43 h1:OK7RB6t2WQX54srQQYSXMW8dF5C6/8+oA/s5QBmmto4=
golang.org/x/sys v0.0.0-20221013171732-95e765b1cc43/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20221013171732-95e765b1cc43/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
......
package mock
import (
"context"
"math/big"
"sync"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
)
// L1ClientConfig houses the internal methods that are executed by the mock
// L1Client. Any members left as nil will panic on execution.
type L1ClientConfig struct {
// BlockNumber returns the most recent block number.
BlockNumber func(context.Context) (uint64, error)
// HeaderByNumber returns a block header from the current canonical chain.
// If number is nil, the latest known header is returned.
HeaderByNumber func(context.Context, *big.Int) (*types.Header, error)
// NonceAt returns the account nonce of the given account. The block number
// can be nil, in which case the nonce is taken from the latest known block.
NonceAt func(context.Context, common.Address, *big.Int) (uint64, error)
// SendTransaction injects a signed transaction into the pending pool for
// execution.
//
// If the transaction was a contract creation use the TransactionReceipt
// method to get the contract address after the transaction has been mined.
SendTransaction func(context.Context, *types.Transaction) error
// SuggestGasTipCap retrieves the currently suggested gas tip cap after 1559
// to allow a timely execution of a transaction.
SuggestGasTipCap func(context.Context) (*big.Int, error)
// TransactionReceipt returns the receipt of a transaction by transaction
// hash. Note that the receipt is not available for pending transactions.
TransactionReceipt func(context.Context, common.Hash) (*types.Receipt, error)
}
// L1Client represents a mock L1Client.
type L1Client struct {
cfg L1ClientConfig
mu sync.RWMutex
}
// NewL1Client returns a new L1Client using the mocked methods in the
// L1ClientConfig.
func NewL1Client(cfg L1ClientConfig) *L1Client {
return &L1Client{
cfg: cfg,
}
}
// BlockNumber returns the most recent block number.
func (c *L1Client) BlockNumber(ctx context.Context) (uint64, error) {
c.mu.RLock()
defer c.mu.RUnlock()
return c.cfg.BlockNumber(ctx)
}
// HeaderByNumber returns a block header from the current canonical chain. If
// number is nil, the latest known header is returned.
func (c *L1Client) HeaderByNumber(ctx context.Context, blockNumber *big.Int) (*types.Header, error) {
c.mu.RLock()
defer c.mu.RUnlock()
return c.cfg.HeaderByNumber(ctx, blockNumber)
}
// NonceAt executes the mock NonceAt method.
func (c *L1Client) NonceAt(ctx context.Context, addr common.Address, blockNumber *big.Int) (uint64, error) {
c.mu.RLock()
defer c.mu.RUnlock()
return c.cfg.NonceAt(ctx, addr, blockNumber)
}
// SendTransaction executes the mock SendTransaction method.
func (c *L1Client) SendTransaction(ctx context.Context, tx *types.Transaction) error {
c.mu.RLock()
defer c.mu.RUnlock()
return c.cfg.SendTransaction(ctx, tx)
}
// SuggestGasTipCap retrieves the currently suggested gas tip cap after 1559 to
// allow a timely execution of a transaction.
func (c *L1Client) SuggestGasTipCap(ctx context.Context) (*big.Int, error) {
c.mu.RLock()
defer c.mu.RUnlock()
return c.cfg.SuggestGasTipCap(ctx)
}
// TransactionReceipt executes the mock TransactionReceipt method.
func (c *L1Client) TransactionReceipt(ctx context.Context, txHash common.Hash) (*types.Receipt, error) {
c.mu.RLock()
defer c.mu.RUnlock()
return c.cfg.TransactionReceipt(ctx, txHash)
}
// SetBlockNumberFunc overwrites the mock BlockNumber method.
func (c *L1Client) SetBlockNumberFunc(
f func(context.Context) (uint64, error)) {
c.mu.Lock()
defer c.mu.Unlock()
c.cfg.BlockNumber = f
}
// SetHeaderByNumberFunc overwrites the mock HeaderByNumber method.
func (c *L1Client) SetHeaderByNumberFunc(
f func(ctx context.Context, blockNumber *big.Int) (*types.Header, error)) {
c.mu.Lock()
defer c.mu.Unlock()
c.cfg.HeaderByNumber = f
}
// SetNonceAtFunc overwrites the mock NonceAt method.
func (c *L1Client) SetNonceAtFunc(
f func(context.Context, common.Address, *big.Int) (uint64, error)) {
c.mu.Lock()
defer c.mu.Unlock()
c.cfg.NonceAt = f
}
// SetSendTransactionFunc overwrites the mock SendTransaction method.
func (c *L1Client) SetSendTransactionFunc(
f func(context.Context, *types.Transaction) error) {
c.mu.Lock()
defer c.mu.Unlock()
c.cfg.SendTransaction = f
}
// SetSuggestGasTipCapFunc overwrites themock SuggestGasTipCap method.
func (c *L1Client) SetSuggestGasTipCapFunc(
f func(context.Context) (*big.Int, error)) {
c.mu.Lock()
defer c.mu.Unlock()
c.cfg.SuggestGasTipCap = f
}
// SetTransactionReceiptFunc overwrites the mock TransactionReceipt method.
func (c *L1Client) SetTransactionReceiptFunc(
f func(context.Context, common.Hash) (*types.Receipt, error)) {
c.mu.Lock()
defer c.mu.Unlock()
c.cfg.TransactionReceipt = f
}
...@@ -3,16 +3,37 @@ package proposer ...@@ -3,16 +3,37 @@ package proposer
import ( import (
"time" "time"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/ethclient"
"github.com/urfave/cli" "github.com/urfave/cli"
"github.com/ethereum-optimism/optimism/op-node/sources"
"github.com/ethereum-optimism/optimism/op-proposer/flags" "github.com/ethereum-optimism/optimism/op-proposer/flags"
"github.com/ethereum-optimism/optimism/op-proposer/txmgr"
oplog "github.com/ethereum-optimism/optimism/op-service/log" oplog "github.com/ethereum-optimism/optimism/op-service/log"
opmetrics "github.com/ethereum-optimism/optimism/op-service/metrics" opmetrics "github.com/ethereum-optimism/optimism/op-service/metrics"
oppprof "github.com/ethereum-optimism/optimism/op-service/pprof" oppprof "github.com/ethereum-optimism/optimism/op-service/pprof"
oprpc "github.com/ethereum-optimism/optimism/op-service/rpc" oprpc "github.com/ethereum-optimism/optimism/op-service/rpc"
opsigner "github.com/ethereum-optimism/optimism/op-signer/client"
) )
// Config contains the well typed fields that are used to initialize the output submitter.
// It is intended for programmatic use.
type Config struct { type Config struct {
L2OutputOracleAddr common.Address
PollInterval time.Duration
TxManagerConfig txmgr.Config
L1Client *ethclient.Client
RollupClient *sources.RollupClient
AllowNonFinalized bool
From common.Address
SignerFnFactory SignerFactory
}
// CLIConfig is a well typed config that is parsed from the CLI params.
// This also contains config options for auxiliary services.
// It is transformed into a `Config` before the L2 output submitter is started.
type CLIConfig struct {
/* Required Params */ /* Required Params */
// L1EthRpc is the HTTP provider URL for L1. // L1EthRpc is the HTTP provider URL for L1.
...@@ -66,9 +87,12 @@ type Config struct { ...@@ -66,9 +87,12 @@ type Config struct {
MetricsConfig opmetrics.CLIConfig MetricsConfig opmetrics.CLIConfig
PprofConfig oppprof.CLIConfig PprofConfig oppprof.CLIConfig
// SignerConfig contains the client config for op-signer service
SignerConfig opsigner.CLIConfig
} }
func (c Config) Check() error { func (c CLIConfig) Check() error {
if err := c.RPCConfig.Check(); err != nil { if err := c.RPCConfig.Check(); err != nil {
return err return err
} }
...@@ -81,13 +105,16 @@ func (c Config) Check() error { ...@@ -81,13 +105,16 @@ func (c Config) Check() error {
if err := c.PprofConfig.Check(); err != nil { if err := c.PprofConfig.Check(); err != nil {
return err return err
} }
if err := c.SignerConfig.Check(); err != nil {
return err
}
return nil return nil
} }
// NewConfig parses the Config from the provided flags or environment variables. // NewConfig parses the Config from the provided flags or environment variables.
func NewConfig(ctx *cli.Context) Config { func NewConfig(ctx *cli.Context) CLIConfig {
return Config{ return CLIConfig{
/* Required Flags */ // Required Flags
L1EthRpc: ctx.GlobalString(flags.L1EthRpcFlag.Name), L1EthRpc: ctx.GlobalString(flags.L1EthRpcFlag.Name),
RollupRpc: ctx.GlobalString(flags.RollupRpcFlag.Name), RollupRpc: ctx.GlobalString(flags.RollupRpcFlag.Name),
L2OOAddress: ctx.GlobalString(flags.L2OOAddressFlag.Name), L2OOAddress: ctx.GlobalString(flags.L2OOAddressFlag.Name),
...@@ -98,10 +125,12 @@ func NewConfig(ctx *cli.Context) Config { ...@@ -98,10 +125,12 @@ func NewConfig(ctx *cli.Context) Config {
Mnemonic: ctx.GlobalString(flags.MnemonicFlag.Name), Mnemonic: ctx.GlobalString(flags.MnemonicFlag.Name),
L2OutputHDPath: ctx.GlobalString(flags.L2OutputHDPathFlag.Name), L2OutputHDPath: ctx.GlobalString(flags.L2OutputHDPathFlag.Name),
PrivateKey: ctx.GlobalString(flags.PrivateKeyFlag.Name), PrivateKey: ctx.GlobalString(flags.PrivateKeyFlag.Name),
AllowNonFinalized: ctx.GlobalBool(flags.AllowNonFinalizedFlag.Name), // Optional Flags
RPCConfig: oprpc.ReadCLIConfig(ctx), AllowNonFinalized: ctx.GlobalBool(flags.AllowNonFinalizedFlag.Name),
LogConfig: oplog.ReadCLIConfig(ctx), RPCConfig: oprpc.ReadCLIConfig(ctx),
MetricsConfig: opmetrics.ReadCLIConfig(ctx), LogConfig: oplog.ReadCLIConfig(ctx),
PprofConfig: oppprof.ReadCLIConfig(ctx), MetricsConfig: opmetrics.ReadCLIConfig(ctx),
PprofConfig: oppprof.ReadCLIConfig(ctx),
SignerConfig: opsigner.ReadCLIConfig(ctx),
} }
} }
package proposer
import (
"context"
"fmt"
"math/big"
"strings"
"github.com/ethereum-optimism/optimism/op-node/sources"
"github.com/ethereum/go-ethereum/accounts/abi"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/ethclient"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum-optimism/optimism/op-bindings/bindings"
"github.com/ethereum-optimism/optimism/op-node/eth"
)
var bigOne = big.NewInt(1)
var supportedL2OutputVersion = eth.Bytes32{}
type SignerFn func(context.Context, common.Address, *types.Transaction) (*types.Transaction, error)
type DriverConfig struct {
Log log.Logger
Name string
// L1Client is used to submit transactions to
L1Client *ethclient.Client
// RollupClient is used to retrieve output roots from
RollupClient *sources.RollupClient
// AllowNonFinalized enables the proposal of safe, but non-finalized L2 blocks.
// The L1 block-hash embedded in the proposal TX is checked and should ensure the proposal
// is never valid on an alternative L1 chain that would produce different L2 data.
// This option is not necessary when higher proposal latency is acceptable and L1 is healthy.
AllowNonFinalized bool
// L2OOAddr is the L1 contract address of the L2 Output Oracle.
L2OOAddr common.Address
// From is the address to send transactions from
From common.Address
// SignerFn is the function used to sign transactions
SignerFn SignerFn
}
type Driver struct {
cfg DriverConfig
l2ooContract *bindings.L2OutputOracle
rawL2ooContract *bind.BoundContract
walletAddr common.Address
l log.Logger
}
func NewDriver(cfg DriverConfig) (*Driver, error) {
l2ooContract, err := bindings.NewL2OutputOracle(cfg.L2OOAddr, cfg.L1Client)
if err != nil {
return nil, err
}
parsed, err := abi.JSON(strings.NewReader(
bindings.L2OutputOracleMetaData.ABI,
))
if err != nil {
return nil, err
}
rawL2ooContract := bind.NewBoundContract(
cfg.L2OOAddr, parsed, cfg.L1Client, cfg.L1Client, cfg.L1Client,
)
cfg.Log.Info("Configured driver", "wallet", cfg.From, "l2-output-contract", cfg.L2OOAddr)
return &Driver{
cfg: cfg,
l2ooContract: l2ooContract,
rawL2ooContract: rawL2ooContract,
walletAddr: cfg.From,
l: cfg.Log,
}, nil
}
// Name is an identifier used to prefix logs for a particular service.
func (d *Driver) Name() string {
return d.cfg.Name
}
// WalletAddr is the wallet address used to pay for transaction fees.
func (d *Driver) WalletAddr() common.Address {
return d.walletAddr
}
// GetBlockRange returns the start and end L2 block heights that need to be
// processed. Note that the end value is *exclusive*, therefore if the returned
// values are identical nothing needs to be processed.
func (d *Driver) GetBlockRange(ctx context.Context) (*big.Int, *big.Int, error) {
name := d.cfg.Name
callOpts := &bind.CallOpts{
Pending: false,
Context: ctx,
}
// Determine the last committed L2 Block Number
start, err := d.l2ooContract.LatestBlockNumber(callOpts)
if err != nil {
d.l.Error(name+" unable to get latest block number", "err", err)
return nil, nil, err
}
start.Add(start, bigOne)
// Next determine the L2 block that we need to commit
nextBlockNumber, err := d.l2ooContract.NextBlockNumber(callOpts)
if err != nil {
d.l.Error(name+" unable to get next block number", "err", err)
return nil, nil, err
}
status, err := d.cfg.RollupClient.SyncStatus(ctx)
if err != nil {
d.l.Error(name+" unable to get sync status", "err", err)
return nil, nil, err
}
var currentBlockNumber *big.Int
if d.cfg.AllowNonFinalized {
currentBlockNumber = new(big.Int).SetUint64(status.SafeL2.Number)
} else {
currentBlockNumber = new(big.Int).SetUint64(status.FinalizedL2.Number)
}
// If we do not have the new L2 Block number
if currentBlockNumber.Cmp(nextBlockNumber) < 0 {
d.l.Info(name+" submission interval has not elapsed",
"currentBlockNumber", currentBlockNumber, "nextBlockNumber", nextBlockNumber)
return start, start, nil
}
d.l.Info(name+" submission interval has elapsed",
"currentBlockNumber", currentBlockNumber, "nextBlockNumber", nextBlockNumber)
// Otherwise the submission interval has elapsed. Transform the next
// expected timestamp into its L2 block number, and add one since end is
// exclusive.
end := new(big.Int).Add(nextBlockNumber, bigOne)
return start, end, nil
}
// CraftTx transforms the L2 blocks between start and end into a transaction
// using the given nonce.
//
// NOTE: This method SHOULD NOT publish the resulting transaction.
func (d *Driver) CraftTx(ctx context.Context, start, end, nonce *big.Int) (*types.Transaction, error) {
name := d.cfg.Name
d.l.Info(name+" crafting checkpoint tx", "start", start, "end", end, "nonce", nonce)
// Fetch the final block in the range, as this is the only L2 output we need to submit.
nextCheckpointBlock := new(big.Int).Sub(end, bigOne).Uint64()
output, err := d.cfg.RollupClient.OutputAtBlock(ctx, nextCheckpointBlock)
if err != nil {
return nil, fmt.Errorf("failed to fetch output at block %d: %w", nextCheckpointBlock, err)
}
if output.Version != supportedL2OutputVersion {
return nil, fmt.Errorf("unsupported l2 output version: %s", output.Version)
}
if output.BlockRef.Number != nextCheckpointBlock { // sanity check, e.g. in case of bad RPC caching
return nil, fmt.Errorf("invalid blockNumber: next blockNumber is %v, blockNumber of block is %v", nextCheckpointBlock, output.BlockRef.Number)
}
// Always propose if it's part of the Finalized L2 chain. Or if allowed, if it's part of the safe L2 chain.
if !(output.BlockRef.Number <= output.Status.FinalizedL2.Number || (d.cfg.AllowNonFinalized && output.BlockRef.Number <= output.Status.SafeL2.Number)) {
d.l.Debug("not proposing yet, L2 block is not ready for proposal",
"l2_proposal", output.BlockRef,
"l2_safe", output.Status.SafeL2,
"l2_finalized", output.Status.FinalizedL2,
"allow_non_finalized", d.cfg.AllowNonFinalized)
return nil, fmt.Errorf("output for L2 block %s is still unsafe", output.BlockRef)
}
opts := &bind.TransactOpts{
From: d.cfg.From,
Signer: func(addr common.Address, tx *types.Transaction) (*types.Transaction, error) {
return d.cfg.SignerFn(ctx, addr, tx)
},
Context: ctx,
Nonce: nonce,
NoSend: true,
}
// Note: the CurrentL1 is up to (and incl.) what the safe chain and finalized chain have been derived from,
// and should be a quite recent L1 block (depends on L1 conf distance applied to rollup node).
tx, err := d.l2ooContract.ProposeL2Output(
opts,
output.OutputRoot,
new(big.Int).SetUint64(output.BlockRef.Number),
output.Status.CurrentL1.Hash,
new(big.Int).SetUint64(output.Status.CurrentL1.Number))
if err != nil {
return nil, err
}
numElements := new(big.Int).Sub(start, end).Uint64()
d.l.Info(name+" proposal constructed",
"start", start, "end", end,
"nonce", nonce, "blocks_committed", numElements,
"tx_hash", tx.Hash(),
"output_version", output.Version,
"output_root", output.OutputRoot,
"output_block", output.BlockRef,
"output_withdrawals_root", output.WithdrawalStorageRoot,
"output_state_root", output.StateRoot,
"current_l1", output.Status.CurrentL1,
"safe_l2", output.Status.SafeL2,
"finalized_l2", output.Status.FinalizedL2,
)
return tx, nil
}
// UpdateGasPrice signs an otherwise identical txn to the one provided but with
// updated gas prices sampled from the existing network conditions.
//
// NOTE: This method SHOULD NOT publish the resulting transaction.
func (d *Driver) UpdateGasPrice(ctx context.Context, tx *types.Transaction) (*types.Transaction, error) {
opts := &bind.TransactOpts{
From: d.cfg.From,
Signer: func(addr common.Address, tx *types.Transaction) (*types.Transaction, error) {
return d.cfg.SignerFn(ctx, addr, tx)
},
Context: ctx,
Nonce: new(big.Int).SetUint64(tx.Nonce()),
NoSend: true,
}
return d.rawL2ooContract.RawTransact(opts, tx.Data())
}
// SendTransaction injects a signed transaction into the pending pool for execution.
func (d *Driver) SendTransaction(ctx context.Context, tx *types.Transaction) error {
d.l.Info(d.cfg.Name+" sending transaction", "tx", tx.Hash())
return d.cfg.L1Client.SendTransaction(ctx, tx)
}
package proposer
import (
"context"
"math/big"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
)
// L1Client is an abstraction over an L1 Ethereum client functionality required
// by the batch submitter.
type L1Client interface {
// HeaderByNumber returns a block header from the current canonical chain.
// If number is nil, the latest known header is returned.
HeaderByNumber(context.Context, *big.Int) (*types.Header, error)
// NonceAt returns the account nonce of the given account. The block number
// can be nil, in which case the nonce is taken from the latest known block.
NonceAt(context.Context, common.Address, *big.Int) (uint64, error)
// SendTransaction injects a signed transaction into the pending pool for
// execution.
//
// If the transaction was a contract creation use the TransactionReceipt
// method to get the contract address after the transaction has been mined.
SendTransaction(context.Context, *types.Transaction) error
// SuggestGasTipCap retrieves the currently suggested gas tip cap after 1559
// to allow a timely execution of a transaction.
SuggestGasTipCap(context.Context) (*big.Int, error)
// TransactionReceipt returns the receipt of a transaction by transaction
// hash. Note that the receipt is not available for pending transactions.
TransactionReceipt(context.Context, common.Hash) (*types.Receipt, error)
}
This diff is collapsed.
package proposer
import (
"context"
"math/big"
"sync"
"time"
"github.com/ethereum-optimism/optimism/op-proposer/txmgr"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/ethclient"
"github.com/ethereum/go-ethereum/log"
)
// DriverInterface is an interface for creating and submitting transactions for a
// specific contract.
type DriverInterface interface {
// Name is an identifier used to prefix logs for a particular service.
Name() string
// WalletAddr is the wallet address used to pay for transaction fees.
WalletAddr() common.Address
// GetBlockRange returns the start and end L2 block heights that need to be
// processed. Note that the end value is *exclusive*, therefore if the
// returned values are identical nothing needs to be processed.
GetBlockRange(ctx context.Context) (*big.Int, *big.Int, error)
// CraftTx transforms the L2 blocks between start and end into a transaction
// using the given nonce.
//
// NOTE: This method SHOULD NOT publish the resulting transaction.
CraftTx(
ctx context.Context,
start, end, nonce *big.Int,
) (*types.Transaction, error)
// UpdateGasPrice signs an otherwise identical txn to the one provided but
// with updated gas prices sampled from the existing network conditions.
//
// NOTE: Thie method SHOULD NOT publish the resulting transaction.
UpdateGasPrice(
ctx context.Context,
tx *types.Transaction,
) (*types.Transaction, error)
// SendTransaction injects a signed transaction into the pending pool for
// execution.
SendTransaction(ctx context.Context, tx *types.Transaction) error
}
type ServiceConfig struct {
Log log.Logger
Context context.Context
Driver DriverInterface
PollInterval time.Duration
L1Client *ethclient.Client
TxManagerConfig txmgr.Config
}
type Service struct {
cfg ServiceConfig
txMgr txmgr.TxManager
l log.Logger
ctx context.Context
cancel func()
wg sync.WaitGroup
}
func NewService(cfg ServiceConfig) *Service {
txMgr := txmgr.NewSimpleTxManager(
cfg.Driver.Name(), cfg.TxManagerConfig, cfg.L1Client,
)
ctx, cancel := context.WithCancel(cfg.Context)
return &Service{
cfg: cfg,
txMgr: txMgr,
l: cfg.Log,
ctx: ctx,
cancel: cancel,
}
}
func (s *Service) Start() error {
s.wg.Add(1)
go s.eventLoop()
return nil
}
func (s *Service) Stop() error {
s.cancel()
s.wg.Wait()
return nil
}
func (s *Service) eventLoop() {
defer s.wg.Done()
name := s.cfg.Driver.Name()
ticker := time.NewTicker(s.cfg.PollInterval)
defer ticker.Stop()
for {
select {
case <-ticker.C:
// Determine the range of L2 blocks that the submitter has not
// processed, and needs to take action on.
s.l.Info(name + " fetching current block range")
start, end, err := s.cfg.Driver.GetBlockRange(s.ctx)
if err != nil {
s.l.Error(name+" unable to get block range", "err", err)
continue
}
// No new updates.
if start.Cmp(end) == 0 {
s.l.Info(name+" no updates", "start", start, "end", end)
continue
}
s.l.Info(name+" block range", "start", start, "end", end)
// Query for the submitter's current nonce.
nonce64, err := s.cfg.L1Client.NonceAt(
s.ctx, s.cfg.Driver.WalletAddr(), nil,
)
if err != nil {
s.l.Error(name+" unable to get current nonce",
"err", err)
continue
}
nonce := new(big.Int).SetUint64(nonce64)
tx, err := s.cfg.Driver.CraftTx(
s.ctx, start, end, nonce,
)
if err != nil {
s.l.Error(name+" unable to craft tx",
"err", err)
continue
}
// Construct the a closure that will update the txn with the current
// gas prices.
updateGasPrice := func(ctx context.Context) (*types.Transaction, error) {
s.l.Info(name+" updating batch tx gas price", "start", start,
"end", end, "nonce", nonce)
return s.cfg.Driver.UpdateGasPrice(ctx, tx)
}
// Wait until one of our submitted transactions confirms. If no
// receipt is received it's likely our gas price was too low.
receipt, err := s.txMgr.Send(
s.ctx, updateGasPrice, s.cfg.Driver.SendTransaction,
)
if err != nil {
s.l.Error(name+" unable to publish tx", "err", err)
continue
}
// The transaction was successfully submitted.
s.l.Info(name+" tx successfully published",
"tx_hash", receipt.TxHash)
case <-s.ctx.Done():
s.l.Info(name + " service shutting down")
return
}
}
}
package proposer
import (
"context"
"fmt"
"github.com/ethereum-optimism/optimism/op-node/client"
"github.com/ethereum-optimism/optimism/op-node/sources"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/ethclient"
"github.com/ethereum/go-ethereum/rpc"
)
// dialEthClientWithTimeout attempts to dial the L1 provider using the provided
// URL. If the dial doesn't complete within defaultDialTimeout seconds, this
// method will return an error.
func dialEthClientWithTimeout(ctx context.Context, url string) (*ethclient.Client, error) {
ctxt, cancel := context.WithTimeout(ctx, defaultDialTimeout)
defer cancel()
return ethclient.DialContext(ctxt, url)
}
// dialRollupClientWithTimeout attempts to dial the RPC provider using the provided
// URL. If the dial doesn't complete within defaultDialTimeout seconds, this
// method will return an error.
func dialRollupClientWithTimeout(ctx context.Context, url string) (*sources.RollupClient, error) {
ctxt, cancel := context.WithTimeout(ctx, defaultDialTimeout)
defer cancel()
rpcCl, err := rpc.DialContext(ctxt, url)
if err != nil {
return nil, err
}
return sources.NewRollupClient(client.NewBaseRPCClient(rpcCl)), nil
}
// parseAddress parses an ETH address from a hex string. This method will fail if
// the address is not a valid hexadecimal address.
func parseAddress(address string) (common.Address, error) {
if common.IsHexAddress(address) {
return common.HexToAddress(address), nil
}
return common.Address{}, fmt.Errorf("invalid address: %v", address)
}
...@@ -3,6 +3,8 @@ package tls ...@@ -3,6 +3,8 @@ package tls
import ( import (
"errors" "errors"
"fmt"
"strings"
"github.com/urfave/cli" "github.com/urfave/cli"
...@@ -15,22 +17,33 @@ const ( ...@@ -15,22 +17,33 @@ const (
TLSKeyFlagName = "tls.key" TLSKeyFlagName = "tls.key"
) )
// CLIFlags returns flags with env var envPrefix
// This should be used for server TLS configs, or when client and server tls configs are the same
func CLIFlags(envPrefix string) []cli.Flag { func CLIFlags(envPrefix string) []cli.Flag {
return CLIFlagsWithFlagPrefix(envPrefix, "")
}
// CLIFlagsWithFlagPrefix returns flags with env var and cli flag prefixes
// Should be used for client TLS configs when different from server on the same process
func CLIFlagsWithFlagPrefix(envPrefix string, flagPrefix string) []cli.Flag {
prefixFunc := func(flagName string) string {
return strings.Trim(fmt.Sprintf("%s.%s", flagPrefix, flagName), ".")
}
return []cli.Flag{ return []cli.Flag{
cli.StringFlag{ cli.StringFlag{
Name: TLSCaCertFlagName, Name: prefixFunc(TLSCaCertFlagName),
Usage: "tls ca cert path", Usage: "tls ca cert path",
Value: "tls/ca.crt", Value: "tls/ca.crt",
EnvVar: opservice.PrefixEnvVar(envPrefix, "TLS_CA"), EnvVar: opservice.PrefixEnvVar(envPrefix, "TLS_CA"),
}, },
cli.StringFlag{ cli.StringFlag{
Name: TLSCertFlagName, Name: prefixFunc(TLSCertFlagName),
Usage: "tls cert path", Usage: "tls cert path",
Value: "tls/tls.crt", Value: "tls/tls.crt",
EnvVar: opservice.PrefixEnvVar(envPrefix, "TLS_CERT"), EnvVar: opservice.PrefixEnvVar(envPrefix, "TLS_CERT"),
}, },
cli.StringFlag{ cli.StringFlag{
Name: TLSKeyFlagName, Name: prefixFunc(TLSKeyFlagName),
Usage: "tls key", Usage: "tls key",
Value: "tls/tls.key", Value: "tls/tls.key",
EnvVar: opservice.PrefixEnvVar(envPrefix, "TLS_KEY"), EnvVar: opservice.PrefixEnvVar(envPrefix, "TLS_KEY"),
...@@ -56,6 +69,8 @@ func (c CLIConfig) TLSEnabled() bool { ...@@ -56,6 +69,8 @@ func (c CLIConfig) TLSEnabled() bool {
return !(c.TLSCaCert == "" && c.TLSCert == "" && c.TLSKey == "") return !(c.TLSCaCert == "" && c.TLSCert == "" && c.TLSKey == "")
} }
// ReadCLIConfig reads tls cli configs
// This should be used for server TLS configs, or when client and server tls configs are the same
func ReadCLIConfig(ctx *cli.Context) CLIConfig { func ReadCLIConfig(ctx *cli.Context) CLIConfig {
return CLIConfig{ return CLIConfig{
TLSCaCert: ctx.GlobalString(TLSCaCertFlagName), TLSCaCert: ctx.GlobalString(TLSCaCertFlagName),
...@@ -63,3 +78,16 @@ func ReadCLIConfig(ctx *cli.Context) CLIConfig { ...@@ -63,3 +78,16 @@ func ReadCLIConfig(ctx *cli.Context) CLIConfig {
TLSKey: ctx.GlobalString(TLSKeyFlagName), TLSKey: ctx.GlobalString(TLSKeyFlagName),
} }
} }
// ReadCLIConfigWithPrefix reads tls cli configs with flag prefix
// Should be used for client TLS configs when different from server on the same process
func ReadCLIConfigWithPrefix(ctx *cli.Context, flagPrefix string) CLIConfig {
prefixFunc := func(flagName string) string {
return strings.Trim(fmt.Sprintf("%s.%s", flagPrefix, flagName), ".")
}
return CLIConfig{
TLSCaCert: ctx.GlobalString(prefixFunc(TLSCaCertFlagName)),
TLSCert: ctx.GlobalString(prefixFunc(TLSCertFlagName)),
TLSKey: ctx.GlobalString(prefixFunc(TLSKeyFlagName)),
}
}
mocks/
mock_*
tls/
# op-signer
op-signer service client
package client
import (
"context"
"crypto/tls"
"crypto/x509"
"fmt"
"math/big"
"net/http"
"os"
"time"
"github.com/dyson/certman"
optls "github.com/ethereum-optimism/optimism/op-service/tls"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/rpc"
)
type SignerClient struct {
client *rpc.Client
status string
logger log.Logger
}
// ethLogger wraps a geth style logger for certman.
type ethLogger struct{ logger log.Logger }
func (l ethLogger) Printf(format string, v ...interface{}) { l.logger.Info(fmt.Sprintf(format, v...)) }
func NewSignerClient(logger log.Logger, endpoint string, tlsConfig optls.CLIConfig) (*SignerClient, error) {
caCert, err := os.ReadFile(tlsConfig.TLSCaCert)
if err != nil {
return nil, fmt.Errorf("failed to read tls.ca: %w", err)
}
caCertPool := x509.NewCertPool()
caCertPool.AppendCertsFromPEM(caCert)
// certman watches for newer client certifictes and automatically reloads them
cm, err := certman.New(tlsConfig.TLSCert, tlsConfig.TLSKey)
cm.Logger(ethLogger{logger: logger})
if err != nil {
logger.Error("failed to read tls cert or key", "err", err)
return nil, err
}
if err := cm.Watch(); err != nil {
logger.Error("failed to start certman watcher", "err", err)
return nil, err
}
httpClient := &http.Client{
Transport: &http.Transport{
TLSClientConfig: &tls.Config{
MinVersion: tls.VersionTLS13,
RootCAs: caCertPool,
GetClientCertificate: func(_ *tls.CertificateRequestInfo) (*tls.Certificate, error) {
return cm.GetCertificate(nil)
},
},
},
}
rpcClient, err := rpc.DialOptions(context.Background(), endpoint, rpc.WithHTTPClient(httpClient))
if err != nil {
return nil, err
}
signer := &SignerClient{logger: logger, client: rpcClient}
// Check if reachable
version, err := signer.pingVersion()
if err != nil {
return nil, err
}
signer.status = fmt.Sprintf("ok [version=%v]", version)
return signer, nil
}
func NewSignerClientFromConfig(logger log.Logger, config CLIConfig) (*SignerClient, error) {
return NewSignerClient(logger, config.Endpoint, config.TLSConfig)
}
func (s *SignerClient) pingVersion() (string, error) {
var v string
ctx, cancel := context.WithTimeout(context.Background(), time.Second*3)
defer cancel()
if err := s.client.CallContext(ctx, &v, "health_status"); err != nil {
return "", err
}
return v, nil
}
func (s *SignerClient) SignTransaction(ctx context.Context, chainId *big.Int, tx *types.Transaction) (*types.Transaction, error) {
args := NewTransactionArgsFromTransaction(chainId, tx)
var result hexutil.Bytes
if err := s.client.CallContext(ctx, &result, "eth_signTransaction", args); err != nil {
return nil, fmt.Errorf("eth_signTransaction failed: %w", err)
}
signed := &types.Transaction{}
if err := signed.UnmarshalBinary(result); err != nil {
return nil, err
}
return signed, nil
}
package client
import (
"errors"
"github.com/urfave/cli"
opservice "github.com/ethereum-optimism/optimism/op-service"
optls "github.com/ethereum-optimism/optimism/op-service/tls"
)
const (
EndpointFlagName = "signer.endpoint"
AddressFlagName = "signer.address"
)
func CLIFlags(envPrefix string) []cli.Flag {
envPrefix += "_SIGNER"
flags := []cli.Flag{
cli.StringFlag{
Name: EndpointFlagName,
Usage: "Signer endpoint the client will connect to",
EnvVar: opservice.PrefixEnvVar(envPrefix, "ENDPOINT"),
},
cli.StringFlag{
Name: AddressFlagName,
Usage: "Address the signer is signing transactions for",
EnvVar: opservice.PrefixEnvVar(envPrefix, "ADDRESS"),
},
}
flags = append(flags, optls.CLIFlagsWithFlagPrefix(envPrefix, "signer")...)
return flags
}
type CLIConfig struct {
Endpoint string
Address string
TLSConfig optls.CLIConfig
}
func (c CLIConfig) Check() error {
if err := c.TLSConfig.Check(); err != nil {
return err
}
if !((c.Endpoint == "" && c.Address == "") || (c.Endpoint != "" && c.Address != "")) {
return errors.New("signer endpoint and address must both be set or not set")
}
return nil
}
func (c CLIConfig) Enabled() bool {
if c.Endpoint != "" && c.Address != "" {
return true
}
return false
}
func ReadCLIConfig(ctx *cli.Context) CLIConfig {
cfg := CLIConfig{
Endpoint: ctx.String(EndpointFlagName),
Address: ctx.String(AddressFlagName),
TLSConfig: optls.ReadCLIConfigWithPrefix(ctx, "signer"),
}
return cfg
}
package client
import (
"math/big"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/core/types"
)
// TransactionArgs represents the arguments to construct a new transaction
// or a message call.
type TransactionArgs struct {
From *common.Address `json:"from"`
To *common.Address `json:"to"`
Gas *hexutil.Uint64 `json:"gas"`
GasPrice *hexutil.Big `json:"gasPrice"`
MaxFeePerGas *hexutil.Big `json:"maxFeePerGas"`
MaxPriorityFeePerGas *hexutil.Big `json:"maxPriorityFeePerGas"`
Value *hexutil.Big `json:"value"`
Nonce *hexutil.Uint64 `json:"nonce"`
// We accept "data" and "input" for backwards-compatibility reasons.
// "input" is the newer name and should be preferred by clients.
// Issue detail: https://github.com/ethereum/go-ethereum/issues/15628
Data *hexutil.Bytes `json:"data"`
Input *hexutil.Bytes `json:"input"`
AccessList *types.AccessList `json:"accessList,omitempty"`
ChainID *hexutil.Big `json:"chainId,omitempty"`
}
// NewTransactionArgsFromTransaction creates a TransactionArgs struct from an EIP-1559 transaction
func NewTransactionArgsFromTransaction(chainId *big.Int, tx *types.Transaction) *TransactionArgs {
data := hexutil.Bytes(tx.Data())
nonce := hexutil.Uint64(tx.Nonce())
gas := hexutil.Uint64(tx.Gas())
accesses := tx.AccessList()
args := &TransactionArgs{
Input: &data,
Nonce: &nonce,
Value: (*hexutil.Big)(tx.Value()),
Gas: &gas,
To: tx.To(),
ChainID: (*hexutil.Big)(chainId),
MaxFeePerGas: (*hexutil.Big)(tx.GasFeeCap()),
MaxPriorityFeePerGas: (*hexutil.Big)(tx.GasTipCap()),
AccessList: &accesses,
}
return args
}
// data retrieves the transaction calldata. Input field is preferred.
func (args *TransactionArgs) data() []byte {
if args.Input != nil {
return *args.Input
}
if args.Data != nil {
return *args.Data
}
return nil
}
// ToTransaction converts the arguments to a transaction.
func (args *TransactionArgs) ToTransaction() *types.Transaction {
var data types.TxData
al := types.AccessList{}
if args.AccessList != nil {
al = *args.AccessList
}
data = &types.DynamicFeeTx{
To: args.To,
ChainID: (*big.Int)(args.ChainID),
Nonce: uint64(*args.Nonce),
Gas: uint64(*args.Gas),
GasFeeCap: (*big.Int)(args.MaxFeePerGas),
GasTipCap: (*big.Int)(args.MaxPriorityFeePerGas),
Value: (*big.Int)(args.Value),
Data: args.data(),
AccessList: al,
}
return types.NewTx(data)
}
module github.com/ethereum-optimism/optimism/op-signer
go 1.18
require (
github.com/dyson/certman v0.3.0
github.com/ethereum-optimism/optimism/op-service v0.10.10
github.com/ethereum/go-ethereum v1.10.26
github.com/urfave/cli v1.22.9
)
require (
github.com/btcsuite/btcd/btcec/v2 v2.2.0 // indirect
github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect
github.com/deckarep/golang-set v1.8.0 // indirect
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0 // indirect
github.com/fsnotify/fsnotify v1.6.0 // indirect
github.com/go-ole/go-ole v1.2.6 // indirect
github.com/go-stack/stack v1.8.1 // indirect
github.com/gorilla/websocket v1.5.0 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/rivo/uniseg v0.2.1-0.20211004051800-57c86be7915a // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect
github.com/shirou/gopsutil v3.21.11+incompatible // indirect
github.com/tklauser/go-sysconf v0.3.10 // indirect
github.com/tklauser/numcpus v0.4.0 // indirect
github.com/yusufpapurcu/wmi v1.2.2 // indirect
golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e // indirect
golang.org/x/sys v0.0.0-20221013171732-95e765b1cc43 // indirect
gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce // indirect
)
replace github.com/ethereum/go-ethereum v1.10.26 => github.com/ethereum-optimism/op-geth v0.0.0-20221216190603-60b51d600468
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/VictoriaMetrics/fastcache v1.9.0 h1:oMwsS6c8abz98B7ytAewQ7M1ZN/Im/iwKoE1euaFvhs=
github.com/btcsuite/btcd/btcec/v2 v2.2.0 h1:fzn1qaOt32TuLjFlkzYSsBC35Q3KUjT1SwPxiMSCF5k=
github.com/btcsuite/btcd/btcec/v2 v2.2.0/go.mod h1:U7MHm051Al6XmscBQ0BoNydpOTsFAn707034b5nY8zU=
github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1 h1:q0rUy8C/TYNBQS1+CGKw68tLOFYSNEs0TFnxxnS9+4U=
github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE=
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w=
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/deckarep/golang-set v1.8.0 h1:sk9/l/KqpunDwP7pSjUg0keiOOLEnOBHzykLrsPppp4=
github.com/deckarep/golang-set v1.8.0/go.mod h1:5nI87KwE7wgsBU1F4GKAw2Qod7p5kyS383rP6+o6qqo=
github.com/decred/dcrd/crypto/blake256 v1.0.0 h1:/8DMNYp9SGi5f0w7uCm6d6M4OU2rGFK09Y2A4Xv7EE0=
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0 h1:HbphB4TFFXpv7MNrT52FGrrgVXF1owhMVTHFZIlnvd4=
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0/go.mod h1:DZGJHZMqrU4JJqFAWUS2UO1+lbSKsdiOoYi9Zzey7Fc=
github.com/dyson/certman v0.3.0 h1:S7WCUim5faT/OiBhiY3u5cMaiC9MNKiA+8PJDXLaIYQ=
github.com/dyson/certman v0.3.0/go.mod h1:RMWlyA9op6D9SxOBRRX3sxnParehv9gf52WWUJPd1JA=
github.com/ethereum-optimism/op-geth v0.0.0-20221104231810-30db39cae2be h1:8TdM3M7FjZkrYeGGX9nEVtDDlZ5RiuHtc0mbi5bGKyY=
github.com/ethereum-optimism/op-geth v0.0.0-20221104231810-30db39cae2be/go.mod h1:1g9UmZgEINqvYfXmWOUCRJX9fxegeOHudVkLCRAXO5Y=
github.com/ethereum-optimism/optimism/op-service v0.10.10 h1:B5mGpATX6zPkDABoh6smCjh6Z5mA2KWh71MD1i6T5ww=
github.com/ethereum-optimism/optimism/op-service v0.10.10/go.mod h1:wbtHqi1fv00B3agj7a2zdP3OFanEfGZ23zPgGgFCF/c=
github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY=
github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw=
github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY=
github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
github.com/go-stack/stack v1.8.1 h1:ntEHSVwIt7PNXNpgPmVfMrNhLtgjlmnZha2kOpuRiDw=
github.com/go-stack/stack v1.8.1/go.mod h1:dcoOX6HbPZSZptuspn9bctJ+N/CnF5gGygcUP3XYfe4=
github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/holiman/big v0.0.0-20221017200358-a027dc42d04e h1:pIYdhNkDh+YENVNi3gto8n9hAmRxKxoar0iE6BLucjw=
github.com/mattn/go-runewidth v0.0.13 h1:lTGmDsbAYt5DmK6OnoV7EuIF1wEIFAcxld6ypU4OSgU=
github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/prometheus/tsdb v0.10.0 h1:If5rVCMTp6W2SiRAQFlbpJNgVlgMEd+U2GZckwK38ic=
github.com/rivo/uniseg v0.2.1-0.20211004051800-57c86be7915a h1:s7GrsqeorVkFR1vGmQ6WVL9nup0eyQCC+YVUeSQLH/Q=
github.com/rivo/uniseg v0.2.1-0.20211004051800-57c86be7915a/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/shirou/gopsutil v3.21.11+incompatible h1:+1+c1VGhc88SSonWP6foOcLhvnKlUeu/erjjvaPEYiI=
github.com/shirou/gopsutil v3.21.11+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
github.com/syndtr/goleveldb v1.0.1-0.20220614013038-64ee5596c38a h1:1ur3QoCqvE5fl+nylMaIr9PVV1w343YRDtsy+Rwu7XI=
github.com/tklauser/go-sysconf v0.3.10 h1:IJ1AZGZRWbY8T5Vfk04D9WOA5WSejdflXxP03OUqALw=
github.com/tklauser/go-sysconf v0.3.10/go.mod h1:C8XykCvCb+Gn0oNCWPIlcb0RuglQTYaQ2hGm7jmxEFk=
github.com/tklauser/numcpus v0.4.0 h1:E53Dm1HjH1/R2/aoCtXtPgzmElmn51aOkhCFSuZq//o=
github.com/tklauser/numcpus v0.4.0/go.mod h1:1+UI3pD8NW14VMwdgJNJ1ESk2UnwhAnz5hMwiKKqXCQ=
github.com/urfave/cli v1.22.9 h1:cv3/KhXGBGjEXLC4bH0sLuJ9BewaAbpk5oyMOveu4pw=
github.com/urfave/cli v1.22.9/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
github.com/yusufpapurcu/wmi v1.2.2 h1:KBNDSne4vP5mbSWnJbO+51IMOXJB67QiYCSBrubbPRg=
github.com/yusufpapurcu/wmi v1.2.2/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e h1:T8NU3HyQ8ClP4SEE+KbFlg6n0NhuTsN4MyznaarGsZM=
golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20221013171732-95e765b1cc43 h1:OK7RB6t2WQX54srQQYSXMW8dF5C6/8+oA/s5QBmmto4=
golang.org/x/sys v0.0.0-20221013171732-95e765b1cc43/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce h1:+JknDZhAj8YMt7GC73Ei8pv4MzjDUNPHgQWJdtMAaDU=
gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce/go.mod h1:5AcXVHNjg+BDxry382+8OKon8SEWiKktQR07RKPsv1c=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
...@@ -65,6 +65,7 @@ services: ...@@ -65,6 +65,7 @@ services:
--metrics.addr=0.0.0.0 --metrics.addr=0.0.0.0
--metrics.port=7300 --metrics.port=7300
--pprof.enabled --pprof.enabled
--rpc.enable-admin
ports: ports:
- "7545:8545" - "7545:8545"
- "9003:9003" - "9003:9003"
......
...@@ -48,6 +48,7 @@ COPY packages/fault-detector/package.json ./packages/fault-detector/package.json ...@@ -48,6 +48,7 @@ COPY packages/fault-detector/package.json ./packages/fault-detector/package.json
COPY packages/replica-healthcheck/package.json ./packages/replica-healthcheck/package.json COPY packages/replica-healthcheck/package.json ./packages/replica-healthcheck/package.json
COPY packages/drippie-mon/package.json ./packages/drippie-mon/package.json COPY packages/drippie-mon/package.json ./packages/drippie-mon/package.json
COPY packages/balance-monitor/package.json ./packages/balance-monitor/package.json COPY packages/balance-monitor/package.json ./packages/balance-monitor/package.json
COPY packages/two-step-monitor/package.json ./packages/two-step-monitor/package.json
COPY integration-tests/package.json ./integration-tests/package.json COPY integration-tests/package.json ./integration-tests/package.json
RUN yarn install --frozen-lockfile && yarn cache clean RUN yarn install --frozen-lockfile && yarn cache clean
...@@ -111,3 +112,7 @@ ENTRYPOINT ["npm", "run", "start"] ...@@ -111,3 +112,7 @@ ENTRYPOINT ["npm", "run", "start"]
FROM base as balance-monitor FROM base as balance-monitor
WORKDIR /opt/optimism/packages/balance-monitor WORKDIR /opt/optimism/packages/balance-monitor
ENTRYPOINT ["yarn", "run", "start:prod"] ENTRYPOINT ["yarn", "run", "start:prod"]
FROM base as two-step-monitor
WORKDIR /opt/optimism/packages/two-step-monitor
ENTRYPOINT ["yarn", "run", "start"]
# @eth-optimism/actor-tests # @eth-optimism/actor-tests
## 0.0.18
### Patch Changes
- Updated dependencies [4964be480]
- @eth-optimism/contracts-bedrock@0.11.3
- @eth-optimism/sdk@1.10.1
## 0.0.17 ## 0.0.17
### Patch Changes ### Patch Changes
......
{ {
"name": "@eth-optimism/actor-tests", "name": "@eth-optimism/actor-tests",
"version": "0.0.17", "version": "0.0.18",
"description": "A library and suite of tests to stress test Optimism Bedrock.", "description": "A library and suite of tests to stress test Optimism Bedrock.",
"license": "MIT", "license": "MIT",
"author": "", "author": "",
...@@ -18,9 +18,9 @@ ...@@ -18,9 +18,9 @@
"test:coverage": "yarn test" "test:coverage": "yarn test"
}, },
"dependencies": { "dependencies": {
"@eth-optimism/contracts-bedrock": "0.11.2", "@eth-optimism/contracts-bedrock": "0.11.3",
"@eth-optimism/core-utils": "^0.12.0", "@eth-optimism/core-utils": "^0.12.0",
"@eth-optimism/sdk": "^1.9.1", "@eth-optimism/sdk": "^1.10.1",
"@types/chai": "^4.2.18", "@types/chai": "^4.2.18",
"@types/chai-as-promised": "^7.1.4", "@types/chai-as-promised": "^7.1.4",
"async-mutex": "^0.3.2", "async-mutex": "^0.3.2",
......
# @eth-optimism/common-ts # @eth-optimism/common-ts
## 0.7.1
### Patch Changes
- f04e5db2d: Fix unknown option error in base service v2
## 0.7.0 ## 0.7.0
### Minor Changes ### Minor Changes
......
{ {
"name": "@eth-optimism/common-ts", "name": "@eth-optimism/common-ts",
"version": "0.7.0", "version": "0.7.1",
"description": "[Optimism] Advanced typescript tooling used by various services", "description": "[Optimism] Advanced typescript tooling used by various services",
"main": "dist/index", "main": "dist/index",
"types": "dist/index", "types": "dist/index",
......
...@@ -156,7 +156,7 @@ export abstract class BaseServiceV2< ...@@ -156,7 +156,7 @@ export abstract class BaseServiceV2<
// Use commander as a way to communicate info about the service. We don't actually *use* // Use commander as a way to communicate info about the service. We don't actually *use*
// commander for anything besides the ability to run `ts-node ./service.ts --help`. // commander for anything besides the ability to run `ts-node ./service.ts --help`.
const program = new Command() const program = new Command().allowUnknownOption(true)
for (const [optionName, optionSpec] of Object.entries(params.optionsSpec)) { for (const [optionName, optionSpec] of Object.entries(params.optionsSpec)) {
// Skip options that are not meant to be used by the user. // Skip options that are not meant to be used by the user.
if (['useEnv', 'useArgv'].includes(optionName)) { if (['useEnv', 'useArgv'].includes(optionName)) {
......
...@@ -20,20 +20,17 @@ export const waitForProvider = async ( ...@@ -20,20 +20,17 @@ export const waitForProvider = async (
name?: string name?: string
} }
) => { ) => {
opts?.logger?.info(`waiting for ${opts?.name || 'target'} provider...`) const name = opts?.name || 'target'
opts?.logger?.info(`waiting for ${name} provider...`)
let connected = false let connected = false
while (!connected) { while (!connected) {
try { try {
await provider.getBlockNumber() await provider.getBlockNumber()
connected = true connected = true
} catch (e) { } catch (e) {
opts?.logger?.info(`${provider} provider not connected, retrying...`) opts?.logger?.info(`${name} provider not connected, retrying...`)
// Don't spam requests
await sleep(opts?.intervalMs || 15000) await sleep(opts?.intervalMs || 15000)
} }
} }
opts?.logger?.info(`${name} provider connected`)
opts?.logger?.info(`${opts?.name || 'target'} provider connected`)
} }
GasBenchMark_L1CrossDomainMessenger:test_sendMessage_benchmark_0() (gas: 261344) GasBenchMark_L1CrossDomainMessenger:test_sendMessage_benchmark_0() (gas: 261344)
GasBenchMark_L1CrossDomainMessenger:test_sendMessage_benchmark_1() (gas: 75851) GasBenchMark_L1CrossDomainMessenger:test_sendMessage_benchmark_1() (gas: 75851)
GasBenchMark_L1StandardBridge_Deposit:test_depositERC20_benchmark_0() (gas: 348151) GasBenchMark_L1StandardBridge_Deposit:test_depositERC20_benchmark_0() (gas: 348207)
GasBenchMark_L1StandardBridge_Deposit:test_depositERC20_benchmark_1() (gas: 112583) GasBenchMark_L1StandardBridge_Deposit:test_depositERC20_benchmark_1() (gas: 112639)
GasBenchMark_L1StandardBridge_Deposit:test_depositETH_benchmark_0() (gas: 348173) GasBenchMark_L1StandardBridge_Deposit:test_depositETH_benchmark_0() (gas: 348229)
GasBenchMark_L1StandardBridge_Deposit:test_depositETH_benchmark_1() (gas: 112604) GasBenchMark_L1StandardBridge_Deposit:test_depositETH_benchmark_1() (gas: 112660)
GasBenchMark_L1StandardBridge_Finalize:test_finalizeETHWithdrawal_benchmark() (gas: 40502) GasBenchMark_L1StandardBridge_Finalize:test_finalizeETHWithdrawal_benchmark() (gas: 40502)
GasBenchMark_L2OutputOracle:test_proposeL2Output_benchmark() (gas: 88513) GasBenchMark_L2OutputOracle:test_proposeL2Output_benchmark() (gas: 88513)
GasBenchMark_OptimismPortal:test_depositTransaction_benchmark() (gas: 74998) GasBenchMark_OptimismPortal:test_depositTransaction_benchmark() (gas: 74998)
...@@ -92,22 +92,23 @@ L1ERC721Bridge_Test:test_finalizeBridgeERC721_notFromRemoteMessenger_reverts() ( ...@@ -92,22 +92,23 @@ L1ERC721Bridge_Test:test_finalizeBridgeERC721_notFromRemoteMessenger_reverts() (
L1ERC721Bridge_Test:test_finalizeBridgeERC721_notViaLocalMessenger_reverts() (gas: 16093) L1ERC721Bridge_Test:test_finalizeBridgeERC721_notViaLocalMessenger_reverts() (gas: 16093)
L1ERC721Bridge_Test:test_finalizeBridgeERC721_selfToken_reverts() (gas: 17593) L1ERC721Bridge_Test:test_finalizeBridgeERC721_selfToken_reverts() (gas: 17593)
L1ERC721Bridge_Test:test_finalizeBridgeERC721_succeeds() (gas: 323814) L1ERC721Bridge_Test:test_finalizeBridgeERC721_succeeds() (gas: 323814)
L1StandardBridge_DepositERC20To_Test:test_depositERC20To_succeeds() (gas: 575959) L1StandardBridge_DepositERC20To_Test:test_depositERC20To_succeeds() (gas: 624279)
L1StandardBridge_DepositERC20_Test:test_depositERC20_succeeds() (gas: 573786) L1StandardBridge_DepositERC20_Test:test_depositERC20_succeeds() (gas: 621958)
L1StandardBridge_DepositERC20_TestFail:test_depositERC20_notEoa_reverts() (gas: 22320) L1StandardBridge_DepositERC20_TestFail:test_depositERC20_notEoa_reverts() (gas: 22320)
L1StandardBridge_DepositETHTo_Test:test_depositETHTo_succeeds() (gas: 324712) L1StandardBridge_DepositETHTo_Test:test_depositETHTo_succeeds() (gas: 358590)
L1StandardBridge_DepositETH_Test:test_depositETH_succeeds() (gas: 367539) L1StandardBridge_DepositETH_Test:test_depositETH_succeeds() (gas: 401413)
L1StandardBridge_DepositETH_TestFail:test_depositETH_notEoa_reverts() (gas: 40780) L1StandardBridge_DepositETH_TestFail:test_depositETH_notEoa_reverts() (gas: 40780)
L1StandardBridge_FinalizeBridgeETH_Test:test_finalizeBridgeETH_succeeds() (gas: 48661)
L1StandardBridge_FinalizeBridgeETH_TestFail:test_finalizeBridgeETH_incorrectValue_reverts() (gas: 34207) L1StandardBridge_FinalizeBridgeETH_TestFail:test_finalizeBridgeETH_incorrectValue_reverts() (gas: 34207)
L1StandardBridge_FinalizeBridgeETH_TestFail:test_finalizeBridgeETH_sendToMessenger_reverts() (gas: 34288) L1StandardBridge_FinalizeBridgeETH_TestFail:test_finalizeBridgeETH_sendToMessenger_reverts() (gas: 34288)
L1StandardBridge_FinalizeBridgeETH_TestFail:test_finalizeBridgeETH_sendToSelf_reverts() (gas: 34257) L1StandardBridge_FinalizeBridgeETH_TestFail:test_finalizeBridgeETH_sendToSelf_reverts() (gas: 34257)
L1StandardBridge_FinalizeERC20Withdrawal_Test:test_finalizeERC20Withdrawal_succeeds() (gas: 492896) L1StandardBridge_FinalizeERC20Withdrawal_Test:test_finalizeERC20Withdrawal_succeeds() (gas: 495885)
L1StandardBridge_FinalizeERC20Withdrawal_TestFail:test_finalizeERC20Withdrawal_notMessenger_reverts() (gas: 31148) L1StandardBridge_FinalizeERC20Withdrawal_TestFail:test_finalizeERC20Withdrawal_notMessenger_reverts() (gas: 31148)
L1StandardBridge_FinalizeERC20Withdrawal_TestFail:test_finalizeERC20Withdrawal_notOtherBridge_reverts() (gas: 31504) L1StandardBridge_FinalizeERC20Withdrawal_TestFail:test_finalizeERC20Withdrawal_notOtherBridge_reverts() (gas: 31504)
L1StandardBridge_FinalizeETHWithdrawal_Test:test_finalizeETHWithdrawal_succeeds() (gas: 58686) L1StandardBridge_FinalizeETHWithdrawal_Test:test_finalizeETHWithdrawal_succeeds() (gas: 58686)
L1StandardBridge_Getter_Test:test_getters_succeeds() (gas: 31449) L1StandardBridge_Getter_Test:test_getters_succeeds() (gas: 32151)
L1StandardBridge_Initialize_Test:test_initialize_succeeds() (gas: 22005) L1StandardBridge_Initialize_Test:test_initialize_succeeds() (gas: 22005)
L1StandardBridge_Receive_Test:test_receive_succeeds() (gas: 514475) L1StandardBridge_Receive_Test:test_receive_succeeds() (gas: 519995)
L2CrossDomainMessenger_Test:test_messageVersion_succeeds() (gas: 8389) L2CrossDomainMessenger_Test:test_messageVersion_succeeds() (gas: 8389)
L2CrossDomainMessenger_Test:test_pause_notOwner_reverts() (gas: 10837) L2CrossDomainMessenger_Test:test_pause_notOwner_reverts() (gas: 10837)
L2CrossDomainMessenger_Test:test_pause_succeeds() (gas: 31846) L2CrossDomainMessenger_Test:test_pause_succeeds() (gas: 31846)
...@@ -163,16 +164,17 @@ L2OutputOracleUpgradeable_Test:test_initValuesOnProxy_succeeds() (gas: 26093) ...@@ -163,16 +164,17 @@ L2OutputOracleUpgradeable_Test:test_initValuesOnProxy_succeeds() (gas: 26093)
L2OutputOracleUpgradeable_Test:test_initializeImpl_alreadyInitialized_reverts() (gas: 15149) L2OutputOracleUpgradeable_Test:test_initializeImpl_alreadyInitialized_reverts() (gas: 15149)
L2OutputOracleUpgradeable_Test:test_initializeProxy_alreadyInitialized_reverts() (gas: 20131) L2OutputOracleUpgradeable_Test:test_initializeProxy_alreadyInitialized_reverts() (gas: 20131)
L2OutputOracleUpgradeable_Test:test_upgrading_succeeds() (gas: 180413) L2OutputOracleUpgradeable_Test:test_upgrading_succeeds() (gas: 180413)
L2StandardBridge_FinalizeBridgeETH_Test:test_finalizeBridgeETH_succeeds() (gas: 36076)
L2StandardBridge_Test:test_finalizeBridgeETH_incorrectValue_reverts() (gas: 23843) L2StandardBridge_Test:test_finalizeBridgeETH_incorrectValue_reverts() (gas: 23843)
L2StandardBridge_Test:test_finalizeBridgeETH_sendToMessenger_reverts() (gas: 23982) L2StandardBridge_Test:test_finalizeBridgeETH_sendToMessenger_reverts() (gas: 23982)
L2StandardBridge_Test:test_finalizeBridgeETH_sendToSelf_reverts() (gas: 23893) L2StandardBridge_Test:test_finalizeBridgeETH_sendToSelf_reverts() (gas: 23893)
L2StandardBridge_Test:test_finalizeDeposit_succeeds() (gas: 89473) L2StandardBridge_Test:test_finalizeDeposit_succeeds() (gas: 90641)
L2StandardBridge_Test:test_initialize_succeeds() (gas: 24270) L2StandardBridge_Test:test_initialize_succeeds() (gas: 24270)
L2StandardBridge_Test:test_receive_succeeds() (gas: 131905) L2StandardBridge_Test:test_receive_succeeds() (gas: 176698)
L2StandardBridge_Test:test_withdrawTo_succeeds() (gas: 344660) L2StandardBridge_Test:test_withdrawTo_succeeds() (gas: 384552)
L2StandardBridge_Test:test_withdraw_insufficientValue_reverts() (gas: 19630) L2StandardBridge_Test:test_withdraw_insufficientValue_reverts() (gas: 19627)
L2StandardBridge_Test:test_withdraw_notEOA_reverts() (gas: 251798) L2StandardBridge_Test:test_withdraw_notEOA_reverts() (gas: 251836)
L2StandardBridge_Test:test_withdraw_succeeds() (gas: 343975) L2StandardBridge_Test:test_withdraw_succeeds() (gas: 382649)
L2ToL1MessagePasserTest:test_burn_succeeds() (gas: 112572) L2ToL1MessagePasserTest:test_burn_succeeds() (gas: 112572)
L2ToL1MessagePasserTest:test_initiateWithdrawal_fromContract_succeeds() (gas: 70423) L2ToL1MessagePasserTest:test_initiateWithdrawal_fromContract_succeeds() (gas: 70423)
L2ToL1MessagePasserTest:test_initiateWithdrawal_fromEOA_succeeds() (gas: 75874) L2ToL1MessagePasserTest:test_initiateWithdrawal_fromEOA_succeeds() (gas: 75874)
......
# @eth-optimism/contracts-bedrock # @eth-optimism/contracts-bedrock
## 0.11.3
### Patch Changes
- 4964be480: Added a test for large deposit gaps
## 0.11.2 ## 0.11.2
### Patch Changes ### Patch Changes
......
...@@ -91,15 +91,22 @@ contract L1StandardBridge is StandardBridge, Semver { ...@@ -91,15 +91,22 @@ contract L1StandardBridge is StandardBridge, Semver {
); );
/** /**
* @custom:semver 1.0.0 * @custom:semver 1.1.0
* *
* @param _messenger Address of the L1CrossDomainMessenger. * @param _messenger Address of the L1CrossDomainMessenger.
*/ */
constructor(address payable _messenger) constructor(address payable _messenger)
Semver(1, 0, 0) Semver(1, 1, 0)
StandardBridge(_messenger, payable(Predeploys.L2_STANDARD_BRIDGE)) StandardBridge(_messenger, payable(Predeploys.L2_STANDARD_BRIDGE))
{} {}
/**
* @notice Allows EOAs to bridge ETH by sending directly to the bridge.
*/
receive() external payable override onlyEOA {
_initiateETHDeposit(msg.sender, msg.sender, RECEIVE_DEFAULT_GAS_LIMIT, bytes(""));
}
/** /**
* @custom:legacy * @custom:legacy
* @notice Finalizes a withdrawal of ERC20 tokens from L2. * @notice Finalizes a withdrawal of ERC20 tokens from L2.
...@@ -261,7 +268,7 @@ contract L1StandardBridge is StandardBridge, Semver { ...@@ -261,7 +268,7 @@ contract L1StandardBridge is StandardBridge, Semver {
address _from, address _from,
address _to, address _to,
uint32 _minGasLimit, uint32 _minGasLimit,
bytes calldata _extraData bytes memory _extraData
) internal { ) internal {
emit ETHDepositInitiated(_from, _to, msg.value, _extraData); emit ETHDepositInitiated(_from, _to, msg.value, _extraData);
_initiateBridgeETH(_from, _to, msg.value, _minGasLimit, _extraData); _initiateBridgeETH(_from, _to, msg.value, _minGasLimit, _extraData);
...@@ -285,7 +292,7 @@ contract L1StandardBridge is StandardBridge, Semver { ...@@ -285,7 +292,7 @@ contract L1StandardBridge is StandardBridge, Semver {
address _to, address _to,
uint256 _amount, uint256 _amount,
uint32 _minGasLimit, uint32 _minGasLimit,
bytes calldata _extraData bytes memory _extraData
) internal { ) internal {
emit ERC20DepositInitiated(_l1Token, _l2Token, _from, _to, _amount, _extraData); emit ERC20DepositInitiated(_l1Token, _l2Token, _from, _to, _amount, _extraData);
_initiateBridgeERC20(_l1Token, _l2Token, _from, _to, _amount, _minGasLimit, _extraData); _initiateBridgeERC20(_l1Token, _l2Token, _from, _to, _amount, _minGasLimit, _extraData);
......
...@@ -59,15 +59,29 @@ contract L2StandardBridge is StandardBridge, Semver { ...@@ -59,15 +59,29 @@ contract L2StandardBridge is StandardBridge, Semver {
); );
/** /**
* @custom:semver 1.0.0 * @custom:semver 1.1.0
* *
* @param _otherBridge Address of the L1StandardBridge. * @param _otherBridge Address of the L1StandardBridge.
*/ */
constructor(address payable _otherBridge) constructor(address payable _otherBridge)
Semver(1, 0, 0) Semver(1, 1, 0)
StandardBridge(payable(Predeploys.L2_CROSS_DOMAIN_MESSENGER), _otherBridge) StandardBridge(payable(Predeploys.L2_CROSS_DOMAIN_MESSENGER), _otherBridge)
{} {}
/**
* @notice Allows EOAs to bridge ETH by sending directly to the bridge.
*/
receive() external payable override onlyEOA {
_initiateWithdrawal(
Predeploys.LEGACY_ERC20_ETH,
msg.sender,
msg.sender,
msg.value,
RECEIVE_DEFAULT_GAS_LIMIT,
bytes("")
);
}
/** /**
* @custom:legacy * @custom:legacy
* @notice Initiates a withdrawal from L2 to L1. * @notice Initiates a withdrawal from L2 to L1.
...@@ -165,7 +179,7 @@ contract L2StandardBridge is StandardBridge, Semver { ...@@ -165,7 +179,7 @@ contract L2StandardBridge is StandardBridge, Semver {
address _to, address _to,
uint256 _amount, uint256 _amount,
uint32 _minGasLimit, uint32 _minGasLimit,
bytes calldata _extraData bytes memory _extraData
) internal { ) internal {
address l1Token = OptimismMintableERC20(_l2Token).l1Token(); address l1Token = OptimismMintableERC20(_l2Token).l1Token();
if (_l2Token == Predeploys.LEGACY_ERC20_ETH) { if (_l2Token == Predeploys.LEGACY_ERC20_ETH) {
......
...@@ -164,11 +164,10 @@ abstract contract StandardBridge { ...@@ -164,11 +164,10 @@ abstract contract StandardBridge {
} }
/** /**
* @notice Allows EOAs to deposit ETH by sending directly to the bridge. * @notice Allows EOAs to bridge ETH by sending directly to the bridge.
* Must be implemented by contracts that inherit.
*/ */
receive() external payable onlyEOA { receive() external payable virtual;
_initiateBridgeETH(msg.sender, msg.sender, msg.value, RECEIVE_DEFAULT_GAS_LIMIT, bytes(""));
}
/** /**
* @custom:legacy * @custom:legacy
...@@ -401,7 +400,7 @@ abstract contract StandardBridge { ...@@ -401,7 +400,7 @@ abstract contract StandardBridge {
address _to, address _to,
uint256 _amount, uint256 _amount,
uint32 _minGasLimit, uint32 _minGasLimit,
bytes calldata _extraData bytes memory _extraData
) internal { ) internal {
if (_isOptimismMintableERC20(_localToken)) { if (_isOptimismMintableERC20(_localToken)) {
require( require(
......
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.
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.
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