Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions common/testcontainers/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ services:

# Sets up the genesis configuration for the go-ethereum client from a JSON file.
geth-genesis:
image: "ethereum/client-go:v1.13.14"
image: "ethereum/client-go:v1.14.0"
command: --datadir=/data/execution init /data/execution/genesis.json
volumes:
- data:/data
Expand Down Expand Up @@ -80,7 +80,7 @@ services:
# Runs the go-ethereum execution client with the specified, unlocked account and necessary
# APIs to allow for proof-of-stake consensus via Prysm.
geth:
image: "ethereum/client-go:v1.13.14"
image: "ethereum/client-go:v1.14.0"
command:
- --http
- --http.api=eth,net,web3
Expand Down
2 changes: 1 addition & 1 deletion common/testcontainers/docker/l1geth/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM ethereum/client-go:v1.13.14
FROM ethereum/client-go:v1.14.0

COPY password /l1geth/
COPY genesis.json /l1geth/
Expand Down
7 changes: 3 additions & 4 deletions common/testcontainers/testcontainers.go
Original file line number Diff line number Diff line change
Expand Up @@ -167,13 +167,13 @@ func (t *TestcontainerApps) GetPoSL1EndPoint() (string, error) {
return contrainer.PortEndpoint(context.Background(), "8545/tcp", "http")
}

// GetPoSL1Client returns a ethclient by dialing running PoS L1 client
func (t *TestcontainerApps) GetPoSL1Client() (*ethclient.Client, error) {
// GetPoSL1Client returns a raw rpc client by dialing the L1 node
func (t *TestcontainerApps) GetPoSL1Client() (*rpc.Client, error) {
endpoint, err := t.GetPoSL1EndPoint()
if err != nil {
return nil, err
}
return ethclient.Dial(endpoint)
return rpc.Dial(endpoint)
}

// GetDBEndPoint returns the endpoint of the running postgres container
Expand Down Expand Up @@ -221,7 +221,6 @@ func (t *TestcontainerApps) GetGormDBClient() (*gorm.DB, error) {

// GetL2GethClient returns a ethclient by dialing running L2Geth
func (t *TestcontainerApps) GetL2GethClient() (*ethclient.Client, error) {

rpcCli, err := t.GetL2Client()
if err != nil {
return nil, err
Expand Down
10 changes: 4 additions & 6 deletions common/testcontainers/testcontainers_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package testcontainers
import (
"testing"

"github.com/scroll-tech/go-ethereum/ethclient"
"github.com/stretchr/testify/assert"
"gorm.io/gorm"
)
Expand All @@ -14,7 +13,6 @@ func TestNewTestcontainerApps(t *testing.T) {
err error
endpoint string
gormDBclient *gorm.DB
ethclient *ethclient.Client
)

testApps := NewTestcontainerApps()
Expand All @@ -32,17 +30,17 @@ func TestNewTestcontainerApps(t *testing.T) {
endpoint, err = testApps.GetL2GethEndPoint()
assert.NoError(t, err)
assert.NotEmpty(t, endpoint)
ethclient, err = testApps.GetL2GethClient()
l2RawClient, err := testApps.GetL2Client()
assert.NoError(t, err)
assert.NotNil(t, ethclient)
assert.NotNil(t, l2RawClient)

assert.NoError(t, testApps.StartPoSL1Container())
endpoint, err = testApps.GetPoSL1EndPoint()
assert.NoError(t, err)
assert.NotEmpty(t, endpoint)
ethclient, err = testApps.GetPoSL1Client()
l1RawClient, err := testApps.GetPoSL1Client()
assert.NoError(t, err)
assert.NotNil(t, ethclient)
assert.NotNil(t, l1RawClient)

assert.NoError(t, testApps.StartWeb3SignerContainer(1))
endpoint, err = testApps.GetWeb3SignerEndpoint()
Expand Down
2 changes: 1 addition & 1 deletion common/version/version.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import (
"runtime/debug"
)

var tag = "v4.7.5"
var tag = "v4.7.6"

var commit = func() string {
if info, ok := debug.ReadBuildInfo(); ok {
Expand Down
15 changes: 12 additions & 3 deletions rollup/cmd/gas_oracle/app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,17 +66,26 @@ func action(ctx *cli.Context) error {
registry := prometheus.DefaultRegisterer
observability.Server(ctx, db)

l1client, err := ethclient.Dial(cfg.L1Config.Endpoint)
// Init L1 connection
l1RpcClient, err := rpc.Dial(cfg.L1Config.Endpoint)
if err != nil {
log.Crit("failed to connect l1 geth", "config file", cfgFile, "error", err)
log.Crit("failed to dial raw RPC client to L1 endpoint", "endpoint", cfg.L1Config.Endpoint, "error", err)
}
l1client := ethclient.NewClient(l1RpcClient)

l1watcher := watcher.NewL1WatcherClient(ctx.Context, l1client, cfg.L1Config.StartHeight, db, registry)
// sanity check config
if cfg.L1Config.RelayerConfig.GasOracleConfig.L1BaseFeeLimit == 0 || cfg.L1Config.RelayerConfig.GasOracleConfig.L1BlobBaseFeeLimit == 0 {
log.Crit("gas-oracle `l1_base_fee_limit` and `l1_blob_base_fee_limit` configs must be set")
}

// Init watcher and relayer
l1watcher := watcher.NewL1WatcherClient(ctx.Context, l1RpcClient, cfg.L1Config.StartHeight, db, registry)

l1relayer, err := relayer.NewLayer1Relayer(ctx.Context, db, cfg.L1Config.RelayerConfig, relayer.ServiceTypeL1GasOracle, registry)
if err != nil {
log.Crit("failed to create new l1 relayer", "config file", cfgFile, "error", err)
}

// Start l1 watcher process
go utils.LoopWithContext(subCtx, 10*time.Second, func(ctx context.Context) {
// Fetch the latest block number to decrease the delay when fetching gas prices
Expand Down
4 changes: 3 additions & 1 deletion rollup/conf/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,9 @@
"check_committed_batches_window_minutes": 5,
"l1_base_fee_default": 15000000000,
"l1_blob_base_fee_default": 1,
"l1_blob_base_fee_threshold": 0
"l1_blob_base_fee_threshold": 0,
"l1_base_fee_limit": 20000000000,
"l1_blob_base_fee_limit": 20000000000
},
"gas_oracle_sender_signer_config": {
"signer_type": "PrivateKey",
Expand Down
2 changes: 1 addition & 1 deletion rollup/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ require (
github.com/cpuguy83/go-md2man/v2 v2.0.3 // indirect
github.com/crate-crypto/go-eth-kzg v1.4.0 // indirect
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
github.com/deckarep/golang-set v0.0.0-20180603214616-504e848d77ea // indirect
github.com/deckarep/golang-set v1.8.0 // indirect
github.com/edsrzf/mmap-go v1.0.0 // indirect
github.com/ethereum/c-kzg-4844/v2 v2.1.5 // indirect
github.com/fjl/memsize v0.0.2 // indirect
Expand Down
4 changes: 2 additions & 2 deletions rollup/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -88,8 +88,8 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/deckarep/golang-set v0.0.0-20180603214616-504e848d77ea h1:j4317fAZh7X6GqbFowYdYdI0L9bwxL07jyPZIdepyZ0=
github.com/deckarep/golang-set v0.0.0-20180603214616-504e848d77ea/go.mod h1:93vsz/8Wt4joVM7c2AVqh+YRMiUSc14yDtF28KmMOgQ=
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/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
github.com/edsrzf/mmap-go v1.0.0 h1:CEBF7HpRnUCSJgGUb5h1Gm7e3VkmVDrR8lvWVLtrOFw=
github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M=
Expand Down
4 changes: 4 additions & 0 deletions rollup/internal/config/relayer.go
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,10 @@ type GasOracleConfig struct {
L1BaseFeeDefault uint64 `json:"l1_base_fee_default"`
L1BlobBaseFeeDefault uint64 `json:"l1_blob_base_fee_default"`

// Upper limit values for gas oracle updates
L1BaseFeeLimit uint64 `json:"l1_base_fee_limit"`
L1BlobBaseFeeLimit uint64 `json:"l1_blob_base_fee_limit"`

// L1BlobBaseFeeThreshold the threshold of L1 blob base fee to enter the default gas price mode
L1BlobBaseFeeThreshold uint64 `json:"l1_blob_base_fee_threshold"`
}
Expand Down
12 changes: 12 additions & 0 deletions rollup/internal/controller/relayer/l1_relayer.go
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,18 @@ func (r *Layer1Relayer) ProcessGasPriceOracle() {
} else if err != nil {
return
}
// Cap base fee update at the configured upper limit
if limit := r.cfg.GasOracleConfig.L1BaseFeeLimit; baseFee > limit {
log.Error("L1 base fee exceed max limit, set to max limit", "baseFee", baseFee, "maxLimit", limit)
r.metrics.rollupL1RelayerGasPriceOracleFeeOverLimitTotal.Inc()
baseFee = limit
}
// Cap blob base fee update at the configured upper limit
if limit := r.cfg.GasOracleConfig.L1BlobBaseFeeLimit; blobBaseFee > limit {
log.Error("L1 blob base fee exceed max limit, set to max limit", "blobBaseFee", blobBaseFee, "maxLimit", limit)
r.metrics.rollupL1RelayerGasPriceOracleFeeOverLimitTotal.Inc()
blobBaseFee = limit
}
data, err := r.l1GasOracleABI.Pack("setL1BaseFeeAndBlobBaseFee", new(big.Int).SetUint64(baseFee), new(big.Int).SetUint64(blobBaseFee))
if err != nil {
log.Error("Failed to pack setL1BaseFeeAndBlobBaseFee", "block.Hash", block.Hash, "block.Height", block.Number, "block.BaseFee", baseFee, "block.BlobBaseFee", blobBaseFee, "err", err)
Expand Down
15 changes: 10 additions & 5 deletions rollup/internal/controller/relayer/l1_relayer_metrics.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,12 @@ import (
)

type l1RelayerMetrics struct {
rollupL1RelayerGasPriceOraclerRunTotal prometheus.Counter
rollupL1RelayerLatestBaseFee prometheus.Gauge
rollupL1RelayerLatestBlobBaseFee prometheus.Gauge
rollupL1UpdateGasOracleConfirmedTotal prometheus.Counter
rollupL1UpdateGasOracleConfirmedFailedTotal prometheus.Counter
rollupL1RelayerGasPriceOraclerRunTotal prometheus.Counter
rollupL1RelayerLatestBaseFee prometheus.Gauge
rollupL1RelayerLatestBlobBaseFee prometheus.Gauge
rollupL1UpdateGasOracleConfirmedTotal prometheus.Counter
rollupL1UpdateGasOracleConfirmedFailedTotal prometheus.Counter
rollupL1RelayerGasPriceOracleFeeOverLimitTotal prometheus.Counter
}

var (
Expand Down Expand Up @@ -43,6 +44,10 @@ func initL1RelayerMetrics(reg prometheus.Registerer) *l1RelayerMetrics {
Name: "rollup_layer1_update_gas_oracle_confirmed_failed_total",
Help: "The total number of updating layer1 gas oracle confirmed failed",
}),
rollupL1RelayerGasPriceOracleFeeOverLimitTotal: promauto.With(reg).NewCounter(prometheus.CounterOpts{
Name: "rollup_layer1_gas_price_oracle_fee_over_limit_total",
Help: "The total number of times when a gas price oracle fee update went over the configured limit",
}),
}
})
return l1RelayerMetric
Expand Down
3 changes: 2 additions & 1 deletion rollup/internal/controller/sender/estimategas.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package sender

import (
"errors"
"fmt"
"math/big"

"github.com/scroll-tech/go-ethereum"
Expand Down Expand Up @@ -118,7 +119,7 @@ func (s *Sender) estimateGasLimit(to *common.Address, data []byte, sidecar *type

gasLimitWithoutAccessList, err := s.client.EstimateGas(s.ctx, msg)
if err != nil {
log.Error("estimateGasLimit EstimateGas failure without access list", "error", err)
log.Error("estimateGasLimit EstimateGas failure without access list", "error", err, "msg", fmt.Sprintf("%+v", msg))
return 0, nil, err
}

Expand Down
19 changes: 16 additions & 3 deletions rollup/internal/controller/sender/sender.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import (
"github.com/holiman/uint256"
"github.com/prometheus/client_golang/prometheus"
"github.com/scroll-tech/go-ethereum/common"
"github.com/scroll-tech/go-ethereum/consensus/misc"
"github.com/scroll-tech/go-ethereum/common/hexutil"
gethTypes "github.com/scroll-tech/go-ethereum/core/types"
"github.com/scroll-tech/go-ethereum/crypto/kzg4844"
"github.com/scroll-tech/go-ethereum/ethclient"
Expand Down Expand Up @@ -67,7 +67,8 @@ type FeeData struct {
// Sender Transaction sender to send transaction to l1/l2
type Sender struct {
config *config.SenderConfig
gethClient *gethclient.Client
rpcClient *rpc.Client // Raw RPC client
gethClient *gethclient.Client // Client to use for CreateAccessList
client *ethclient.Client // The client to retrieve on chain data (read-only)
writeClients []*ethclient.Client // The clients to send transactions to (write operations)
transactionSigner *TransactionSigner
Expand Down Expand Up @@ -141,6 +142,7 @@ func NewSender(ctx context.Context, config *config.SenderConfig, signerConfig *c
sender := &Sender{
ctx: ctx,
config: config,
rpcClient: rpcClient,
gethClient: gethclient.New(rpcClient),
client: client,
writeClients: writeClients,
Expand Down Expand Up @@ -841,8 +843,19 @@ func (s *Sender) getBlockNumberAndTimestampAndBaseFeeAndBlobFee(ctx context.Cont

var blobBaseFee uint64
if excess := header.ExcessBlobGas; excess != nil {
blobBaseFee = misc.CalcBlobFee(*excess).Uint64()
// Leave it up to the L1 node to compute the correct blob base fee.
// Previously we would compute it locally using `CalcBlobFee`, but
// that approach requires syncing any future L1 configuration changes.
// Note: The fetched blob base fee might not correspond to the block
// that we fetched in the previous step, but this is acceptable.
var blobBaseFeeHex hexutil.Big
if err := s.rpcClient.CallContext(ctx, &blobBaseFeeHex, "eth_blobBaseFee"); err != nil {
return 0, 0, 0, 0, fmt.Errorf("failed to call eth_blobBaseFee, err: %w", err)
}
// A correct L1 node could not return a value that overflows uint64
blobBaseFee = blobBaseFeeHex.ToInt().Uint64()
}

// header.Number.Uint64() returns the pendingBlockNumber, so we minus 1 to get the latestBlockNumber.
return header.Number.Uint64() - 1, header.Time, baseFee, blobBaseFee, nil
}
Expand Down
4 changes: 3 additions & 1 deletion rollup/internal/controller/sender/sender_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import (
gethTypes "github.com/scroll-tech/go-ethereum/core/types"
"github.com/scroll-tech/go-ethereum/crypto"
"github.com/scroll-tech/go-ethereum/crypto/kzg4844"
"github.com/scroll-tech/go-ethereum/ethclient"
"github.com/scroll-tech/go-ethereum/log"
"github.com/scroll-tech/go-ethereum/rpc"
"github.com/stretchr/testify/assert"
Expand Down Expand Up @@ -94,8 +95,9 @@ func setupEnv(t *testing.T) {
assert.NoError(t, err)
assert.NoError(t, migrate.ResetDB(sqlDB))

l1Client, err := testApps.GetPoSL1Client()
l1RawClient, err := testApps.GetPoSL1Client()
assert.NoError(t, err)
l1Client := ethclient.NewClient(l1RawClient)

chainID, err := l1Client.ChainID(context.Background())
assert.NoError(t, err)
Expand Down
24 changes: 19 additions & 5 deletions rollup/internal/controller/watcher/l1_watcher.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,15 @@ package watcher
import (
"context"
"errors"
"fmt"
"math/big"

"github.com/prometheus/client_golang/prometheus"
"github.com/scroll-tech/go-ethereum/consensus/misc"
"github.com/scroll-tech/go-ethereum/common/hexutil"
gethTypes "github.com/scroll-tech/go-ethereum/core/types"
"github.com/scroll-tech/go-ethereum/ethclient"
"github.com/scroll-tech/go-ethereum/log"
"github.com/scroll-tech/go-ethereum/rpc"
"gorm.io/gorm"

"scroll-tech/common/types"
Expand All @@ -20,7 +22,8 @@ import (
// L1WatcherClient will listen for smart contract events from Eth L1.
type L1WatcherClient struct {
ctx context.Context
client *ethclient.Client
rpcClient *rpc.Client // Raw RPC client
client *ethclient.Client // Go SDK RPC client
l1BlockOrm *orm.L1Block

// The height of the block that the watcher has retrieved header rlp
Expand All @@ -30,7 +33,7 @@ type L1WatcherClient struct {
}

// NewL1WatcherClient returns a new instance of L1WatcherClient.
func NewL1WatcherClient(ctx context.Context, client *ethclient.Client, startHeight uint64, db *gorm.DB, reg prometheus.Registerer) *L1WatcherClient {
func NewL1WatcherClient(ctx context.Context, rpcClient *rpc.Client, startHeight uint64, db *gorm.DB, reg prometheus.Registerer) *L1WatcherClient {
l1BlockOrm := orm.NewL1Block(db)
savedL1BlockHeight, err := l1BlockOrm.GetLatestL1BlockHeight(ctx)
if err != nil {
Expand All @@ -43,7 +46,8 @@ func NewL1WatcherClient(ctx context.Context, client *ethclient.Client, startHeig

return &L1WatcherClient{
ctx: ctx,
client: client,
rpcClient: rpcClient,
client: ethclient.NewClient(rpcClient),
l1BlockOrm: l1BlockOrm,

processedBlockHeight: savedL1BlockHeight,
Expand Down Expand Up @@ -80,7 +84,17 @@ func (w *L1WatcherClient) FetchBlockHeader(blockHeight uint64) error {

var blobBaseFee uint64
if excess := block.ExcessBlobGas; excess != nil {
blobBaseFee = misc.CalcBlobFee(*excess).Uint64()
// Leave it up to the L1 node to compute the correct blob base fee.
// Previously we would compute it locally using `CalcBlobFee`, but
// that approach requires syncing any future L1 configuration changes.
// Note: The fetched blob base fee might not correspond to the block
// that we fetched in the previous step, but this is acceptable.
var blobBaseFeeHex hexutil.Big
if err := w.rpcClient.CallContext(w.ctx, &blobBaseFeeHex, "eth_blobBaseFee"); err != nil {
return fmt.Errorf("failed to call eth_blobBaseFee, err: %w", err)
}
// A correct L1 node could not return a value that overflows uint64
blobBaseFee = blobBaseFeeHex.ToInt().Uint64()
}

l1Block := orm.L1Block{
Expand Down
4 changes: 2 additions & 2 deletions rollup/internal/controller/watcher/l1_watcher_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,10 @@ import (

func setupL1Watcher(t *testing.T) (*L1WatcherClient, *gorm.DB) {
db := setupDB(t)
client, err := testApps.GetPoSL1Client()
l1RawClient, err := testApps.GetPoSL1Client()
assert.NoError(t, err)
l1Cfg := cfg.L1Config
watcher := NewL1WatcherClient(context.Background(), client, l1Cfg.StartHeight, db, nil)
watcher := NewL1WatcherClient(context.Background(), l1RawClient, l1Cfg.StartHeight, db, nil)
return watcher, db
}

Expand Down
Loading
Loading